diff options
| author | Linus Torvalds <torvalds@home.osdl.org> | 2003-07-25 02:58:59 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.osdl.org> | 2003-07-25 02:58:59 -0700 |
| commit | 3c6bf5ce5f0554a7e8a8d82036b3dccabd370400 (patch) | |
| tree | 0dc6057d1dcb9a43d3b5080bb1377ae439f21ec2 | |
| parent | 5ade138f373b988a4eef0698b327a868a7c03b6e (diff) | |
| parent | 54cdf53bc01532ce8e08f4684526b83adac7ed8a (diff) | |
Merge bk://kernel.bkbits.net/davem/net-2.5
into home.osdl.org:/home/torvalds/v2.5/linux
44 files changed, 595 insertions, 374 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 790ddb4c535e..1b3d07ec3645 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1632,8 +1632,8 @@ L: linux-scsi@vger.kernel.org S: Maintained SCTP PROTOCOL -P: Jon Grimm -M: jgrimm2@us.ibm.com +P: Sridhar Samudrala +M: sri@us.ibm.com L: lksctp-developers@lists.sourceforge.net S: Supported diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d2a0f9082a63..beed7b3adebe 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -154,6 +154,8 @@ static struct pci_device_id tg3_pci_tbl[] __devinitdata = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { 0, } diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index 277f087da8cc..174ebf05fe11 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -5832,6 +5832,7 @@ 1737 Linksys 173b Altima (nee Broadcom) 03e8 AC1000 Gigabit Ethernet + 03e9 AC1001 Gigabit Ethernet 03ea AC9100 Gigabit Ethernet 1743 Peppercon AG 8139 ROL/F-100 Fast Ethernet Adapter with ROL diff --git a/include/linux/ipv6_route.h b/include/linux/ipv6_route.h index eacfa6c80f0e..46d8b7e8b1aa 100644 --- a/include/linux/ipv6_route.h +++ b/include/linux/ipv6_route.h @@ -16,6 +16,7 @@ #define RTF_DEFAULT 0x00010000 /* default - learned via ND */ #define RTF_ALLONLINK 0x00020000 /* fallback, no routers on link */ #define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */ +#define RTF_PREFIX_RT 0x00080000 /* A prefix only route - RA */ #define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */ #define RTF_EXPIRES 0x00400000 diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index 1056e450ef14..b9fcbf85f047 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -33,6 +33,23 @@ struct ebt_counter uint64_t bcnt; }; +struct ebt_replace +{ + char name[EBT_TABLE_MAXNAMELEN]; + unsigned int valid_hooks; + /* nr of rules in the table */ + unsigned int nentries; + /* total size of the entries */ + unsigned int entries_size; + /* start of the chains */ + struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; + /* nr of counters userspace expects back */ + unsigned int num_counters; + /* where the kernel will put the old counters */ + struct ebt_counter *counters; + char *entries; +}; + struct ebt_entries { /* this field is always set to zero * See EBT_ENTRY_OR_ENTRIES. @@ -47,7 +64,7 @@ struct ebt_entries { /* nr. of entries */ unsigned int nentries; /* entry list */ - char data[0]; + char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); }; /* used for the bitmask of struct ebt_entry */ @@ -87,7 +104,7 @@ struct ebt_entry_match } u; /* size of data */ unsigned int match_size; - unsigned char data[0]; + unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); }; struct ebt_entry_watcher @@ -98,7 +115,7 @@ struct ebt_entry_watcher } u; /* size of data */ unsigned int watcher_size; - unsigned char data[0]; + unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); }; struct ebt_entry_target @@ -109,7 +126,7 @@ struct ebt_entry_target } u; /* size of data */ unsigned int target_size; - unsigned char data[0]; + unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); }; #define EBT_STANDARD_TARGET "standard" @@ -143,24 +160,7 @@ struct ebt_entry { unsigned int target_offset; /* sizeof ebt_entry + matches + watchers + target */ unsigned int next_offset; - unsigned char elems[0]; -}; - -struct ebt_replace -{ - char name[EBT_TABLE_MAXNAMELEN]; - unsigned int valid_hooks; - /* nr of rules in the table */ - unsigned int nentries; - /* total size of the entries */ - unsigned int entries_size; - /* start of the chains */ - struct ebt_entries *hook_entry[NF_BR_NUMHOOKS]; - /* nr of counters userspace expects back */ - unsigned int num_counters; - /* where the kernel will put the old counters */ - struct ebt_counter *counters; - char *entries; + unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace)))); }; /* {g,s}etsockopt numbers */ @@ -263,6 +263,8 @@ struct ebt_table struct module *me; }; +#define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \ + ~(__alignof__(struct ebt_replace)-1)) extern int ebt_register_table(struct ebt_table *table); extern void ebt_unregister_table(struct ebt_table *table); extern int ebt_register_match(struct ebt_match *match); diff --git a/include/linux/netfilter_ipv4/ipt_REJECT.h b/include/linux/netfilter_ipv4/ipt_REJECT.h index ad195e435ba9..4293a1ad1b01 100644 --- a/include/linux/netfilter_ipv4/ipt_REJECT.h +++ b/include/linux/netfilter_ipv4/ipt_REJECT.h @@ -9,7 +9,8 @@ enum ipt_reject_with { IPT_ICMP_ECHOREPLY, IPT_ICMP_NET_PROHIBITED, IPT_ICMP_HOST_PROHIBITED, - IPT_TCP_RESET + IPT_TCP_RESET, + IPT_ICMP_ADMIN_PROHIBITED }; struct ipt_reject_info { diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index f5184b7f9fdc..7b54e6b44e81 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1757,6 +1757,7 @@ #define PCI_VENDOR_ID_ALTIMA 0x173b #define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8 +#define PCI_DEVICE_ID_ALTIMA_AC1001 0x03e9 #define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea #define PCI_VENDOR_ID_SYMPHONY 0x1c1c diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 788132027e48..3e3a26916a12 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -168,6 +168,7 @@ enum rt_scope_t #define RTM_F_NOTIFY 0x100 /* Notify user of route change */ #define RTM_F_CLONED 0x200 /* This route is cloned */ #define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */ +#define RTM_F_PREFIX 0x800 /* Prefix addresses */ /* Reserved table identifiers */ @@ -458,6 +459,40 @@ struct ifinfomsg unsigned ifi_change; /* IFF_* change mask */ }; +/* The struct should be in sync with struct net_device_stats */ +struct rtnl_link_stats +{ + __u32 rx_packets; /* total packets received */ + __u32 tx_packets; /* total packets transmitted */ + __u32 rx_bytes; /* total bytes received */ + __u32 tx_bytes; /* total bytes transmitted */ + __u32 rx_errors; /* bad packets received */ + __u32 tx_errors; /* packet transmit problems */ + __u32 rx_dropped; /* no space in linux buffers */ + __u32 tx_dropped; /* no space available in linux */ + __u32 multicast; /* multicast packets received */ + __u32 collisions; + + /* detailed rx_errors: */ + __u32 rx_length_errors; + __u32 rx_over_errors; /* receiver ring buff overflow */ + __u32 rx_crc_errors; /* recved pkt with crc error */ + __u32 rx_frame_errors; /* recv'd frame alignment error */ + __u32 rx_fifo_errors; /* recv'r fifo overrun */ + __u32 rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + __u32 tx_aborted_errors; + __u32 tx_carrier_errors; + __u32 tx_fifo_errors; + __u32 tx_heartbeat_errors; + __u32 tx_window_errors; + + /* for cslip etc */ + __u32 rx_compressed; + __u32 tx_compressed; +}; + enum { IFLA_UNSPEC, @@ -599,6 +634,22 @@ extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const voi ({ if (skb_tailroom(skb) < (int)RTA_SPACE(attrlen)) goto rtattr_failure; \ __rta_fill(skb, attrtype, attrlen, data); }) +static inline struct rtattr * +__rta_reserve(struct sk_buff *skb, int attrtype, int attrlen) +{ + struct rtattr *rta; + int size = RTA_LENGTH(attrlen); + + rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size)); + rta->rta_type = attrtype; + rta->rta_len = size; + return rta; +} + +#define __RTA_PUT(skb, attrtype, attrlen) \ +({ if (skb_tailroom(skb) < (int)RTA_SPACE(attrlen)) goto rtattr_failure; \ + __rta_reserve(skb, attrtype, attrlen); }) + extern void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change); extern struct semaphore rtnl_sem; diff --git a/net/atm/lec.c b/net/atm/lec.c index cc075949cd30..67228a48527d 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -1031,7 +1031,7 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr, #define LEC_ARP_REFRESH_INTERVAL (3*HZ) static void lec_arp_check_expire(unsigned long data); -static __inline__ void lec_arp_expire_arp(unsigned long data); +static void lec_arp_expire_arp(unsigned long data); void dump_arp_table(struct lec_priv *priv); /* @@ -1371,7 +1371,7 @@ lec_arp_destroy(struct lec_priv *priv) struct lec_arp_table *entry, *next; int i; - del_timer(&priv->lec_arp_timer); + del_timer_sync(&priv->lec_arp_timer); /* * Remove all entries @@ -1386,7 +1386,7 @@ lec_arp_destroy(struct lec_priv *priv) entry = priv->lec_arp_empty_ones; while(entry) { next = entry->next; - del_timer(&entry->timer); + del_timer_sync(&entry->timer); lec_arp_clear_vccs(entry); kfree(entry); entry = next; @@ -1395,7 +1395,7 @@ lec_arp_destroy(struct lec_priv *priv) entry = priv->lec_no_forward; while(entry) { next = entry->next; - del_timer(&entry->timer); + del_timer_sync(&entry->timer); lec_arp_clear_vccs(entry); kfree(entry); entry = next; @@ -1404,7 +1404,7 @@ lec_arp_destroy(struct lec_priv *priv) entry = priv->mcast_fwds; while(entry) { next = entry->next; - del_timer(&entry->timer); + /* No timer, LANEv2 7.1.20 and 2.3.5.3 */ lec_arp_clear_vccs(entry); kfree(entry); entry = next; @@ -1478,8 +1478,6 @@ lec_arp_expire_arp(unsigned long data) entry = (struct lec_arp_table *)data; - del_timer(&entry->timer); - DPRINTK("lec_arp_expire_arp\n"); if (entry->status == ESI_ARP_PENDING) { if (entry->no_tries <= entry->priv->max_retry_count) { @@ -1489,8 +1487,7 @@ lec_arp_expire_arp(unsigned long data) send_to_lecd(entry->priv, l_arp_xmt, entry->mac_addr, NULL, NULL); entry->no_tries++; } - entry->timer.expires = jiffies + (1*HZ); - add_timer(&entry->timer); + mod_timer(&entry->timer, jiffies + (1*HZ)); } } @@ -1562,8 +1559,6 @@ lec_arp_check_expire(unsigned long data) unsigned long time_to_check; int i; - del_timer(&priv->lec_arp_timer); - DPRINTK("lec_arp_check_expire %p,%d\n",priv, atomic_read(&priv->lec_arp_users)); DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones, @@ -1621,8 +1616,8 @@ lec_arp_check_expire(unsigned long data) } lec_arp_put(priv); } - priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL; - add_timer(&priv->lec_arp_timer); + + mod_timer(&priv->lec_arp_timer, jiffies + LEC_ARP_REFRESH_INTERVAL); } /* * Try to find vcc where mac_address is attached. diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index b4e92cb875c6..36d02b08989d 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -110,23 +110,38 @@ static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst) return -1; } +/* convert later to direct kfree */ +static void br_dev_free(struct net_device *dev) +{ + struct net_bridge *br = dev->priv; + + WARN_ON(!list_empty(&br->port_list)); + WARN_ON(!list_empty(&br->age_list)); + + BUG_ON(timer_pending(&br->hello_timer)); + BUG_ON(timer_pending(&br->tcn_timer)); + BUG_ON(timer_pending(&br->topology_change_timer)); + BUG_ON(timer_pending(&br->gc_timer)); + + kfree(dev); +} void br_dev_setup(struct net_device *dev) { memset(dev->dev_addr, 0, ETH_ALEN); + ether_setup(dev); + dev->do_ioctl = br_dev_do_ioctl; dev->get_stats = br_dev_get_stats; dev->hard_start_xmit = br_dev_xmit; dev->open = br_dev_open; dev->set_multicast_list = br_dev_set_multicast_list; - dev->destructor = (void (*)(struct net_device *))kfree; + dev->destructor = br_dev_free; SET_MODULE_OWNER(dev); dev->stop = br_dev_stop; dev->accept_fastpath = br_dev_accept_fastpath; dev->tx_queue_len = 0; dev->set_mac_address = NULL; dev->priv_flags = IFF_EBRIDGE; - - ether_setup(dev); } diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index cbfa8653f210..220b97a09921 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -41,6 +41,13 @@ static int br_initial_port_cost(struct net_device *dev) static void destroy_nbp(void *arg) { struct net_bridge_port *p = arg; + + p->dev->br_port = NULL; + + BUG_ON(timer_pending(&p->message_age_timer)); + BUG_ON(timer_pending(&p->forward_delay_timer)); + BUG_ON(timer_pending(&p->hold_timer)); + dev_put(p->dev); kfree(p); } @@ -53,16 +60,19 @@ static void del_nbp(struct net_bridge_port *p) br_stp_disable_port(p); dev_set_promiscuity(dev, -1); - dev->br_port = NULL; list_del_rcu(&p->list); br_fdb_delete_by_port(p->br, p); + del_timer(&p->message_age_timer); + del_timer(&p->forward_delay_timer); + del_timer(&p->hold_timer); + call_rcu(&p->rcu, destroy_nbp, p); } -static void del_ifs(struct net_bridge *br) +static void del_br(struct net_bridge *br) { struct list_head *p, *n; @@ -71,6 +81,10 @@ static void del_ifs(struct net_bridge *br) del_nbp(list_entry(p, struct net_bridge_port, list)); } spin_unlock_bh(&br->lock); + + del_timer_sync(&br->gc_timer); + + unregister_netdevice(br->dev); } static struct net_bridge *new_nb(const char *name) @@ -182,15 +196,14 @@ int br_del_bridge(const char *name) ret = -EBUSY; } - else { - del_ifs((struct net_bridge *) dev->priv); - unregister_netdevice(dev); - } + else + del_br(dev->priv); rtnl_unlock(); return ret; } +/* called under bridge lock */ int br_add_if(struct net_bridge *br, struct net_device *dev) { struct net_bridge_port *p; @@ -205,7 +218,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) return -ELOOP; dev_hold(dev); - spin_lock_bh(&br->lock); if ((p = new_nbp(br, dev)) == NULL) { spin_unlock_bh(&br->lock); dev_put(dev); @@ -218,26 +230,21 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) br_fdb_insert(br, p, dev->dev_addr, 1); if ((br->dev->flags & IFF_UP) && (dev->flags & IFF_UP)) br_stp_enable_port(p); - spin_unlock_bh(&br->lock); return 0; } +/* called under bridge lock */ int br_del_if(struct net_bridge *br, struct net_device *dev) { struct net_bridge_port *p; - int retval = 0; - spin_lock_bh(&br->lock); if ((p = dev->br_port) == NULL || p->br != br) - retval = -EINVAL; - else { - del_nbp(p); - br_stp_recalculate_bridge_id(br); - } - spin_unlock_bh(&br->lock); + return -EINVAL; - return retval; + del_nbp(p); + br_stp_recalculate_bridge_id(br); + return 0; } int br_get_bridge_ifindices(int *indices, int num) @@ -274,13 +281,8 @@ void __exit br_cleanup_bridges(void) rtnl_lock(); for (dev = dev_base; dev; dev = nxt) { nxt = dev->next; - if (dev->priv_flags & IFF_EBRIDGE) { - pr_debug("cleanup %s\n", dev->name); - - del_ifs((struct net_bridge *) dev->priv); - - unregister_netdevice(dev); - } + if (dev->priv_flags & IFF_EBRIDGE) + del_br(dev->priv); } rtnl_unlock(); diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c index 939663847ca4..3ee2e2e8361d 100644 --- a/net/bridge/br_ioctl.c +++ b/net/bridge/br_ioctl.c @@ -59,10 +59,12 @@ static int br_ioctl_device(struct net_bridge *br, if (dev == NULL) return -EINVAL; + spin_lock_bh(&br->lock); if (cmd == BRCTL_ADD_IF) ret = br_add_if(br, dev); else ret = br_del_if(br, dev); + spin_unlock_bh(&br->lock); dev_put(dev); return ret; diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 72cc91e87523..9993944c56cf 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -38,39 +38,27 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v br = p->br; + spin_lock_bh(&br->lock); switch (event) { case NETDEV_CHANGEADDR: - spin_lock_bh(&br->lock); br_fdb_changeaddr(p, dev->dev_addr); br_stp_recalculate_bridge_id(br); - spin_unlock_bh(&br->lock); - break; - - case NETDEV_GOING_DOWN: - /* extend the protocol to send some kind of notification? */ break; case NETDEV_DOWN: - if (br->dev->flags & IFF_UP) { - spin_lock_bh(&br->lock); - br_stp_disable_port(p); - spin_unlock_bh(&br->lock); - } + br_stp_disable_port(p); break; case NETDEV_UP: - if (!(br->dev->flags & IFF_UP)) { - spin_lock_bh(&br->lock); - br_stp_enable_port(p); - spin_unlock_bh(&br->lock); - } + br_stp_enable_port(p); break; case NETDEV_UNREGISTER: br_del_if(br, dev); break; } + spin_unlock_bh(&br->lock); return NOTIFY_DONE; } diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 26e5ef0e7d92..b833444f9fa4 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -20,7 +20,11 @@ #include "br_private_stp.h" static const char *br_port_state_names[] = { - "disabled", "learning", "forwarding", "blocking", + [BR_STATE_DISABLED] = "disabled", + [BR_STATE_LISTENING] = "listening", + [BR_STATE_LEARNING] = "learning", + [BR_STATE_FORWARDING] = "forwarding", + [BR_STATE_BLOCKING] = "blocking", }; void br_log_state(const struct net_bridge_port *p) @@ -289,22 +293,20 @@ static inline void br_topology_change_acknowledged(struct net_bridge *br) /* called under bridge lock */ void br_topology_change_detection(struct net_bridge *br) { - if (!(br->dev->flags & IFF_UP)) - return; + int isroot = br_is_root_bridge(br); + + pr_info("%s: topology change detected, %s\n", br->dev->name, + isroot ? "propgating" : "sending tcn bpdu"); - pr_info("%s: topology change detected", br->dev->name); - if (br_is_root_bridge(br)) { - printk(", propagating"); + if (isroot) { br->topology_change = 1; mod_timer(&br->topology_change_timer, jiffies + br->bridge_forward_delay + br->bridge_max_age); } else if (!br->topology_change_detected) { - printk(", sending tcn bpdu"); br_transmit_tcn(br); mod_timer(&br->tcn_timer, jiffies + br->bridge_hello_time); } - printk("\n"); br->topology_change_detected = 1; } diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index f644f2164a5e..c3a906a1159c 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c @@ -43,8 +43,7 @@ void br_stp_enable_bridge(struct net_bridge *br) struct net_bridge_port *p; spin_lock_bh(&br->lock); - br->hello_timer.expires = jiffies + br->hello_time; - add_timer(&br->hello_timer); + mod_timer(&br->hello_timer, jiffies + br->hello_time); br_config_bpdu_generation(br); list_for_each_entry(p, &br->port_list, list) { @@ -74,8 +73,6 @@ void br_stp_disable_bridge(struct net_bridge *br) del_timer_sync(&br->hello_timer); del_timer_sync(&br->topology_change_timer); del_timer_sync(&br->tcn_timer); - del_timer_sync(&br->gc_timer); - } /* called under bridge lock */ diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c index a5a75cede729..eb106a4042fd 100644 --- a/net/bridge/br_stp_timer.c +++ b/net/bridge/br_stp_timer.c @@ -43,8 +43,7 @@ static void br_hello_timer_expired(unsigned long arg) if (br->dev->flags & IFF_UP) { br_config_bpdu_generation(br); - br->hello_timer.expires = jiffies + br->hello_time; - add_timer(&br->hello_timer); + mod_timer(&br->hello_timer, jiffies + br->hello_time); } spin_unlock_bh(&br->lock); } @@ -73,6 +72,8 @@ static void br_message_age_timer_expired(unsigned long arg) * check is redundant. I'm leaving it in for now, though. */ spin_lock_bh(&br->lock); + if (p->state == BR_STATE_DISABLED) + goto unlock; was_root = br_is_root_bridge(br); br_become_designated_port(p); @@ -80,6 +81,7 @@ static void br_message_age_timer_expired(unsigned long arg) br_port_state_selection(br); if (br_is_root_bridge(br) && !was_root) br_become_root_bridge(br); + unlock: spin_unlock_bh(&br->lock); } @@ -93,8 +95,8 @@ static void br_forward_delay_timer_expired(unsigned long arg) spin_lock_bh(&br->lock); if (p->state == BR_STATE_LISTENING) { p->state = BR_STATE_LEARNING; - p->forward_delay_timer.expires = jiffies + br->forward_delay; - add_timer(&p->forward_delay_timer); + mod_timer(&p->forward_delay_timer, + jiffies + br->forward_delay); } else if (p->state == BR_STATE_LEARNING) { p->state = BR_STATE_FORWARDING; if (br_is_designated_for_some_port(br)) @@ -113,8 +115,7 @@ static void br_tcn_timer_expired(unsigned long arg) if (br->dev->flags & IFF_UP) { br_transmit_tcn(br); - br->tcn_timer.expires = jiffies + br->bridge_hello_time; - add_timer(&br->tcn_timer); + mod_timer(&br->tcn_timer,jiffies + br->bridge_hello_time); } spin_unlock_bh(&br->lock); } diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c index d63d7206bbcb..eb675848fbc3 100644 --- a/net/bridge/netfilter/ebt_arp.c +++ b/net/bridge/netfilter/ebt_arp.c @@ -99,7 +99,7 @@ static int ebt_arp_check(const char *tablename, unsigned int hookmask, { struct ebt_arp_info *info = (struct ebt_arp_info *)data; - if (datalen != sizeof(struct ebt_arp_info)) + if (datalen != EBT_ALIGN(sizeof(struct ebt_arp_info))) return -EINVAL; if ((e->ethproto != __constant_htons(ETH_P_ARP) && e->ethproto != __constant_htons(ETH_P_RARP)) || diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c index c8b3357cc090..f9552dfb1655 100644 --- a/net/bridge/netfilter/ebt_dnat.c +++ b/net/bridge/netfilter/ebt_dnat.c @@ -47,7 +47,7 @@ static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask, (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) && (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) return -EINVAL; - if (datalen != sizeof(struct ebt_nat_info)) + if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info))) return -EINVAL; if (INVALID_TARGET) return -EINVAL; diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c index 7ef0662f81c6..7bab7d065bd3 100644 --- a/net/bridge/netfilter/ebt_ip.c +++ b/net/bridge/netfilter/ebt_ip.c @@ -75,7 +75,7 @@ static int ebt_ip_check(const char *tablename, unsigned int hookmask, { struct ebt_ip_info *info = (struct ebt_ip_info *)data; - if (datalen != sizeof(struct ebt_ip_info)) + if (datalen != EBT_ALIGN(sizeof(struct ebt_ip_info))) return -EINVAL; if (e->ethproto != __constant_htons(ETH_P_IP) || e->invflags & EBT_IPROTO) diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index e7a3ef4afe5a..2da7c682744d 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c @@ -22,7 +22,7 @@ static int ebt_log_check(const char *tablename, unsigned int hookmask, { struct ebt_log_info *info = (struct ebt_log_info *)data; - if (datalen != sizeof(struct ebt_log_info)) + if (datalen != EBT_ALIGN(sizeof(struct ebt_log_info))) return -EINVAL; if (info->bitmask & ~EBT_LOG_MASK) return -EINVAL; diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c index b7a87f612983..02c632b4d325 100644 --- a/net/bridge/netfilter/ebt_mark.c +++ b/net/bridge/netfilter/ebt_mark.c @@ -35,7 +35,7 @@ static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, { struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data; - if (datalen != sizeof(struct ebt_mark_t_info)) + if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info))) return -EINVAL; if (BASE_CHAIN && info->target == EBT_RETURN) return -EINVAL; diff --git a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c index c710b4e0be14..625102de1495 100644 --- a/net/bridge/netfilter/ebt_mark_m.c +++ b/net/bridge/netfilter/ebt_mark_m.c @@ -28,7 +28,7 @@ static int ebt_mark_check(const char *tablename, unsigned int hookmask, { struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data; - if (datalen != sizeof(struct ebt_mark_m_info)) + if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_m_info))) return -EINVAL; if (info->bitmask & ~EBT_MARK_MASK) return -EINVAL; diff --git a/net/bridge/netfilter/ebt_pkttype.c b/net/bridge/netfilter/ebt_pkttype.c index f6458adea80a..ecd3b42b19b0 100644 --- a/net/bridge/netfilter/ebt_pkttype.c +++ b/net/bridge/netfilter/ebt_pkttype.c @@ -28,7 +28,7 @@ static int ebt_pkttype_check(const char *tablename, unsigned int hookmask, { struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data; - if (datalen != sizeof(struct ebt_pkttype_info)) + if (datalen != EBT_ALIGN(sizeof(struct ebt_pkttype_info))) return -EINVAL; if (info->invert != 0 && info->invert != 1) return -EINVAL; diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c index d97d05fdd14f..998bab1c5ef9 100644 --- a/net/bridge/netfilter/ebt_redirect.c +++ b/net/bridge/netfilter/ebt_redirect.c @@ -47,7 +47,7 @@ static int ebt_target_redirect_check(const char *tablename, unsigned int hookmas { struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; - if (datalen != sizeof(struct ebt_redirect_info)) + if (datalen != EBT_ALIGN(sizeof(struct ebt_redirect_info))) return -EINVAL; if (BASE_CHAIN && info->target == EBT_RETURN) return -EINVAL; diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c index c457ac90c5c6..ae0f0539c5f0 100644 --- a/net/bridge/netfilter/ebt_snat.c +++ b/net/bridge/netfilter/ebt_snat.c @@ -40,7 +40,7 @@ static int ebt_target_snat_check(const char *tablename, unsigned int hookmask, { struct ebt_nat_info *info = (struct ebt_nat_info *) data; - if (datalen != sizeof(struct ebt_nat_info)) + if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info))) return -EINVAL; if (BASE_CHAIN && info->target == EBT_RETURN) return -EINVAL; diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c index 8be478935ba8..d0299efa1001 100644 --- a/net/bridge/netfilter/ebt_stp.c +++ b/net/bridge/netfilter/ebt_stp.c @@ -150,7 +150,7 @@ static int ebt_stp_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_stp_info *info = (struct ebt_stp_info *)data; - int len = sizeof(struct ebt_stp_info); + int len = EBT_ALIGN(sizeof(struct ebt_stp_info)); uint8_t bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; uint8_t msk[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c index 54120a771d3e..341af7d5708b 100644 --- a/net/bridge/netfilter/ebt_vlan.c +++ b/net/bridge/netfilter/ebt_vlan.c @@ -35,7 +35,7 @@ MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v" MODULE_LICENSE("GPL"); -#define DEBUG_MSG(...) if (debug) printk (KERN_DEBUG "ebt_vlan: " __VA_ARGS__) +#define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args) #define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : "" #define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_ #define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_ @@ -94,7 +94,7 @@ ebt_check_vlan(const char *tablename, struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; /* Parameters buffer overflow check */ - if (datalen != sizeof(struct ebt_vlan_info)) { + if (datalen != EBT_ALIGN(sizeof(struct ebt_vlan_info))) { DEBUG_MSG ("passed size %d is not eq to ebt_vlan_info (%Zd)\n", datalen, sizeof(struct ebt_vlan_info)); diff --git a/net/core/filter.c b/net/core/filter.c index 3bb1e4669ba5..5b2a5b785462 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -256,10 +256,9 @@ load_b: k = X + fentry->k; goto load_b; case BPF_LDX|BPF_B|BPF_MSH: - k = fentry->k; - if (k >= 0 && (unsigned int)k >= len) + if (fentry->k >= len) return 0; - X = (data[k] & 0xf) << 2; + X = (data[fentry->k] & 0xf) << 2; continue; case BPF_LD|BPF_IMM: A = fentry->k; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index fcb38de5ad40..e163036c3f83 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -186,7 +186,7 @@ struct netstat_fs_entry { static ssize_t net_device_stat_show(unsigned long var, char *buf) { - return sprintf(buf, "%ld\n", var); + return sprintf(buf, "%lu\n", var); } /* generate a read-only statistics attribute */ diff --git a/net/core/netfilter.c b/net/core/netfilter.c index 1c08a5bfae90..980cd4514d69 100644 --- a/net/core/netfilter.c +++ b/net/core/netfilter.c @@ -625,66 +625,62 @@ int ip_route_me_harder(struct sk_buff **pskb) { struct iphdr *iph = (*pskb)->nh.iph; struct rtable *rt; - struct flowi fl = { .nl_u = { .ip4_u = - { .daddr = iph->daddr, - .saddr = iph->saddr, - .tos = RT_TOS(iph->tos)|RTO_CONN, -#ifdef CONFIG_IP_ROUTE_FWMARK - .fwmark = (*pskb)->nfmark -#endif - } }, - .oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0, - }; - struct net_device *dev_src = NULL; - int err; - - /* accommodate ip_route_output_slow(), which expects the key src to be - 0 or a local address; however some non-standard hacks like - ipt_REJECT.c:send_reset() can cause packets with foreign - saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */ - if(fl.fl4_src && !(dev_src = ip_dev_find(fl.fl4_src))) - fl.fl4_src = 0; - - if ((err=ip_route_output_key(&rt, &fl)) != 0) { - printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n", - NIPQUAD(iph->daddr), NIPQUAD(iph->saddr), - (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0, - RT_TOS(iph->tos)|RTO_CONN, + struct flowi fl = {}; + struct dst_entry *odst; + unsigned int hh_len; + + /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause + * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook. + */ + if (inet_addr_type(iph->saddr) == RTN_LOCAL) { + fl.nl_u.ip4_u.daddr = iph->daddr; + fl.nl_u.ip4_u.saddr = iph->saddr; + fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); + fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0; #ifdef CONFIG_IP_ROUTE_FWMARK - (*pskb)->nfmark, -#else - 0UL, + fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark; #endif - err); - goto out; - } + if (ip_route_output_key(&rt, &fl) != 0) + return -1; - /* Drop old route. */ - dst_release((*pskb)->dst); - - (*pskb)->dst = &rt->u.dst; + /* Drop old route. */ + dst_release((*pskb)->dst); + (*pskb)->dst = &rt->u.dst; + } else { + /* non-local src, find valid iif to satisfy + * rp-filter when calling ip_route_input. */ + fl.nl_u.ip4_u.daddr = iph->saddr; + if (ip_route_output_key(&rt, &fl) != 0) + return -1; + + odst = (*pskb)->dst; + if (ip_route_input(*pskb, iph->daddr, iph->saddr, + RT_TOS(iph->tos), rt->u.dst.dev) != 0) { + dst_release(&rt->u.dst); + return -1; + } + dst_release(&rt->u.dst); + dst_release(odst); + } + + if ((*pskb)->dst->error) + return -1; /* Change in oif may mean change in hh_len. */ - if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) { + hh_len = (*pskb)->dst->dev->hard_header_len; + if (skb_headroom(*pskb) < hh_len) { struct sk_buff *nskb; - nskb = skb_realloc_headroom(*pskb, - (*pskb)->dst->dev->hard_header_len); - if (!nskb) { - err = -ENOMEM; - goto out; - } + nskb = skb_realloc_headroom(*pskb, hh_len); + if (!nskb) + return -1; if ((*pskb)->sk) skb_set_owner_w(nskb, (*pskb)->sk); kfree_skb(*pskb); *pskb = nskb; } -out: - if (dev_src) - dev_put(dev_src); - - return err; + return 0; } int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len) diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 2fd263454969..0652fdaf9079 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -47,6 +47,9 @@ * Also moved to /proc/net/pktgen/ * --ro * + * Fix refcount off by one if first packet fails, potential null deref, + * memleak 030710- KJP + * * See Documentation/networking/pktgen.txt for how to use this. */ @@ -85,9 +88,9 @@ #define cycles() ((u32)get_cycles()) -#define VERSION "pktgen version 1.2" +#define VERSION "pktgen version 1.3" static char version[] __initdata = - "pktgen.c: v1.2: Packet Generator for packet performance testing.\n"; + "pktgen.c: v1.3: Packet Generator for packet performance testing.\n"; /* Used to help with determining the pkts on receive */ @@ -611,12 +614,11 @@ static void inject(struct pktgen_info* info) kfree_skb(skb); skb = fill_packet(odev, info); if (skb == NULL) { - break; + goto out_reldev; } fp++; fp_tmp = 0; /* reset counter */ } - atomic_inc(&skb->users); } nr_frags = skb_shinfo(skb)->nr_frags; @@ -624,7 +626,11 @@ static void inject(struct pktgen_info* info) spin_lock_bh(&odev->xmit_lock); if (!netif_queue_stopped(odev)) { + atomic_inc(&skb->users); + if (odev->hard_start_xmit(skb, odev)) { + + atomic_dec(&skb->users); if (net_ratelimit()) { printk(KERN_INFO "Hard xmit error\n"); } @@ -729,15 +735,15 @@ static void inject(struct pktgen_info* info) (unsigned long long) info->errors ); } - + + kfree_skb(skb); + out_reldev: if (odev) { dev_put(odev); odev = NULL; } - /* TODO: Is this worth printing out (other than for debug?) */ - printk("fp = %llu\n", (unsigned long long) fp); return; } @@ -953,7 +959,8 @@ static int proc_write(struct file *file, const char *user_buffer, if (len < 0) return len; memset(name, 0, sizeof(name)); - copy_from_user(name, &user_buffer[i], len); + if (copy_from_user(name, &user_buffer[i], len)) + return -EFAULT; i += len; max = count -i; @@ -1083,18 +1090,20 @@ static int proc_write(struct file *file, const char *user_buffer, if (len < 0) return len; memset(info->outdev, 0, sizeof(info->outdev)); - copy_from_user(info->outdev, &user_buffer[i], len); + if (copy_from_user(info->outdev, &user_buffer[i], len)) + return -EFAULT; i += len; sprintf(result, "OK: odev=%s", info->outdev); return count; } if (!strcmp(name, "flag")) { char f[32]; - memset(f, 0, 32); len = strn_len(&user_buffer[i], sizeof(f) - 1); if (len < 0) return len; - copy_from_user(f, &user_buffer[i], len); + memset(f, 0, 32); + if (copy_from_user(f, &user_buffer[i], len)) + return -EFAULT; i += len; if (strcmp(f, "IPSRC_RND") == 0) { info->flags |= F_IPSRC_RND; @@ -1146,7 +1155,8 @@ static int proc_write(struct file *file, const char *user_buffer, if (len < 0) return len; memset(info->dst_min, 0, sizeof(info->dst_min)); - copy_from_user(info->dst_min, &user_buffer[i], len); + if (copy_from_user(info->dst_min, &user_buffer[i], len)) + return -EFAULT; if(debug) printk("pg: dst_min set to: %s\n", info->dst_min); i += len; @@ -1158,7 +1168,8 @@ static int proc_write(struct file *file, const char *user_buffer, if (len < 0) return len; memset(info->dst_max, 0, sizeof(info->dst_max)); - copy_from_user(info->dst_max, &user_buffer[i], len); + if (copy_from_user(info->dst_max, &user_buffer[i], len)) + return -EFAULT; if(debug) printk("pg: dst_max set to: %s\n", info->dst_max); i += len; @@ -1170,7 +1181,8 @@ static int proc_write(struct file *file, const char *user_buffer, if (len < 0) return len; memset(info->src_min, 0, sizeof(info->src_min)); - copy_from_user(info->src_min, &user_buffer[i], len); + if (copy_from_user(info->src_min, &user_buffer[i], len)) + return -EFAULT; if(debug) printk("pg: src_min set to: %s\n", info->src_min); i += len; @@ -1182,7 +1194,8 @@ static int proc_write(struct file *file, const char *user_buffer, if (len < 0) return len; memset(info->src_max, 0, sizeof(info->src_max)); - copy_from_user(info->src_max, &user_buffer[i], len); + if (copy_from_user(info->src_max, &user_buffer[i], len)) + return -EFAULT; if(debug) printk("pg: src_max set to: %s\n", info->src_max); i += len; @@ -1197,7 +1210,8 @@ static int proc_write(struct file *file, const char *user_buffer, if (len < 0) return len; memset(valstr, 0, sizeof(valstr)); - copy_from_user(valstr, &user_buffer[i], len); + if (copy_from_user(valstr, &user_buffer[i], len)) + return -EFAULT; i += len; for(*m = 0;*v && m < info->dst_mac + 6; v++) { @@ -1229,7 +1243,8 @@ static int proc_write(struct file *file, const char *user_buffer, if (len < 0) return len; memset(valstr, 0, sizeof(valstr)); - copy_from_user(valstr, &user_buffer[i], len); + if (copy_from_user(valstr, &user_buffer[i], len)) + return -EFAULT; i += len; for(*m = 0;*v && m < info->src_mac + 6; v++) { diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 32e64ed866a3..4215e4a7dcd0 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -191,9 +191,18 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, if (dev->master) RTA_PUT(skb, IFLA_MASTER, sizeof(int), &dev->master->ifindex); if (dev->get_stats) { - struct net_device_stats *stats = dev->get_stats(dev); - if (stats) - RTA_PUT(skb, IFLA_STATS, sizeof(*stats), stats); + unsigned long *stats = (unsigned long*)dev->get_stats(dev); + if (stats) { + struct rtattr *a; + __u32 *s; + int i; + int n = sizeof(struct rtnl_link_stats)/4; + + a = __RTA_PUT(skb, IFLA_STATS, n*4); + s = RTA_DATA(a); + for (i=0; i<n; i++) + s[i] = stats[i]; + } } nlh->nlmsg_len = skb->tail - b; return skb->len; diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 3e38ed82429b..9ea7856f9fbc 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -86,7 +86,7 @@ ctl_table core_table[] = { { .ctl_name = NET_CORE_NO_CONG_THRESH, .procname = "no_cong_thresh", - .data = &no_cong, + .data = &no_cong_thresh, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 318740b029d6..296938c8cfca 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -2308,6 +2308,7 @@ out_kfree: } static struct file_operations dn_socket_seq_fops = { + .owner = THIS_MODULE, .open = dn_socket_seq_open, .read = seq_read, .llseek = seq_lseek, diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 63fdae09b071..2b8050dc1cd3 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -1443,6 +1443,7 @@ static int dn_dev_seq_open(struct inode *inode, struct file *file) } static struct file_operations dn_dev_seq_fops = { + .owner = THIS_MODULE, .open = dn_dev_seq_open, .read = seq_read, .llseek = seq_lseek, diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index cbaa260873ec..fb87e4730f64 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1766,6 +1766,7 @@ out_kfree: } static struct file_operations dn_rt_cache_seq_fops = { + .owner = THIS_MODULE, .open = dn_rt_cache_seq_open, .read = seq_read, .llseek = seq_lseek, diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index d26810835859..e58581b20e22 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1313,7 +1313,7 @@ void __init ip_init(void) ip_rt_init(); inet_initpeers(); -#ifdef CONFIG_IP_MULTICAST +#if defined(CONFIG_IP_MULTICAST) && defined(CONFIG_PROC_FS) igmp_mc_proc_init(); #endif } diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 0c19a8881a94..b0f1db9c9357 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -251,7 +251,7 @@ static void unexpect_related(struct ip_conntrack_expect *expect) } /* delete all unconfirmed expectations for this conntrack */ -static void remove_expectations(struct ip_conntrack *ct) +static void remove_expectations(struct ip_conntrack *ct, int drop_refcount) { struct list_head *exp_entry, *next; struct ip_conntrack_expect *exp; @@ -266,8 +266,11 @@ static void remove_expectations(struct ip_conntrack *ct) * the un-established ones only */ if (exp->sibling) { DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct); - /* Indicate that this expectations parent is dead */ - exp->expectant = NULL; + if (drop_refcount) { + /* Indicate that this expectations parent is dead */ + ip_conntrack_put(exp->expectant); + exp->expectant = NULL; + } continue; } @@ -292,7 +295,7 @@ clean_from_lists(struct ip_conntrack *ct) &ct->tuplehash[IP_CT_DIR_REPLY]); /* Destroy all un-established, pending expectations */ - remove_expectations(ct); + remove_expectations(ct, 1); } static void @@ -1117,7 +1120,7 @@ static inline int unhelp(struct ip_conntrack_tuple_hash *i, { if (i->ctrack->helper == me) { /* Get rid of any expected. */ - remove_expectations(i->ctrack); + remove_expectations(i->ctrack, 0); /* And *then* set helper to NULL */ i->ctrack->helper = NULL; } diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c index 79bb3f076b5c..7cb21646e214 100644 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ b/net/ipv4/netfilter/ip_conntrack_irc.c @@ -54,7 +54,7 @@ MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); #endif static char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " }; -#define MAXMATCHLEN 6 +#define MINMATCHLEN 5 DECLARE_LOCK(ip_irc_lock); struct module *ip_conntrack_irc = THIS_MODULE; @@ -87,9 +87,11 @@ int parse_dcc(char *data, char *data_end, u_int32_t * ip, u_int16_t * port, *ip = simple_strtoul(data, &data, 10); /* skip blanks between ip and port */ - while (*data == ' ') + while (*data == ' ') { + if (data >= data_end) + return -1; data++; - + } *port = simple_strtoul(data, &data, 10); *ad_end_p = data; @@ -139,13 +141,17 @@ static int help(struct sk_buff *skb, data = irc_buffer; data_limit = irc_buffer + skb->len - dataoff; - while (data < (data_limit - (22 + MAXMATCHLEN))) { + + /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24 + * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */ + while (data < (data_limit - (19 + MINMATCHLEN))) { if (memcmp(data, "\1DCC ", 5)) { data++; continue; } data += 5; + /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n", NIPQUAD(iph->saddr), ntohs(tcph.source), @@ -159,6 +165,9 @@ static int help(struct sk_buff *skb, DEBUGP("DCC %s detected\n", dccprotos[i]); data += strlen(dccprotos[i]); + /* we have at least + * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid + * data left (== 14/13 bytes) */ if (parse_dcc((char *)data, data_limit, &dcc_ip, &dcc_port, &addr_beg_p, &addr_end_p)) { /* unable to parse */ diff --git a/net/ipv4/netfilter/ipt_MIRROR.c b/net/ipv4/netfilter/ipt_MIRROR.c index 3f8faff13dc4..1d64fe1cbfe6 100644 --- a/net/ipv4/netfilter/ipt_MIRROR.c +++ b/net/ipv4/netfilter/ipt_MIRROR.c @@ -9,6 +9,12 @@ Changes: 25 Aug 2001 Harald Welte <laforge@gnumonks.org> - decrement and check TTL if not called from FORWARD hook + 18 Jul 2003 Harald Welte <laforge@netfilter.org> + - merge Patrick McHardy's mirror fixes from 2.4.22 to + 2.6.0-test1 + 19 Jul 2003 Harald Welte <laforge@netfilter.org> + - merge Patrick McHardy's rp_filter fixes from 2.4.22 to + 2.6.0-test1 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -32,7 +38,6 @@ #include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netdevice.h> #include <linux/route.h> -struct in_device; #include <net/route.h> #if 0 @@ -41,46 +46,58 @@ struct in_device; #define DEBUGP(format, args...) #endif -static int route_mirror(struct sk_buff *skb) +static inline struct rtable *route_mirror(struct sk_buff *skb, int local) { struct iphdr *iph = skb->nh.iph; - struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr, - .saddr = iph->daddr, - .tos = RT_TOS(iph->tos) | RTO_CONN } } }; + struct dst_entry *odst; + struct flowi fl = {}; struct rtable *rt; - /* Backwards */ - if (ip_route_output_key(&rt, &fl)) { - return 0; + if (local) { + fl.nl_u.ip4_u.daddr = iph->saddr; + fl.nl_u.ip4_u.saddr = iph->daddr; + fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); + + if (ip_route_output_key(&rt, &fl) != 0) + return NULL; + } else { + /* non-local src, find valid iif to satisfy + * rp-filter when calling ip_route_input(). */ + fl.nl_u.ip4_u.daddr = iph->daddr; + if (ip_route_output_key(&rt, &fl) != 0) + return NULL; + + odst = skb->dst; + if (ip_route_input(skb, iph->saddr, iph->daddr, + RT_TOS(iph->tos), rt->u.dst.dev) != 0) { + dst_release(&rt->u.dst); + return NULL; + } + dst_release(&rt->u.dst); + rt = (struct rtable *)skb->dst; + skb->dst = odst; } - /* check if the interface we are leaving by is the same as the - one we arrived on */ - if (skb->dev == rt->u.dst.dev) { - /* Drop old route. */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; - return 1; + if (rt->u.dst.error) { + dst_release(&rt->u.dst); + rt = NULL; } - return 0; + + return rt; } -static int ip_rewrite(struct sk_buff **pskb) +static inline void ip_rewrite(struct sk_buff *skb) { u32 odaddr, osaddr; - if (!skb_ip_make_writable(pskb, sizeof(struct iphdr))) - return 0; + odaddr = skb->nh.iph->saddr; + osaddr = skb->nh.iph->daddr; - odaddr = (*pskb)->nh.iph->saddr; - osaddr = (*pskb)->nh.iph->daddr; - - (*pskb)->nfcache |= NFC_ALTERED; + skb->nfcache |= NFC_ALTERED; /* Rewrite IP header */ - (*pskb)->nh.iph->daddr = odaddr; - (*pskb)->nh.iph->saddr = osaddr; - return 1; + skb->nh.iph->daddr = odaddr; + skb->nh.iph->saddr = osaddr; } /* Stolen from ip_finish_output2 */ @@ -113,31 +130,51 @@ static unsigned int ipt_mirror_target(struct sk_buff **pskb, const void *targinfo, void *userinfo) { - if (((*pskb)->dst != NULL) && route_mirror(*pskb)) { - if (!ip_rewrite(pskb)) - return NF_DROP; + struct rtable *rt; + struct sk_buff *nskb; + unsigned int hh_len; - /* If we are not at FORWARD hook (INPUT/PREROUTING), - * the TTL isn't decreased by the IP stack */ - if (hooknum != NF_IP_FORWARD) { - if ((*pskb)->nh.iph->ttl <= 1) { - /* this will traverse normal stack, and - * thus call conntrack on the icmp packet */ - icmp_send(*pskb, ICMP_TIME_EXCEEDED, - ICMP_EXC_TTL, 0); - return NF_DROP; - } - /* Made writable by ip_rewrite */ - ip_decrease_ttl((*pskb)->nh.iph); + /* Make skb writable */ + if (!skb_ip_make_writable(pskb, sizeof(struct iphdr))) + return 0; + + /* If we are not at FORWARD hook (INPUT/PREROUTING), + * the TTL isn't decreased by the IP stack */ + if (hooknum != NF_IP_FORWARD) { + if ((*pskb)->nh.iph->ttl <= 1) { + /* this will traverse normal stack, and + * thus call conntrack on the icmp packet */ + icmp_send(*pskb, ICMP_TIME_EXCEEDED, + ICMP_EXC_TTL, 0); + return NF_DROP; } + ip_decrease_ttl((*pskb)->nh.iph); + } - /* Don't let conntrack code see this packet: - it will think we are starting a new - connection! --RR */ - ip_direct_send(*pskb); + if ((rt = route_mirror(*pskb, hooknum == NF_IP_LOCAL_IN)) == NULL) + return NF_DROP; - return NF_STOLEN; + hh_len = (rt->u.dst.dev->hard_header_len + 15) & ~15; + + /* Copy skb (even if skb is about to be dropped, we can't just + * clone it because there may be other things, such as tcpdump, + * interested in it). We also need to expand headroom in case + * hh_len of incoming interface < hh_len of outgoing interface */ + nskb = skb_copy_expand(*pskb, hh_len, skb_tailroom(*pskb), GFP_ATOMIC); + if (nskb == NULL) { + dst_release(&rt->u.dst); + return NF_DROP; } + + dst_release(nskb->dst); + nskb->dst = &rt->u.dst; + + ip_rewrite(nskb); + /* Don't let conntrack code see this packet: + * it will think we are starting a new + * connection! --RR */ + ip_direct_send(nskb); + return NF_DROP; } diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 2582a825f499..c1147531acd2 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -1,6 +1,7 @@ /* * This is a module which is used for rejecting packets. * Added support for customized reject packets (Jozsef Kadlecsik). + * Added support for ICMP type-3-code-13 (Maciej Soltysiak). [RFC 1812] */ #include <linux/config.h> #include <linux/module.h> @@ -35,134 +36,180 @@ static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct) } } +static inline struct rtable *route_reverse(struct sk_buff *skb, int local) +{ + struct iphdr *iph = skb->nh.iph; + struct dst_entry *odst; + struct flowi fl = {}; + struct rtable *rt; + + if (local) { + fl.nl_u.ip4_u.daddr = iph->saddr; + fl.nl_u.ip4_u.saddr = iph->daddr; + fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); + + if (ip_route_output_key(&rt, &fl) != 0) + return NULL; + } else { + /* non-local src, find valid iif to satisfy + * rp-filter when calling ip_route_input. */ + fl.nl_u.ip4_u.daddr = iph->daddr; + if (ip_route_output_key(&rt, &fl) != 0) + return NULL; + + odst = skb->dst; + if (ip_route_input(skb, iph->saddr, iph->daddr, + RT_TOS(iph->tos), rt->u.dst.dev) != 0) { + dst_release(&rt->u.dst); + return NULL; + } + dst_release(&rt->u.dst); + rt = (struct rtable *)skb->dst; + skb->dst = odst; + } + + if (rt->u.dst.error) { + dst_release(&rt->u.dst); + rt = NULL; + } + + return rt; +} + /* Send RST reply */ -static unsigned int send_reset(struct sk_buff **pskb, int local) +static void send_reset(struct sk_buff *oldskb, int local) { - struct tcphdr tcph; + struct sk_buff *nskb; + struct tcphdr *otcph, *tcph; struct rtable *rt; + unsigned int otcplen; u_int16_t tmp_port; u_int32_t tmp_addr; - int needs_ack, hh_len, datalen; - struct nf_ct_info *oldnfct; + int needs_ack; + int hh_len; - /* No RSTs for fragments. */ - if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) - return NF_DROP; + /* IP header checks: fragment, too short. */ + if (oldskb->nh.iph->frag_off & htons(IP_OFFSET) + || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr)) + return; - if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4, - &tcph, sizeof(tcph)) < 0) - return NF_DROP; + otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl); + otcplen = oldskb->len - oldskb->nh.iph->ihl*4; + + if (skb_copy_bits(oldskb, oldskb->nh.iph->ihl*4, + otcph, sizeof(*otcph)) < 0) + return; /* No RST for RST. */ - if (tcph.rst) - return NF_DROP; + if (otcph->rst) + return; - /* FIXME: Check checksum. */ - { - struct flowi fl = { .nl_u = { .ip4_u = - { .daddr = (*pskb)->nh.iph->saddr, - .saddr = (local ? - (*pskb)->nh.iph->daddr : - 0), - .tos = RT_TOS((*pskb)->nh.iph->tos) } } }; + /* Check checksum. */ + if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr, + oldskb->nh.iph->daddr, + csum_partial((char *)otcph, otcplen, 0)) != 0) + return; - /* Routing: if not headed for us, route won't like source */ - if (ip_route_output_key(&rt, &fl)) - return NF_DROP; + if ((rt = route_reverse(oldskb, local)) == NULL) + return; - hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; - } + hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; - /* We're going to flip the header around, drop options and data. */ - if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(tcph))) { - ip_rt_put(rt); - return NF_DROP; + /* Copy skb (even if skb is about to be dropped, we can't just + clone it because there may be other things, such as tcpdump, + interested in it). We also need to expand headroom in case + hh_len of incoming interface < hh_len of outgoing interface */ + nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb), + GFP_ATOMIC); + if (!nskb) { + dst_release(&rt->u.dst); + return; } - (*pskb)->h.th = (void *)(*pskb)->nh.iph + sizeof(tcph); - datalen = (*pskb)->len - (*pskb)->nh.iph->ihl*4 - tcph.doff*4; - - /* Change over route. */ - dst_release((*pskb)->dst); - (*pskb)->dst = &rt->u.dst; + dst_release(nskb->dst); + nskb->dst = &rt->u.dst; /* This packet will not be the same as the other: clear nf fields */ - (*pskb)->nfcache = 0; + nf_conntrack_put(nskb->nfct); + nskb->nfct = NULL; + nskb->nfcache = 0; #ifdef CONFIG_NETFILTER_DEBUG - (*pskb)->nf_debug = 0; + nskb->nf_debug = 0; #endif - (*pskb)->nfmark = 0; + nskb->nfmark = 0; + + tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); /* Swap source and dest */ - tmp_addr = (*pskb)->nh.iph->saddr; - (*pskb)->nh.iph->saddr = (*pskb)->nh.iph->daddr; - (*pskb)->nh.iph->daddr = tmp_addr; - tmp_port = (*pskb)->h.th->source; - (*pskb)->h.th->source = (*pskb)->h.th->dest; - (*pskb)->h.th->dest = tmp_port; + tmp_addr = nskb->nh.iph->saddr; + nskb->nh.iph->saddr = nskb->nh.iph->daddr; + nskb->nh.iph->daddr = tmp_addr; + tmp_port = tcph->source; + tcph->source = tcph->dest; + tcph->dest = tmp_port; /* Truncate to length (no data) */ - (*pskb)->h.th->doff = sizeof(struct tcphdr)/4; - skb_trim(*pskb, (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr)); - (*pskb)->nh.iph->tot_len = htons((*pskb)->len); + tcph->doff = sizeof(struct tcphdr)/4; + skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); + nskb->nh.iph->tot_len = htons(nskb->len); - if ((*pskb)->h.th->ack) { + if (tcph->ack) { needs_ack = 0; - (*pskb)->h.th->seq = tcph.ack_seq; - (*pskb)->h.th->ack_seq = 0; + tcph->seq = otcph->ack_seq; + tcph->ack_seq = 0; } else { needs_ack = 1; - (*pskb)->h.th->ack_seq = htonl(ntohl(tcph.seq) - + tcph.syn + tcph.fin - + datalen); - (*pskb)->h.th->seq = 0; + tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin + + otcplen - (otcph->doff<<2)); + tcph->seq = 0; } /* Reset flags */ - memset((*pskb)->h.raw + 13, 0, 1); - (*pskb)->h.th->rst = 1; - (*pskb)->h.th->ack = needs_ack; + ((u_int8_t *)tcph)[13] = 0; + tcph->rst = 1; + tcph->ack = needs_ack; - (*pskb)->h.th->window = 0; - (*pskb)->h.th->urg_ptr = 0; + tcph->window = 0; + tcph->urg_ptr = 0; /* Adjust TCP checksum */ - (*pskb)->h.th->check = 0; - (*pskb)->h.th->check - = tcp_v4_check((*pskb)->h.th, - sizeof(struct tcphdr), - (*pskb)->nh.iph->saddr, - (*pskb)->nh.iph->daddr, - csum_partial((*pskb)->h.raw, - sizeof(struct tcphdr), 0)); + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), + nskb->nh.iph->saddr, + nskb->nh.iph->daddr, + csum_partial((char *)tcph, + sizeof(struct tcphdr), 0)); /* Adjust IP TTL, DF */ - (*pskb)->nh.iph->ttl = MAXTTL; + nskb->nh.iph->ttl = MAXTTL; /* Set DF, id = 0 */ - (*pskb)->nh.iph->frag_off = htons(IP_DF); - (*pskb)->nh.iph->id = 0; + nskb->nh.iph->frag_off = htons(IP_DF); + nskb->nh.iph->id = 0; /* Adjust IP checksum */ - (*pskb)->nh.iph->check = 0; - (*pskb)->nh.iph->check = ip_fast_csum((*pskb)->nh.raw, - (*pskb)->nh.iph->ihl); + nskb->nh.iph->check = 0; + nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, + nskb->nh.iph->ihl); /* "Never happens" */ - if ((*pskb)->len > dst_pmtu((*pskb)->dst)) - return NF_DROP; + if (nskb->len > dst_pmtu(nskb->dst)) + goto free_nskb; - /* Related to old connection. */ - oldnfct = (*pskb)->nfct; - connection_attach(*pskb, oldnfct); - nf_conntrack_put(oldnfct); + connection_attach(nskb, oldskb->nfct); - NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, *pskb, NULL, (*pskb)->dst->dev, + NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, ip_finish_output); - return NF_STOLEN; + return; + + free_nskb: + kfree_skb(nskb); } -static void send_unreach(const struct sk_buff *skb_in, int code) +static void send_unreach(struct sk_buff *skb_in, int code) { + struct iphdr *iph; + struct udphdr *udph; + struct icmphdr *icmph; struct sk_buff *nskb; u32 saddr; u8 tos; @@ -177,6 +224,8 @@ static void send_unreach(const struct sk_buff *skb_in, int code) if (!xrlim_allow(&rt->u.dst, 1*HZ)) return; + iph = skb_in->nh.iph; + /* No replies to physical multicast/broadcast */ if (skb_in->pkt_type!=PACKET_HOST) return; @@ -186,38 +235,52 @@ static void send_unreach(const struct sk_buff *skb_in, int code) return; /* Only reply to fragment 0. */ - if (skb_in->nh.iph->frag_off&htons(IP_OFFSET)) + if (iph->frag_off&htons(IP_OFFSET)) return; /* Ensure we have at least 8 bytes of proto header. */ if (skb_in->len < skb_in->nh.iph->ihl*4 + 8) return; + /* if UDP checksum is set, verify it's correct */ + if (iph->protocol == IPPROTO_UDP + && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) { + int datalen = skb_in->len - (iph->ihl<<2); + udph = (struct udphdr *)((char *)iph + (iph->ihl<<2)); + if (udph->check + && csum_tcpudp_magic(iph->saddr, iph->daddr, + datalen, IPPROTO_UDP, + csum_partial((char *)udph, datalen, + 0)) != 0) + return; + } + /* If we send an ICMP error to an ICMP error a mess would result.. */ - if (skb_in->nh.iph->protocol == IPPROTO_ICMP) { - struct icmphdr icmph; + if (iph->protocol == IPPROTO_ICMP + && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) { + icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); if (skb_copy_bits(skb_in, skb_in->nh.iph->ihl*4, - &icmph, sizeof(icmph)) < 0) + icmph, sizeof(*icmph)) < 0) return; /* Between echo-reply (0) and timestamp (13), everything except echo-request (8) is an error. Also, anything greater than NR_ICMP_TYPES is unknown, and hence should be treated as an error... */ - if ((icmph.type < ICMP_TIMESTAMP - && icmph.type != ICMP_ECHOREPLY - && icmph.type != ICMP_ECHO) - || icmph.type > NR_ICMP_TYPES) + if ((icmph->type < ICMP_TIMESTAMP + && icmph->type != ICMP_ECHOREPLY + && icmph->type != ICMP_ECHO) + || icmph->type > NR_ICMP_TYPES) return; } - saddr = skb_in->nh.iph->daddr; + saddr = iph->daddr; if (!(rt->rt_flags & RTCF_LOCAL)) saddr = 0; - tos = (skb_in->nh.iph->tos & IPTOS_TOS_MASK) - | IPTOS_PREC_INTERNETCONTROL; + tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL; + { struct flowi fl = { .nl_u = { .ip4_u = { .daddr = skb_in->nh.iph->saddr, @@ -247,38 +310,41 @@ static void send_unreach(const struct sk_buff *skb_in, int code) skb_reserve(nskb, hh_len); /* Set up IP header */ - nskb->nh.iph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); - nskb->nh.iph->version=4; - nskb->nh.iph->ihl=5; - nskb->nh.iph->tos=tos; - nskb->nh.iph->tot_len = htons(length); + iph = nskb->nh.iph + = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); + iph->version=4; + iph->ihl=5; + iph->tos=tos; + iph->tot_len = htons(length); /* PMTU discovery never applies to ICMP packets. */ - nskb->nh.iph->frag_off = 0; + iph->frag_off = 0; - nskb->nh.iph->ttl = MAXTTL; - ip_select_ident(nskb->nh.iph, &rt->u.dst, NULL); - nskb->nh.iph->protocol=IPPROTO_ICMP; - nskb->nh.iph->saddr=rt->rt_src; - nskb->nh.iph->daddr=rt->rt_dst; - nskb->nh.iph->check=0; - nskb->nh.iph->check = ip_fast_csum(nskb->nh.raw, - nskb->nh.iph->ihl); + iph->ttl = MAXTTL; + ip_select_ident(iph, &rt->u.dst, NULL); + iph->protocol=IPPROTO_ICMP; + iph->saddr=rt->rt_src; + iph->daddr=rt->rt_dst; + iph->check=0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); /* Set up ICMP header. */ - nskb->h.icmph = (struct icmphdr *)skb_put(nskb,sizeof(struct icmphdr)); - nskb->h.icmph->type = ICMP_DEST_UNREACH; - nskb->h.icmph->code = code; - nskb->h.icmph->un.gateway = 0; - nskb->h.icmph->checksum = 0; + icmph = nskb->h.icmph + = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr)); + icmph->type = ICMP_DEST_UNREACH; + icmph->code = code; + icmph->un.gateway = 0; + icmph->checksum = 0; /* Copy as much of original packet as will fit */ data = skb_put(nskb, length - sizeof(struct iphdr) - sizeof(struct icmphdr)); + skb_copy_bits(skb_in, 0, data, length - sizeof(struct iphdr) - sizeof(struct icmphdr)); - nskb->h.icmph->checksum = ip_compute_csum(nskb->h.raw, - length-sizeof(struct iphdr)); + + icmph->checksum = ip_compute_csum((unsigned char *)icmph, + length - sizeof(struct iphdr)); connection_attach(nskb, skb_in->nfct); @@ -322,8 +388,11 @@ static unsigned int reject(struct sk_buff **pskb, case IPT_ICMP_HOST_PROHIBITED: send_unreach(*pskb, ICMP_HOST_ANO); break; + case IPT_ICMP_ADMIN_PROHIBITED: + send_unreach(*pskb, ICMP_PKT_FILTERED); + break; case IPT_TCP_RESET: - return send_reset(pskb, hooknum == NF_IP_LOCAL_IN); + send_reset(*pskb, hooknum == NF_IP_LOCAL_IN); case IPT_ICMP_ECHOREPLY: /* Doesn't happen. */ break; diff --git a/net/ipv4/netfilter/ipt_helper.c b/net/ipv4/netfilter/ipt_helper.c index 1f7efb91c5e8..28ab46445e4a 100644 --- a/net/ipv4/netfilter/ipt_helper.c +++ b/net/ipv4/netfilter/ipt_helper.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/skbuff.h> #include <linux/netfilter_ipv4/ip_conntrack.h> +#include <linux/netfilter_ipv4/ip_conntrack_core.h> #include <linux/netfilter_ipv4/ip_conntrack_helper.h> #include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ipt_helper.h> @@ -34,6 +35,7 @@ match(const struct sk_buff *skb, struct ip_conntrack_expect *exp; struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; + int ret = 0; ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); if (!ct) { @@ -47,23 +49,27 @@ match(const struct sk_buff *skb, } exp = ct->master; + READ_LOCK(&ip_conntrack_lock); if (!exp->expectant) { DEBUGP("ipt_helper: expectation %p without expectant !?!\n", exp); - return 0; + goto out_unlock; } if (!exp->expectant->helper) { DEBUGP("ipt_helper: master ct %p has no helper\n", exp->expectant); - return 0; + goto out_unlock; } DEBUGP("master's name = %s , info->name = %s\n", exp->expectant->helper->name, info->name); - return !strncmp(exp->expectant->helper->name, info->name, - strlen(exp->expectant->helper->name)) ^ info->invert; + ret = !strncmp(exp->expectant->helper->name, info->name, + strlen(exp->expectant->helper->name)) ^ info->invert; +out_unlock: + READ_UNLOCK(&ip_conntrack_lock); + return ret; } static int check(const char *tablename, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 649df9f76068..925effb2390c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -130,7 +130,7 @@ static spinlock_t addrconf_verify_lock = SPIN_LOCK_UNLOCKED; static int addrconf_ifdown(struct net_device *dev, int how); -static void addrconf_dad_start(struct inet6_ifaddr *ifp); +static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags); static void addrconf_dad_timer(unsigned long data); static void addrconf_dad_completed(struct inet6_ifaddr *ifp); static void addrconf_rs_timer(unsigned long data); @@ -710,7 +710,7 @@ retry: ift->prefered_lft = tmp_prefered_lft; ift->tstamp = ifp->tstamp; spin_unlock_bh(&ift->lock); - addrconf_dad_start(ift); + addrconf_dad_start(ift, 0); in6_ifa_put(ift); in6_dev_put(idev); out: @@ -1247,7 +1247,7 @@ static void addrconf_add_mroute(struct net_device *dev) rtmsg.rtmsg_dst_len = 8; rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; rtmsg.rtmsg_ifindex = dev->ifindex; - rtmsg.rtmsg_flags = RTF_UP|RTF_ADDRCONF; + rtmsg.rtmsg_flags = RTF_UP; rtmsg.rtmsg_type = RTMSG_NEWROUTE; ip6_route_add(&rtmsg, NULL, NULL); } @@ -1274,7 +1274,7 @@ static void addrconf_add_lroute(struct net_device *dev) struct in6_addr addr; ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); - addrconf_prefix_route(&addr, 64, dev, 0, RTF_ADDRCONF); + addrconf_prefix_route(&addr, 64, dev, 0, 0); } static struct inet6_dev *addrconf_add_dev(struct net_device *dev) @@ -1367,7 +1367,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) } } else if (valid_lft) { addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, - dev, rt_expires, RTF_ADDRCONF|RTF_EXPIRES); + dev, rt_expires, RTF_ADDRCONF|RTF_EXPIRES|RTF_PREFIX_RT); } if (rt) dst_release(&rt->u.dst); @@ -1413,7 +1413,7 @@ ok: } update_lft = create = 1; - addrconf_dad_start(ifp); + addrconf_dad_start(ifp, RTF_ADDRCONF|RTF_PREFIX_RT); } if (ifp) { @@ -1586,7 +1586,7 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen) ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { - addrconf_dad_start(ifp); + addrconf_dad_start(ifp, 0); in6_ifa_put(ifp); return 0; } @@ -1761,7 +1761,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT); if (!IS_ERR(ifp)) { - addrconf_dad_start(ifp); + addrconf_dad_start(ifp, 0); in6_ifa_put(ifp); } } @@ -2021,8 +2021,7 @@ static void addrconf_rs_timer(unsigned long data) memset(&rtmsg, 0, sizeof(struct in6_rtmsg)); rtmsg.rtmsg_type = RTMSG_NEWROUTE; rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; - rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_ADDRCONF | - RTF_DEFAULT | RTF_UP); + rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_DEFAULT | RTF_UP); rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex; @@ -2036,7 +2035,7 @@ out: /* * Duplicate Address Detection */ -static void addrconf_dad_start(struct inet6_ifaddr *ifp) +static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags) { struct net_device *dev; unsigned long rand_num; @@ -2046,7 +2045,8 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp) addrconf_join_solict(dev, &ifp->addr); if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT)) - addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0, RTF_ADDRCONF); + addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0, + flags); net_srandom(ifp->addr.s6_addr32[3]); rand_num = net_random() % (ifp->idev->cnf.rtr_solicit_delay ? : 1); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 69d7791712f8..b3adf22ef02e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1459,13 +1459,20 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, struct in6_addr *src, int iif, int type, u32 pid, u32 seq, - struct nlmsghdr *in_nlh) + struct nlmsghdr *in_nlh, int prefix) { struct rtmsg *rtm; struct nlmsghdr *nlh; unsigned char *b = skb->tail; struct rta_cacheinfo ci; + if (prefix) { /* user wants prefix routes only */ + if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { + /* success since this is not a prefix route */ + return 1; + } + } + if (!pid && in_nlh) { pid = in_nlh->nlmsg_pid; } @@ -1546,10 +1553,17 @@ rtattr_failure: static int rt6_dump_route(struct rt6_info *rt, void *p_arg) { struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg; + struct rtmsg *rtm; + int prefix; + + rtm = NLMSG_DATA(arg->cb->nlh); + if (rtm) + prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0; + else prefix = 0; return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq, - NULL); + NULL, prefix); } static int fib6_dump_node(struct fib6_walker_t *w) @@ -1697,7 +1711,7 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) &fl.fl6_dst, &fl.fl6_src, iif, RTM_NEWROUTE, NETLINK_CB(in_skb).pid, - nlh->nlmsg_seq, nlh); + nlh->nlmsg_seq, nlh, 0); if (err < 0) { err = -EMSGSIZE; goto out_free; @@ -1723,7 +1737,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh) netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS); return; } - if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0, nlh) < 0) { + if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0, nlh, 0) < 0) { kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL); return; |
