]> err.no Git - linux-2.6/commitdiff
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Wed, 26 Jul 2006 14:22:10 +0000 (07:22 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 26 Jul 2006 14:22:10 +0000 (07:22 -0700)
* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [IPV4/IPV6]: Setting 0 for unused port field in RAW IP recvmsg().
  [IPV4] ipmr: ip multicast route bug fix.
  [TG3]: Update version and reldate
  [TG3]: Handle tg3_init_rings() failures
  [TG3]: Add tg3_restart_hw()
  [IPV4]: Clear the whole IPCB, this clears also IPCB(skb)->flags.
  [IPV6]: Clean skb cb on IPv6 input.
  [NETFILTER]: Demote xt_sctp to EXPERIMENTAL
  [NETFILTER]: bridge netfilter: add deferred output hooks to feature-removal-schedule
  [NETFILTER]: xt_pkttype: fix mismatches on locally generated packets
  [NETFILTER]: SNMP NAT: fix byteorder confusion
  [NETFILTER]: conntrack: fix SYSCTL=n compile
  [NETFILTER]: nf_queue: handle NF_STOP and unknown verdicts in nf_reinject
  [NETFILTER]: H.323 helper: fix possible NULL-ptr dereference

17 files changed:
Documentation/feature-removal-schedule.txt
drivers/net/tg3.c
include/linux/netfilter_bridge.h
net/bridge/br_netfilter.c
net/ipv4/ip_input.c
net/ipv4/ipmr.c
net/ipv4/netfilter/ip_conntrack_helper_h323.c
net/ipv4/netfilter/ip_conntrack_standalone.c
net/ipv4/netfilter/ip_nat_snmp_basic.c
net/ipv4/raw.c
net/ipv6/ip6_input.c
net/ipv6/raw.c
net/netfilter/Kconfig
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_queue.c
net/netfilter/xt_physdev.c
net/netfilter/xt_pkttype.c

index 9d3a0775a11df394f3504dbd13ee60af75db4c3b..87851efb02285658f55031c390258c10c490d170 100644 (file)
@@ -258,3 +258,19 @@ Why:       These drivers never compiled since they were added to the kernel
 Who:   Jean Delvare <khali@linux-fr.org>
 
 ---------------------------
+
+What:  Bridge netfilter deferred IPv4/IPv6 output hook calling
+When:  January 2007
+Why:   The deferred output hooks are a layering violation causing unusual
+       and broken behaviour on bridge devices. Examples of things they
+       break include QoS classifation using the MARK or CLASSIFY targets,
+       the IPsec policy match and connection tracking with VLANs on a
+       bridge. Their only use is to enable bridge output port filtering
+       within iptables with the physdev match, which can also be done by
+       combining iptables and ebtables using netfilter marks. Until it
+       will get removed the hook deferral is disabled by default and is
+       only enabled when needed.
+
+Who:   Patrick McHardy <kaber@trash.net>
+
+---------------------------
index ce6f3be86da00b77e363d426eb7562c962c35121..1b8138f641e3e6023250500fa46f7e5ccb55afdd 100644 (file)
@@ -68,8 +68,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.62"
-#define DRV_MODULE_RELDATE     "June 30, 2006"
+#define DRV_MODULE_VERSION     "3.63"
+#define DRV_MODULE_RELDATE     "July 25, 2006"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -3590,6 +3590,28 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id,
 static int tg3_init_hw(struct tg3 *, int);
 static int tg3_halt(struct tg3 *, int, int);
 
+/* Restart hardware after configuration changes, self-test, etc.
+ * Invoked with tp->lock held.
+ */
+static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
+{
+       int err;
+
+       err = tg3_init_hw(tp, reset_phy);
+       if (err) {
+               printk(KERN_ERR PFX "%s: Failed to re-initialize device, "
+                      "aborting.\n", tp->dev->name);
+               tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+               tg3_full_unlock(tp);
+               del_timer_sync(&tp->timer);
+               tp->irq_sync = 0;
+               netif_poll_enable(tp->dev);
+               dev_close(tp->dev);
+               tg3_full_lock(tp, 0);
+       }
+       return err;
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void tg3_poll_controller(struct net_device *dev)
 {
@@ -3630,13 +3652,15 @@ static void tg3_reset_task(void *_data)
        }
 
        tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
-       tg3_init_hw(tp, 1);
+       if (tg3_init_hw(tp, 1))
+               goto out;
 
        tg3_netif_start(tp);
 
        if (restart_timer)
                mod_timer(&tp->timer, jiffies + 1);
 
+out:
        tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
 
        tg3_full_unlock(tp);
@@ -4124,6 +4148,7 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
 static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct tg3 *tp = netdev_priv(dev);
+       int err;
 
        if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
                return -EINVAL;
@@ -4144,13 +4169,14 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
 
        tg3_set_mtu(dev, tp, new_mtu);
 
-       tg3_init_hw(tp, 0);
+       err = tg3_restart_hw(tp, 0);
 
-       tg3_netif_start(tp);
+       if (!err)
+               tg3_netif_start(tp);
 
        tg3_full_unlock(tp);
 
-       return 0;
+       return err;
 }
 
 /* Free up pending packets in all rx/tx rings.
@@ -4232,7 +4258,7 @@ static void tg3_free_rings(struct tg3 *tp)
  * end up in the driver.  tp->{tx,}lock are held and thus
  * we may not sleep.
  */
-static void tg3_init_rings(struct tg3 *tp)
+static int tg3_init_rings(struct tg3 *tp)
 {
        u32 i;
 
@@ -4281,18 +4307,38 @@ static void tg3_init_rings(struct tg3 *tp)
 
        /* Now allocate fresh SKBs for each rx ring. */
        for (i = 0; i < tp->rx_pending; i++) {
-               if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD,
-                                    -1, i) < 0)
+               if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD, -1, i) < 0) {
+                       printk(KERN_WARNING PFX
+                              "%s: Using a smaller RX standard ring, "
+                              "only %d out of %d buffers were allocated "
+                              "successfully.\n",
+                              tp->dev->name, i, tp->rx_pending);
+                       if (i == 0)
+                               return -ENOMEM;
+                       tp->rx_pending = i;
                        break;
+               }
        }
 
        if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) {
                for (i = 0; i < tp->rx_jumbo_pending; i++) {
                        if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO,
-                                            -1, i) < 0)
+                                            -1, i) < 0) {
+                               printk(KERN_WARNING PFX
+                                      "%s: Using a smaller RX jumbo ring, "
+                                      "only %d out of %d buffers were "
+                                      "allocated successfully.\n",
+                                      tp->dev->name, i, tp->rx_jumbo_pending);
+                               if (i == 0) {
+                                       tg3_free_rings(tp);
+                                       return -ENOMEM;
+                               }
+                               tp->rx_jumbo_pending = i;
                                break;
+                       }
                }
        }
+       return 0;
 }
 
 /*
@@ -5815,6 +5861,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
 {
        struct tg3 *tp = netdev_priv(dev);
        struct sockaddr *addr = p;
+       int err = 0;
 
        if (!is_valid_ether_addr(addr->sa_data))
                return -EINVAL;
@@ -5832,9 +5879,9 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
                tg3_full_lock(tp, 1);
 
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-               tg3_init_hw(tp, 0);
-
-               tg3_netif_start(tp);
+               err = tg3_restart_hw(tp, 0);
+               if (!err)
+                       tg3_netif_start(tp);
                tg3_full_unlock(tp);
        } else {
                spin_lock_bh(&tp->lock);
@@ -5842,7 +5889,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
                spin_unlock_bh(&tp->lock);
        }
 
-       return 0;
+       return err;
 }
 
 /* tp->lock is held. */
@@ -5942,7 +5989,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
         * can only do this after the hardware has been
         * successfully reset.
         */
-       tg3_init_rings(tp);
+       err = tg3_init_rings(tp);
+       if (err)
+               return err;
 
        /* This value is determined during the probe time DMA
         * engine test, tg3_test_dma.
@@ -7956,7 +8005,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
 static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
 {
        struct tg3 *tp = netdev_priv(dev);
-       int irq_sync = 0;
+       int irq_sync = 0, err = 0;
   
        if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
            (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
@@ -7980,13 +8029,14 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
 
        if (netif_running(dev)) {
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-               tg3_init_hw(tp, 1);
-               tg3_netif_start(tp);
+               err = tg3_restart_hw(tp, 1);
+               if (!err)
+                       tg3_netif_start(tp);
        }
 
        tg3_full_unlock(tp);
   
-       return 0;
+       return err;
 }
   
 static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
@@ -8001,7 +8051,7 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
 static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
 {
        struct tg3 *tp = netdev_priv(dev);
-       int irq_sync = 0;
+       int irq_sync = 0, err = 0;
   
        if (netif_running(dev)) {
                tg3_netif_stop(tp);
@@ -8025,13 +8075,14 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
 
        if (netif_running(dev)) {
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-               tg3_init_hw(tp, 1);
-               tg3_netif_start(tp);
+               err = tg3_restart_hw(tp, 1);
+               if (!err)
+                       tg3_netif_start(tp);
        }
 
        tg3_full_unlock(tp);
   
-       return 0;
+       return err;
 }
   
 static u32 tg3_get_rx_csum(struct net_device *dev)
@@ -8666,7 +8717,9 @@ static int tg3_test_loopback(struct tg3 *tp)
        if (!netif_running(tp->dev))
                return TG3_LOOPBACK_FAILED;
 
-       tg3_reset_hw(tp, 1);
+       err = tg3_reset_hw(tp, 1);
+       if (err)
+               return TG3_LOOPBACK_FAILED;
 
        if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
                err |= TG3_MAC_LOOPBACK_FAILED;
@@ -8740,8 +8793,8 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
                tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
                if (netif_running(dev)) {
                        tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
-                       tg3_init_hw(tp, 1);
-                       tg3_netif_start(tp);
+                       if (!tg3_restart_hw(tp, 1))
+                               tg3_netif_start(tp);
                }
 
                tg3_full_unlock(tp);
@@ -11699,7 +11752,8 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
                tg3_full_lock(tp, 0);
 
                tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
-               tg3_init_hw(tp, 1);
+               if (tg3_restart_hw(tp, 1))
+                       goto out;
 
                tp->timer.expires = jiffies + tp->timer_offset;
                add_timer(&tp->timer);
@@ -11707,6 +11761,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
                netif_device_attach(dev);
                tg3_netif_start(tp);
 
+out:
                tg3_full_unlock(tp);
        }
 
@@ -11733,16 +11788,19 @@ static int tg3_resume(struct pci_dev *pdev)
        tg3_full_lock(tp, 0);
 
        tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
-       tg3_init_hw(tp, 1);
+       err = tg3_restart_hw(tp, 1);
+       if (err)
+               goto out;
 
        tp->timer.expires = jiffies + tp->timer_offset;
        add_timer(&tp->timer);
 
        tg3_netif_start(tp);
 
+out:
        tg3_full_unlock(tp);
 
-       return 0;
+       return err;
 }
 
 static struct pci_driver tg3_driver = {
index 87764022cc670050ec0573d2a454f16fabfa61c3..31f02ba036cef56c62d08cb59aee9bbea440379b 100644 (file)
@@ -79,6 +79,8 @@ struct bridge_skb_cb {
                __u32 ipv4;
        } daddr;
 };
+
+extern int brnf_deferred_hooks;
 #endif /* CONFIG_BRIDGE_NETFILTER */
 
 #endif /* __KERNEL__ */
index cbc8a389a0a8ceb4063661eb42239c0cfd4a0b52..05b3de88824362fd797c1fe3309567520cc163df 100644 (file)
@@ -61,6 +61,9 @@ static int brnf_filter_vlan_tagged = 1;
 #define brnf_filter_vlan_tagged 1
 #endif
 
+int brnf_deferred_hooks;
+EXPORT_SYMBOL_GPL(brnf_deferred_hooks);
+
 static __be16 inline vlan_proto(const struct sk_buff *skb)
 {
        return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
@@ -890,6 +893,8 @@ static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb,
                                return NF_ACCEPT;
                        else if (ip->version == 6 && !brnf_call_ip6tables)
                                return NF_ACCEPT;
+                       else if (!brnf_deferred_hooks)
+                               return NF_ACCEPT;
 #endif
                        if (hook == NF_IP_POST_ROUTING)
                                return NF_ACCEPT;
index 184c78ca79e65e895800153e351ca4fbaa7e7e60..212734ca238fa88e2bcee0eb43e13c246a5f9720 100644 (file)
@@ -429,7 +429,7 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
        }
 
        /* Remove any debris in the socket control block */
-       memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+       memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
 
        return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
                       ip_rcv_finish);
index 9ccacf57f08bd8ff7a0e6315ae6766f6744fb59c..85893eef6b16c5488ab01d0be5c168874b338293 100644 (file)
@@ -1578,6 +1578,7 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait)
        cache = ipmr_cache_find(rt->rt_src, rt->rt_dst);
 
        if (cache==NULL) {
+               struct sk_buff *skb2;
                struct net_device *dev;
                int vif;
 
@@ -1591,12 +1592,18 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait)
                        read_unlock(&mrt_lock);
                        return -ENODEV;
                }
-               skb->nh.raw = skb_push(skb, sizeof(struct iphdr));
-               skb->nh.iph->ihl = sizeof(struct iphdr)>>2;
-               skb->nh.iph->saddr = rt->rt_src;
-               skb->nh.iph->daddr = rt->rt_dst;
-               skb->nh.iph->version = 0;
-               err = ipmr_cache_unresolved(vif, skb);
+               skb2 = skb_clone(skb, GFP_ATOMIC);
+               if (!skb2) {
+                       read_unlock(&mrt_lock);
+                       return -ENOMEM;
+               }
+
+               skb2->nh.raw = skb_push(skb2, sizeof(struct iphdr));
+               skb2->nh.iph->ihl = sizeof(struct iphdr)>>2;
+               skb2->nh.iph->saddr = rt->rt_src;
+               skb2->nh.iph->daddr = rt->rt_dst;
+               skb2->nh.iph->version = 0;
+               err = ipmr_cache_unresolved(vif, skb2);
                read_unlock(&mrt_lock);
                return err;
        }
index af35235672d58f9ce0ec320073b838930b0352a7..9a39e2969712701d0ab45b9bb0dcd1d3c6ccf0e6 100644 (file)
@@ -1200,7 +1200,7 @@ static struct ip_conntrack_expect *find_expect(struct ip_conntrack *ct,
        tuple.dst.protonum = IPPROTO_TCP;
 
        exp = __ip_conntrack_expect_find(&tuple);
-       if (exp->master == ct)
+       if (exp && exp->master == ct)
                return exp;
        return NULL;
 }
index 7bd3c22003a20a84b9e92479db92a0c1b871edcf..7a9fa04a467a2b807c7fed4d16245fa7201dab04 100644 (file)
@@ -534,6 +534,8 @@ static struct nf_hook_ops ip_conntrack_ops[] = {
 
 /* Sysctl support */
 
+int ip_conntrack_checksum = 1;
+
 #ifdef CONFIG_SYSCTL
 
 /* From ip_conntrack_core.c */
@@ -568,8 +570,6 @@ extern unsigned int ip_ct_generic_timeout;
 static int log_invalid_proto_min = 0;
 static int log_invalid_proto_max = 255;
 
-int ip_conntrack_checksum = 1;
-
 static struct ctl_table_header *ip_ct_sysctl_header;
 
 static ctl_table ip_ct_sysctl_table[] = {
index 0b1b416759ccc948a54c9e78aabcda86b68fe89d..18b7fbdccb6126684f67478fa6a7ba1580445b23 100644 (file)
@@ -1255,9 +1255,9 @@ static int help(struct sk_buff **pskb,
        struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
 
        /* SNMP replies and originating SNMP traps get mangled */
-       if (udph->source == ntohs(SNMP_PORT) && dir != IP_CT_DIR_REPLY)
+       if (udph->source == htons(SNMP_PORT) && dir != IP_CT_DIR_REPLY)
                return NF_ACCEPT;
-       if (udph->dest == ntohs(SNMP_TRAP_PORT) && dir != IP_CT_DIR_ORIGINAL)
+       if (udph->dest == htons(SNMP_TRAP_PORT) && dir != IP_CT_DIR_ORIGINAL)
                return NF_ACCEPT;
 
        /* No NAT? */
index bd221ec3f81eb668390d9e811712c8bc3da6fdfd..62b2762a2420bb1331d88d0d076737c1cc358ac3 100644 (file)
@@ -609,6 +609,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        if (sin) {
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = skb->nh.iph->saddr;
+               sin->sin_port = 0;
                memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
        }
        if (inet->cmsg_flags)
index df8f051c0fce2eb910429a9313ec0db8e3ba9462..25c2a9e0389549f05578c2ad3155ab105ef8ecfa 100644 (file)
@@ -71,6 +71,8 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
                goto out;
        }
 
+       memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
+
        /*
         * Store incoming device index. When the packet will
         * be queued, we cannot refer to skb->dev anymore.
index fa1ce0ae123ed0d855d9db3cfb44c380cb668058..d57e61ce4a7db05f776d58f546d8d3c2d0a865ef 100644 (file)
@@ -411,6 +411,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
        /* Copy the address. */
        if (sin6) {
                sin6->sin6_family = AF_INET6;
+               sin6->sin6_port = 0;
                ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
                sin6->sin6_flowinfo = 0;
                sin6->sin6_scope_id = 0;
index 42a178aa30f9fde82b434b48ece146e8b1e27b98..a9894ddfd72af22044e12de52ea397ac3c50e3de 100644 (file)
@@ -386,8 +386,8 @@ config NETFILTER_XT_MATCH_REALM
          <file:Documentation/modules.txt>.  If unsure, say `N'.
 
 config NETFILTER_XT_MATCH_SCTP
-       tristate  '"sctp" protocol match support'
-       depends on NETFILTER_XTABLES
+       tristate  '"sctp" protocol match support (EXPERIMENTAL)'
+       depends on NETFILTER_XTABLES && EXPERIMENTAL
        help
          With this option enabled, you will be able to use the 
          `sctp' match in order to match on SCTP source/destination ports
index 5fcab2ef231f56d62d5f39deb8ec7b1bc0117e05..4ef8366999623b6723a9e104e56c1ba673989b8c 100644 (file)
@@ -428,6 +428,8 @@ static struct file_operations ct_cpu_seq_fops = {
 
 /* Sysctl support */
 
+int nf_conntrack_checksum = 1;
+
 #ifdef CONFIG_SYSCTL
 
 /* From nf_conntrack_core.c */
@@ -459,8 +461,6 @@ extern unsigned int nf_ct_generic_timeout;
 static int log_invalid_proto_min = 0;
 static int log_invalid_proto_max = 255;
 
-int nf_conntrack_checksum = 1;
-
 static struct ctl_table_header *nf_ct_sysctl_header;
 
 static ctl_table nf_ct_sysctl_table[] = {
index bb6fcee452ca37f8a683d89a4c63775ea250b004..662a869593bff6ea852180428b8ac0dbf8af1692 100644 (file)
@@ -219,21 +219,20 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
 
        switch (verdict & NF_VERDICT_MASK) {
        case NF_ACCEPT:
+       case NF_STOP:
                info->okfn(skb);
+       case NF_STOLEN:
                break;
-
        case NF_QUEUE:
                if (!nf_queue(&skb, elem, info->pf, info->hook, 
                              info->indev, info->outdev, info->okfn,
                              verdict >> NF_VERDICT_BITS))
                        goto next_hook;
                break;
+       default:
+               kfree_skb(skb);
        }
        rcu_read_unlock();
-
-       if (verdict == NF_DROP)
-               kfree_skb(skb);
-
        kfree(info);
        return;
 }
index 5fe4c9df17f5e7e015b524e3caa03a0acb3a1781..a9f4f6f3c628225e9720d0cefad672a598fa00c9 100644 (file)
@@ -113,6 +113,21 @@ checkentry(const char *tablename,
        if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
            info->bitmask & ~XT_PHYSDEV_OP_MASK)
                return 0;
+       if (brnf_deferred_hooks == 0 &&
+           info->bitmask & XT_PHYSDEV_OP_OUT &&
+           (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||
+            info->invert & XT_PHYSDEV_OP_BRIDGED) &&
+           hook_mask & ((1 << NF_IP_LOCAL_OUT) | (1 << NF_IP_FORWARD) |
+                        (1 << NF_IP_POST_ROUTING))) {
+               printk(KERN_WARNING "physdev match: using --physdev-out in the "
+                      "OUTPUT, FORWARD and POSTROUTING chains for non-bridged "
+                      "traffic is deprecated and breaks other things, it will "
+                      "be removed in January 2007. See Documentation/"
+                      "feature-removal-schedule.txt for details. This doesn't "
+                      "affect you in case you're using it for purely bridged "
+                      "traffic.\n");
+               brnf_deferred_hooks = 1;
+       }
        return 1;
 }
 
index 3ac703b5cb8ffb9413d8c5a7f12f616d576189e3..d2f5320a80bf6a91f97ff2790ec2f3d5540c87e2 100644 (file)
@@ -9,6 +9,8 @@
 #include <linux/skbuff.h>
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
+#include <linux/in.h>
+#include <linux/ip.h>
 
 #include <linux/netfilter/xt_pkttype.h>
 #include <linux/netfilter/x_tables.h>
@@ -28,9 +30,17 @@ static int match(const struct sk_buff *skb,
       unsigned int protoff,
       int *hotdrop)
 {
+       u_int8_t type;
        const struct xt_pkttype_info *info = matchinfo;
 
-       return (skb->pkt_type == info->pkttype) ^ info->invert;
+       if (skb->pkt_type == PACKET_LOOPBACK)
+               type = (MULTICAST(skb->nh.iph->daddr)
+                       ? PACKET_MULTICAST
+                       : PACKET_BROADCAST);
+       else
+               type = skb->pkt_type;
+
+       return (type == info->pkttype) ^ info->invert;
 }
 
 static struct xt_match pkttype_match = {