From fc482cc54e56bde012585905eb0f3565bec18ff5 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Fri, 25 Sep 2009 13:11:24 +0000 Subject: net: fix vlan_get_size to include vlan_flags size Fix vlan_get_size to include vlan->flags. Currently, the size of the vlan flags is not included in the nlmsg size. Signed-off-by: John Fastabend Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- net/8021q/vlan_netlink.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index 343146e1bceb..a91504850195 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -169,6 +169,7 @@ static size_t vlan_get_size(const struct net_device *dev) struct vlan_dev_info *vlan = vlan_dev_info(dev); return nla_total_size(2) + /* IFLA_VLAN_ID */ + sizeof(struct ifla_vlan_flags) + /* IFLA_VLAN_FLAGS */ vlan_qos_map_size(vlan->nr_ingress_mappings) + vlan_qos_map_size(vlan->nr_egress_mappings); } -- cgit v1.2.3 From 5dba93aedfc6906b27791c4a1136b177beae25b7 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Fri, 25 Sep 2009 13:11:44 +0000 Subject: net: fix nlmsg len size for skb when error bit is set. Currently, the nlmsg->len field is not set correctly in netlink_ack() for ack messages that include the nlmsg of the error frame. This corrects the length field passed to __nlmsg_put to use the correct payload size. Signed-off-by: John Fastabend Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index a4bafbf15097..dd85320907cb 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1788,7 +1788,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) } rep = __nlmsg_put(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, - NLMSG_ERROR, sizeof(struct nlmsgerr), 0); + NLMSG_ERROR, payload, 0); errmsg = nlmsg_data(rep); errmsg->error = err; memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(*nlh)); -- cgit v1.2.3 From 7eaf5077b37bb33dbd44e569ff88566d6fe286e9 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Fri, 25 Sep 2009 13:12:03 +0000 Subject: net: fix double skb free in dcbnl netlink_unicast() calls kfree_skb even in the error case. dcbnl calls netlink_unicast() which when it fails free's the skb and returns an error value. dcbnl is free'ing the skb again when this error occurs. This patch removes the double free. Signed-off-by: John Fastabend Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- net/dcb/dcbnl.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c index e0879bfb7dd5..ac1205df6c86 100644 --- a/net/dcb/dcbnl.c +++ b/net/dcb/dcbnl.c @@ -194,7 +194,7 @@ static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, nlmsg_end(dcbnl_skb, nlh); ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + return -EINVAL; return 0; nlmsg_failure: @@ -275,7 +275,7 @@ static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + goto err_out; return 0; nlmsg_failure: @@ -316,12 +316,11 @@ static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + goto err_out; return 0; nlmsg_failure: -err: kfree_skb(dcbnl_skb); err_out: return -EINVAL; @@ -383,7 +382,7 @@ static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + goto err_out; return 0; nlmsg_failure: @@ -460,7 +459,7 @@ static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) { ret = -EINVAL; - goto err; + goto err_out; } return 0; @@ -799,7 +798,7 @@ static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + goto err_out; return 0; @@ -1063,7 +1062,7 @@ static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb, ret = rtnl_unicast(dcbnl_skb, &init_net, pid); if (ret) - goto err; + goto err_out; return 0; -- cgit v1.2.3 From d1f8297a96b0d70f17704296a6666468f2087ce6 Mon Sep 17 00:00:00 2001 From: Sascha Hlusiak Date: Sat, 26 Sep 2009 20:28:07 -0700 Subject: Revert "sit: stateless autoconf for isatap" This reverts commit 645069299a1c7358cf7330afe293f07552f11a5d. While the code does not actually break anything, it does not completely follow RFC5214 yet. After talking back with Fred L. Templin, I agree that completing the ISATAP specific RS/RA code, would pollute the kernel a lot with code that is better implemented in userspace. The kernel should not send RS packages for ISATAP at all. Signed-off-by: Sascha Hlusiak Acked-by: Fred L. Templin Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 1 - net/ipv6/sit.c | 58 -------------------------------------------------------- 2 files changed, 59 deletions(-) (limited to 'net') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 498b9b0b0fad..f74e4e2cdd06 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -658,7 +658,6 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, &icmp6h, NULL, send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0); } -EXPORT_SYMBOL(ndisc_send_rs); static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index fcb539628847..d65e0c496cc0 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -15,7 +15,6 @@ * Roger Venning : 6to4 support * Nate Thompson : 6to4 support * Fred Templin : isatap support - * Sascha Hlusiak : stateless autoconf for isatap */ #include @@ -223,44 +222,6 @@ failed: return NULL; } -static void ipip6_tunnel_rs_timer(unsigned long data) -{ - struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *) data; - struct inet6_dev *ifp; - struct inet6_ifaddr *addr; - - spin_lock(&p->lock); - ifp = __in6_dev_get(p->tunnel->dev); - - read_lock_bh(&ifp->lock); - for (addr = ifp->addr_list; addr; addr = addr->if_next) { - struct in6_addr rtr; - - if (!(ipv6_addr_type(&addr->addr) & IPV6_ADDR_LINKLOCAL)) - continue; - - /* Send RS to guessed linklocal address of router - * - * Better: send to ff02::2 encapsuled in unicast directly - * to router-v4 instead of guessing the v6 address. - * - * Cisco/Windows seem to not set the u/l bit correctly, - * so we won't guess right. - */ - ipv6_addr_set(&rtr, htonl(0xFE800000), 0, 0, 0); - if (!__ipv6_isatap_ifid(rtr.s6_addr + 8, - p->addr)) { - ndisc_send_rs(p->tunnel->dev, &addr->addr, &rtr); - } - } - read_unlock_bh(&ifp->lock); - - mod_timer(&p->rs_timer, jiffies + HZ * p->rs_delay); - spin_unlock(&p->lock); - - return; -} - static struct ip_tunnel_prl_entry * __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) { @@ -319,7 +280,6 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, continue; kp[c].addr = prl->addr; kp[c].flags = prl->flags; - kp[c].rs_delay = prl->rs_delay; c++; if (kprl.addr != htonl(INADDR_ANY)) break; @@ -369,23 +329,11 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) } p->next = t->prl; - p->tunnel = t; t->prl = p; t->prl_count++; - - spin_lock_init(&p->lock); - setup_timer(&p->rs_timer, ipip6_tunnel_rs_timer, (unsigned long) p); update: p->addr = a->addr; p->flags = a->flags; - p->rs_delay = a->rs_delay; - if (p->rs_delay == 0) - p->rs_delay = IPTUNNEL_RS_DEFAULT_DELAY; - spin_lock(&p->lock); - del_timer(&p->rs_timer); - if (p->flags & PRL_DEFAULT) - mod_timer(&p->rs_timer, jiffies + 1); - spin_unlock(&p->lock); out: write_unlock(&ipip6_lock); return err; @@ -404,9 +352,6 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) if ((*p)->addr == a->addr) { x = *p; *p = x->next; - spin_lock(&x->lock); - del_timer(&x->rs_timer); - spin_unlock(&x->lock); kfree(x); t->prl_count--; goto out; @@ -417,9 +362,6 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) while (t->prl) { x = t->prl; t->prl = t->prl->next; - spin_lock(&x->lock); - del_timer(&x->rs_timer); - spin_unlock(&x->lock); kfree(x); t->prl_count--; } -- cgit v1.2.3 From 2f72291d3d0e440f9343c7b97dc233c1a122165a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 28 Sep 2009 12:26:28 -0700 Subject: ax25: Add missing dev_put in ax25_setsockopt ax25_setsockopt SO_BINDTODEVICE is missing a dev_put call in case of success. Re-order code to fix this bug. While at it also reformat two lines of code to comply with the Linux coding style. Initial patch by Jarek Poplawski . Reported-by: Bernard Pidoux F6BVP Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- net/ax25/af_ax25.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index fbcac76fdc0d..4102de1022ee 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -641,15 +641,10 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, case SO_BINDTODEVICE: if (optlen > IFNAMSIZ) - optlen=IFNAMSIZ; - if (copy_from_user(devname, optval, optlen)) { - res = -EFAULT; - break; - } + optlen = IFNAMSIZ; - dev = dev_get_by_name(&init_net, devname); - if (dev == NULL) { - res = -ENODEV; + if (copy_from_user(devname, optval, optlen)) { + res = -EFAULT; break; } @@ -657,12 +652,18 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, (sock->state != SS_UNCONNECTED || sk->sk_state == TCP_LISTEN)) { res = -EADDRNOTAVAIL; - dev_put(dev); + break; + } + + dev = dev_get_by_name(&init_net, devname); + if (!dev) { + res = -ENODEV; break; } ax25->ax25_dev = ax25_dev_ax25dev(dev); ax25_fillin_cb(ax25, ax25->ax25_dev); + dev_put(dev); break; default: -- cgit v1.2.3 From 30df94f800368a016d09ee672c9fcc20751d0260 Mon Sep 17 00:00:00 2001 From: Jeff Hansen Date: Mon, 28 Sep 2009 12:54:25 -0700 Subject: bridge: Fix double-free in br_add_if. There is a potential double-kfree in net/bridge/br_if.c. If br_fdb_insert fails, then the kobject is put back (which calls kfree due to the kobject release), and then kfree is called again on the net_bridge_port. This patch fixes the crash. Thanks to Stephen Hemminger for the one-line fix. Signed-off-by: Jeff Hansen Signed-off-by: David S. Miller --- net/bridge/br_if.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 142ebac14176..b1b3b0fbf41c 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -432,6 +432,7 @@ err2: br_fdb_delete_by_port(br, p, 1); err1: kobject_put(&p->kobj); + p = NULL; /* kobject_put frees */ err0: dev_set_promiscuity(dev, -1); put_back: -- cgit v1.2.3 From 47379052b5c87707bc6e20a2a4f6ac156fb8357c Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Mon, 28 Sep 2009 12:57:44 -0700 Subject: net: Add explicit bound checks in net/socket.c The sys_socketcall() function has a very clever system for the copy size of its arguments. Unfortunately, gcc cannot deal with this in terms of proving that the copy_from_user() is then always in bounds. This is the last (well 9th of this series, but last in the kernel) such case around. With this patch, we can turn on code to make having the boundary provably right for the whole kernel, and detect introduction of new security accidents of this type early on. Signed-off-by: Arjan van de Ven Signed-off-by: David S. Miller --- net/socket.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/socket.c b/net/socket.c index 49917a1cac7d..41e8847508aa 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2098,12 +2098,17 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) unsigned long a[6]; unsigned long a0, a1; int err; + unsigned int len; if (call < 1 || call > SYS_ACCEPT4) return -EINVAL; + len = nargs[call]; + if (len > sizeof(a)) + return -EINVAL; + /* copy_from_user should be SMP safe. */ - if (copy_from_user(a, args, nargs[call])) + if (copy_from_user(a, args, len)) return -EFAULT; audit_socketcall(nargs[call] / sizeof(unsigned long), a); -- cgit v1.2.3 From 33de4f9d787e01646f715ac10c2699fb98fd479e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 17 Sep 2009 08:35:54 -0700 Subject: cfg80211: wext: don't display BSSID unless associated Currently, cfg80211's SIOCGIWAP implementation returns the BSSID that the user set, even if the connection has since been dropped due to other changes. It only should return the current BSSID when actually connected. Also do a small code cleanup. Reported-by: Thomas H. Guenther Signed-off-by: Johannes Berg Tested-by: Thomas H. Guenther Signed-off-by: John W. Linville --- net/wireless/wext-sme.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'net') diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index bf725275eb8d..53c6ba98dc25 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -229,8 +229,7 @@ int cfg80211_mgd_wext_giwessid(struct net_device *dev, data->flags = 1; data->length = wdev->wext.connect.ssid_len; memcpy(ssid, wdev->wext.connect.ssid, data->length); - } else - data->flags = 0; + } wdev_unlock(wdev); return 0; @@ -306,8 +305,6 @@ int cfg80211_mgd_wext_giwap(struct net_device *dev, wdev_lock(wdev); if (wdev->current_bss) memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); - else if (wdev->wext.connect.bssid) - memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN); else memset(ap_addr->sa_data, 0, ETH_ALEN); wdev_unlock(wdev); -- cgit v1.2.3 From 4be3bd8ccc195297870b9ffca4ef18bcbc2f1822 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 24 Sep 2009 09:00:57 +0200 Subject: cfg80211: don't set privacy w/o key When wpa_supplicant is used to connect to open networks, it causes the wdev->wext.keys to point to key memory, but that key memory is all empty. Only use privacy when there is a default key to be used. Signed-off-by: Johannes Berg Tested-by: Luis R. Rodriguez Tested-by: Kalle Valo Signed-off-by: John W. Linville --- net/wireless/wext-sme.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c index 53c6ba98dc25..5615a8802536 100644 --- a/net/wireless/wext-sme.c +++ b/net/wireless/wext-sme.c @@ -30,7 +30,8 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, if (wdev->wext.keys) { wdev->wext.keys->def = wdev->wext.default_key; wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key; - wdev->wext.connect.privacy = true; + if (wdev->wext.default_key != -1) + wdev->wext.connect.privacy = true; } if (!wdev->wext.connect.ssid_len) -- cgit v1.2.3 From 8bb894859e9495a94f94af3ee4711c89cdf24a95 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 26 Sep 2009 14:42:53 +0200 Subject: cfg80211: always get BSS Multiple problems were reported due to interaction between wpa_supplicant and the wext compat code in cfg80211, which appear to be due to it not getting any bss pointer here when wpa_supplicant sets all parameters -- do that now. We should still get the bss after doing an extra scan, but that appears to increase the time we need for connecting enough to sometimes cause timeouts. Signed-off-by: Johannes Berg Tested-by: Hin-Tak Leung , Signed-off-by: John W. Linville --- net/wireless/sme.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 7fae7eee65de..93c3ed329204 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -762,9 +762,8 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev, wdev->conn->params.ssid = wdev->ssid; wdev->conn->params.ssid_len = connect->ssid_len; - /* don't care about result -- but fill bssid & channel */ - if (!wdev->conn->params.bssid || !wdev->conn->params.channel) - bss = cfg80211_get_conn_bss(wdev); + /* see if we have the bss already */ + bss = cfg80211_get_conn_bss(wdev); wdev->sme_state = CFG80211_SME_CONNECTING; wdev->connect_keys = connkeys; -- cgit v1.2.3 From 0ff716136ab73d2fc1edc0664e38169e7a76bb9a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 26 Sep 2009 14:45:41 +0200 Subject: mac80211: improve/fix mlme messages It's useful to know the MAC address when being disassociated; fix a typo (missing colon) and move some messages so we get them only when they are actually taking effect. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 97a278a2f48e..8d26e9bf8964 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1388,8 +1388,8 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", - sdata->dev->name, reason_code); + printk(KERN_DEBUG "%s: disassociated from %pM (Reason: %u)\n", + sdata->dev->name, mgmt->sa, reason_code); ieee80211_set_disassoc(sdata, false); return RX_MGMT_CFG80211_DISASSOC; @@ -1675,7 +1675,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, /* direct probe may be part of the association flow */ if (wk && wk->state == IEEE80211_MGD_STATE_PROBE) { - printk(KERN_DEBUG "%s direct probe responded\n", + printk(KERN_DEBUG "%s: direct probe responded\n", sdata->dev->name); wk->tries = 0; wk->state = IEEE80211_MGD_STATE_AUTH; @@ -2502,9 +2502,6 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgd_work *wk; const u8 *bssid = NULL; - printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n", - sdata->dev->name, req->reason_code); - mutex_lock(&ifmgd->mtx); if (ifmgd->associated && &ifmgd->associated->cbss == req->bss) { @@ -2532,6 +2529,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, mutex_unlock(&ifmgd->mtx); + printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n", + sdata->dev->name, bssid, req->reason_code); + ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH, req->reason_code, cookie); @@ -2545,9 +2545,6 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; - printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n", - sdata->dev->name, req->reason_code); - mutex_lock(&ifmgd->mtx); /* @@ -2561,6 +2558,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return -ENOLINK; } + printk(KERN_DEBUG "%s: disassociating from %pM by local choice (reason=%d)\n", + sdata->dev->name, req->bss->bssid, req->reason_code); + ieee80211_set_disassoc(sdata, false); mutex_unlock(&ifmgd->mtx); -- cgit v1.2.3 From 8503bd8c7dc6f82ec2de9d05e0a476e6ca5adc8b Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sat, 26 Sep 2009 20:51:14 +0200 Subject: wext: Add bound checks for copy_from_user The wireless extensions have a copy_from_user to a local stack array "essid", but both me and gcc have failed to find where the bounds for this copy are located in the code. This patch adds some basic sanity checks for the copy length to make sure that we don't overflow the stack buffer. Signed-off-by: Arjan van de Ven Cc: linux-wireless@vger.kernel.org Signed-off-by: John W. Linville --- net/wireless/wext.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 5b4a0cee4418..ac4ac26b53ce 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -773,10 +773,13 @@ static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, essid_compat = 1; else if (IW_IS_SET(cmd) && (iwp->length != 0)) { char essid[IW_ESSID_MAX_SIZE + 1]; + unsigned int len; + len = iwp->length * descr->token_size; - err = copy_from_user(essid, iwp->pointer, - iwp->length * - descr->token_size); + if (len > IW_ESSID_MAX_SIZE) + return -EFAULT; + + err = copy_from_user(essid, iwp->pointer, len); if (err) return -EFAULT; -- cgit v1.2.3 From 8f1546cadf7ac5e9a40d54089a1c7302264ec49b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 28 Sep 2009 15:26:43 +0200 Subject: wext: add back wireless/ dir in sysfs for cfg80211 interfaces The move away from having drivers assign wireless handlers, in favour of making cfg80211 assign them, broke the sysfs registration (the wireless/ dir went missing) because the handlers are now assigned only after registration, which is too late. Fix this by special-casing cfg80211-based devices, all of which are required to have an ieee80211_ptr, in the sysfs code, and also using get_wireless_stats() to have the same values reported as in procfs. Signed-off-by: Johannes Berg Reported-by: Hugh Dickins Tested-by: Hugh Dickins Signed-off-by: John W. Linville --- net/core/net-sysfs.c | 12 +++++------- net/wireless/wext.c | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 7d4c57523b09..821d30918cfc 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include "net-sysfs.h" @@ -363,15 +363,13 @@ static ssize_t wireless_show(struct device *d, char *buf, char *)) { struct net_device *dev = to_net_dev(d); - const struct iw_statistics *iw = NULL; + const struct iw_statistics *iw; ssize_t ret = -EINVAL; read_lock(&dev_base_lock); if (dev_isalive(dev)) { - if (dev->wireless_handlers && - dev->wireless_handlers->get_wireless_stats) - iw = dev->wireless_handlers->get_wireless_stats(dev); - if (iw != NULL) + iw = get_wireless_stats(dev); + if (iw) ret = (*format)(iw, buf); } read_unlock(&dev_base_lock); @@ -505,7 +503,7 @@ int netdev_register_kobject(struct net_device *net) *groups++ = &netstat_group; #ifdef CONFIG_WIRELESS_EXT_SYSFS - if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats) + if (net->wireless_handlers || net->ieee80211_ptr) *groups++ = &wireless_group; #endif #endif /* CONFIG_SYSFS */ diff --git a/net/wireless/wext.c b/net/wireless/wext.c index ac4ac26b53ce..60fe57761ca9 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -470,7 +470,7 @@ static iw_handler get_handler(struct net_device *dev, unsigned int cmd) /* * Get statistics out of the driver */ -static struct iw_statistics *get_wireless_stats(struct net_device *dev) +struct iw_statistics *get_wireless_stats(struct net_device *dev) { /* New location */ if ((dev->wireless_handlers != NULL) && -- cgit v1.2.3 From 1f08e84ff642294e42d138442a388989ffb20865 Mon Sep 17 00:00:00 2001 From: Igor Perminov Date: Tue, 22 Sep 2009 00:25:44 +0400 Subject: mac80211: Fix [re]association power saving issue on AP side Consider the following step-by step: 1. A STA authenticates and associates with the AP and exchanges traffic. 2. The STA reports to the AP that it is going to PS state. 3. Some time later the STA device goes to the stand-by mode (not only its wi-fi card, but the device itself) and drops the association state without sending a disassociation frame. 4. The STA device wakes up and begins authentication with an Auth frame as it hasn't been authenticated/associated previously. At the step 4 the AP "remembers" the STA and considers it is still in the PS state, so the AP buffers frames, which it has to send to the STA. But the STA isn't actually in the PS state and so it neither checks TIM bits nor reports to the AP that it isn't power saving. Because of that authentication/[re]association fails. To fix authentication/[re]association stage of this issue, Auth, Assoc Resp and Reassoc Resp frames are transmitted disregarding of STA's power saving state. N.B. This patch doesn't fix further data frame exchange after authentication/[re]association. A patch in hostapd is required to fix that. Signed-off-by: Igor Perminov Signed-off-by: John W. Linville --- net/mac80211/tx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 5143d203256b..fd4028296613 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -367,7 +367,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; u32 staflags; - if (unlikely(!sta || ieee80211_is_probe_resp(hdr->frame_control))) + if (unlikely(!sta || ieee80211_is_probe_resp(hdr->frame_control) + || ieee80211_is_auth(hdr->frame_control) + || ieee80211_is_assoc_resp(hdr->frame_control) + || ieee80211_is_reassoc_resp(hdr->frame_control))) return TX_CONTINUE; staflags = get_sta_flags(sta); -- cgit v1.2.3 From b7058842c940ad2c08dd829b21e5c92ebe3b8758 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 30 Sep 2009 16:12:20 -0700 Subject: net: Make setsockopt() optlen be unsigned. This provides safety against negative optlen at the type level instead of depending upon (sometimes non-trivial) checks against this sprinkled all over the the place, in each and every implementation. Based upon work done by Arjan van de Ven and feedback from Linus Torvalds. Signed-off-by: David S. Miller --- net/atm/common.c | 2 +- net/atm/common.h | 2 +- net/atm/pvc.c | 2 +- net/atm/svc.c | 2 +- net/ax25/af_ax25.c | 2 +- net/bluetooth/hci_sock.c | 2 +- net/bluetooth/l2cap.c | 4 +-- net/bluetooth/rfcomm/sock.c | 4 +-- net/bluetooth/sco.c | 2 +- net/can/raw.c | 2 +- net/compat.c | 12 ++++---- net/core/sock.c | 8 +++--- net/dccp/dccp.h | 4 +-- net/dccp/proto.c | 10 +++---- net/decnet/af_decnet.c | 6 ++-- net/ieee802154/dgram.c | 2 +- net/ieee802154/raw.c | 2 +- net/ipv4/inet_connection_sock.c | 2 +- net/ipv4/ip_sockglue.c | 6 ++-- net/ipv4/ipmr.c | 2 +- net/ipv4/raw.c | 6 ++-- net/ipv4/tcp.c | 6 ++-- net/ipv4/udp.c | 6 ++-- net/ipv4/udp_impl.h | 4 +-- net/ipv6/ip6mr.c | 2 +- net/ipv6/ipv6_sockglue.c | 6 ++-- net/ipv6/raw.c | 6 ++-- net/ipv6/udp.c | 4 +-- net/ipv6/udp_impl.h | 4 +-- net/ipx/af_ipx.c | 2 +- net/irda/af_irda.c | 2 +- net/iucv/af_iucv.c | 2 +- net/llc/af_llc.c | 2 +- net/netfilter/nf_sockopt.c | 4 +-- net/netlink/af_netlink.c | 2 +- net/netrom/af_netrom.c | 2 +- net/packet/af_packet.c | 2 +- net/phonet/pep.c | 2 +- net/rds/af_rds.c | 2 +- net/rose/af_rose.c | 2 +- net/rxrpc/af_rxrpc.c | 2 +- net/sctp/socket.c | 62 ++++++++++++++++++++++------------------- net/socket.c | 2 +- net/tipc/socket.c | 2 +- net/x25/af_x25.c | 2 +- 45 files changed, 110 insertions(+), 106 deletions(-) (limited to 'net') diff --git a/net/atm/common.c b/net/atm/common.c index 8c4d843eb17f..950bd16d2383 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -679,7 +679,7 @@ static int check_qos(const struct atm_qos *qos) } int vcc_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct atm_vcc *vcc; unsigned long value; diff --git a/net/atm/common.h b/net/atm/common.h index 92e2981f479f..f48a76b6cdf4 100644 --- a/net/atm/common.h +++ b/net/atm/common.h @@ -21,7 +21,7 @@ unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait); int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); int vcc_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); int vcc_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen); diff --git a/net/atm/pvc.c b/net/atm/pvc.c index e1d22d9430dd..d4c024504f99 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -59,7 +59,7 @@ static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr, } static int pvc_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int error; diff --git a/net/atm/svc.c b/net/atm/svc.c index 7b831b526d0b..f90d143c4b25 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -446,7 +446,7 @@ int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos) static int svc_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct atm_vcc *vcc = ATM_SD(sock); diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 4102de1022ee..cd1c3dc0fe01 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -534,7 +534,7 @@ ax25_cb *ax25_create_cb(void) */ static int ax25_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; ax25_cb *ax25; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 4f9621f759a0..75302a986067 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -466,7 +466,7 @@ drop: goto done; } -static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int len) +static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int len) { struct hci_ufilter uf = { .opcode = 0 }; struct sock *sk = sock->sk; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index b03012564647..555d9da1869b 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1698,7 +1698,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms return bt_sock_recvmsg(iocb, sock, msg, len, flags); } -static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen) +static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct l2cap_options opts; @@ -1755,7 +1755,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us return err; } -static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) +static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct bt_security sec; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 0b85e8116859..8a20aaf1f231 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -730,7 +730,7 @@ out: return copied ? : err; } -static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen) +static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int err = 0; @@ -766,7 +766,7 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u return err; } -static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) +static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct bt_security sec; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 13c27f17192c..77f4153bdb5e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -644,7 +644,7 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock, return err; } -static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) +static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int err = 0; diff --git a/net/can/raw.c b/net/can/raw.c index db3152df7d2b..b5e897922d32 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -411,7 +411,7 @@ static int raw_getname(struct socket *sock, struct sockaddr *uaddr, } static int raw_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct raw_sock *ro = raw_sk(sk); diff --git a/net/compat.c b/net/compat.c index 12728b17a226..a407c3addbae 100644 --- a/net/compat.c +++ b/net/compat.c @@ -331,7 +331,7 @@ struct compat_sock_fprog { }; static int do_set_attach_filter(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct compat_sock_fprog __user *fprog32 = (struct compat_sock_fprog __user *)optval; struct sock_fprog __user *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog)); @@ -351,7 +351,7 @@ static int do_set_attach_filter(struct socket *sock, int level, int optname, } static int do_set_sock_timeout(struct socket *sock, int level, - int optname, char __user *optval, int optlen) + int optname, char __user *optval, unsigned int optlen) { struct compat_timeval __user *up = (struct compat_timeval __user *) optval; struct timeval ktime; @@ -373,7 +373,7 @@ static int do_set_sock_timeout(struct socket *sock, int level, } static int compat_sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (optname == SO_ATTACH_FILTER) return do_set_attach_filter(sock, level, optname, @@ -385,7 +385,7 @@ static int compat_sock_setsockopt(struct socket *sock, int level, int optname, } asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int err; struct socket *sock; @@ -558,8 +558,8 @@ struct compat_group_filter { int compat_mc_setsockopt(struct sock *sock, int level, int optname, - char __user *optval, int optlen, - int (*setsockopt)(struct sock *,int,int,char __user *,int)) + char __user *optval, unsigned int optlen, + int (*setsockopt)(struct sock *,int,int,char __user *,unsigned int)) { char __user *koptval = optval; int koptlen = optlen; diff --git a/net/core/sock.c b/net/core/sock.c index 524712a7b154..77fbfed332e8 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -446,7 +446,7 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) */ int sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int val; @@ -1697,7 +1697,7 @@ int sock_no_shutdown(struct socket *sock, int how) EXPORT_SYMBOL(sock_no_shutdown); int sock_no_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { return -EOPNOTSUPP; } @@ -2018,7 +2018,7 @@ EXPORT_SYMBOL(sock_common_recvmsg); * Set socket options on an inet socket. */ int sock_common_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; @@ -2028,7 +2028,7 @@ EXPORT_SYMBOL(sock_common_setsockopt); #ifdef CONFIG_COMPAT int compat_sock_common_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index d6bc47363b1c..5ef32c2f0d6a 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -290,14 +290,14 @@ extern int dccp_disconnect(struct sock *sk, int flags); extern int dccp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); extern int dccp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); #ifdef CONFIG_COMPAT extern int compat_dccp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); extern int compat_dccp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); #endif extern int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg); extern int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, diff --git a/net/dccp/proto.c b/net/dccp/proto.c index bc4467082a00..a156319fd0ac 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -393,7 +393,7 @@ out: EXPORT_SYMBOL_GPL(dccp_ioctl); static int dccp_setsockopt_service(struct sock *sk, const __be32 service, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct dccp_sock *dp = dccp_sk(sk); struct dccp_service_list *sl = NULL; @@ -464,7 +464,7 @@ static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx) } static int dccp_setsockopt_ccid(struct sock *sk, int type, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { u8 *val; int rc = 0; @@ -494,7 +494,7 @@ static int dccp_setsockopt_ccid(struct sock *sk, int type, } static int do_dccp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct dccp_sock *dp = dccp_sk(sk); int val, err = 0; @@ -546,7 +546,7 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, } int dccp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level != SOL_DCCP) return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level, @@ -559,7 +559,7 @@ EXPORT_SYMBOL_GPL(dccp_setsockopt); #ifdef CONFIG_COMPAT int compat_dccp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level != SOL_DCCP) return inet_csk_compat_setsockopt(sk, level, optname, diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 77d40289653c..7a58c87baf17 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -157,7 +157,7 @@ static struct hlist_head dn_sk_hash[DN_SK_HASH_SIZE]; static struct hlist_head dn_wild_sk; static atomic_t decnet_memory_allocated; -static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen, int flags); +static int __dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen, int flags); static int __dn_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen, int flags); static struct hlist_head *dn_find_list(struct sock *sk) @@ -1325,7 +1325,7 @@ out: return err; } -static int dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) +static int dn_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int err; @@ -1337,7 +1337,7 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use return err; } -static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user *optval, int optlen, int flags) +static int __dn_setsockopt(struct socket *sock, int level,int optname, char __user *optval, unsigned int optlen, int flags) { struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index 51593a48f2dd..a413b1bf4465 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c @@ -414,7 +414,7 @@ static int dgram_getsockopt(struct sock *sk, int level, int optname, } static int dgram_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct dgram_sock *ro = dgram_sk(sk); int val; diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c index 13198859982e..30e74eee07d6 100644 --- a/net/ieee802154/raw.c +++ b/net/ieee802154/raw.c @@ -244,7 +244,7 @@ static int raw_getsockopt(struct sock *sk, int level, int optname, } static int raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { return -EOPNOTSUPP; } diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 22cd19ee44e5..4351ca2cf0b8 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -714,7 +714,7 @@ int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname, EXPORT_SYMBOL_GPL(inet_csk_compat_getsockopt); int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { const struct inet_connection_sock *icsk = inet_csk(sk); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 5a0693576e82..0c0b6e363a20 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -440,7 +440,7 @@ out: */ static int do_ip_setsockopt(struct sock *sk, int level, - int optname, char __user *optval, int optlen) + int optname, char __user *optval, unsigned int optlen) { struct inet_sock *inet = inet_sk(sk); int val = 0, err; @@ -950,7 +950,7 @@ e_inval: } int ip_setsockopt(struct sock *sk, int level, - int optname, char __user *optval, int optlen) + int optname, char __user *optval, unsigned int optlen) { int err; @@ -975,7 +975,7 @@ EXPORT_SYMBOL(ip_setsockopt); #ifdef CONFIG_COMPAT int compat_ip_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int err; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index c43ec2d51ce2..630a56df7b47 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -931,7 +931,7 @@ static void mrtsock_destruct(struct sock *sk) * MOSPF/PIM router set up we can clean this up. */ -int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int optlen) +int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) { int ret; struct vifctl vif; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index ebb1e5848bc6..757c9171e7c2 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -741,7 +741,7 @@ out: return ret; } static int do_raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (optname == ICMP_FILTER) { if (inet_sk(sk)->num != IPPROTO_ICMP) @@ -753,7 +753,7 @@ static int do_raw_setsockopt(struct sock *sk, int level, int optname, } static int raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level != SOL_RAW) return ip_setsockopt(sk, level, optname, optval, optlen); @@ -762,7 +762,7 @@ static int raw_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_COMPAT static int compat_raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level != SOL_RAW) return compat_ip_setsockopt(sk, level, optname, optval, optlen); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 21387ebabf00..5a15e7629d8e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2032,7 +2032,7 @@ int tcp_disconnect(struct sock *sk, int flags) * Socket option code for TCP. */ static int do_tcp_setsockopt(struct sock *sk, int level, - int optname, char __user *optval, int optlen) + int optname, char __user *optval, unsigned int optlen) { struct tcp_sock *tp = tcp_sk(sk); struct inet_connection_sock *icsk = inet_csk(sk); @@ -2220,7 +2220,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, } int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, - int optlen) + unsigned int optlen) { struct inet_connection_sock *icsk = inet_csk(sk); @@ -2232,7 +2232,7 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, #ifdef CONFIG_COMPAT int compat_tcp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level != SOL_TCP) return inet_csk_compat_setsockopt(sk, level, optname, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ebaaa7f973d7..3326aff65906 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1359,7 +1359,7 @@ void udp_destroy_sock(struct sock *sk) * Socket option code for UDP */ int udp_lib_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen, + char __user *optval, unsigned int optlen, int (*push_pending_frames)(struct sock *)) { struct udp_sock *up = udp_sk(sk); @@ -1441,7 +1441,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, EXPORT_SYMBOL(udp_lib_setsockopt); int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) return udp_lib_setsockopt(sk, level, optname, optval, optlen, @@ -1451,7 +1451,7 @@ int udp_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_COMPAT int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) return udp_lib_setsockopt(sk, level, optname, optval, optlen, diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h index 9f4a6165f722..aaad650d47d9 100644 --- a/net/ipv4/udp_impl.h +++ b/net/ipv4/udp_impl.h @@ -11,13 +11,13 @@ extern void __udp4_lib_err(struct sk_buff *, u32, struct udp_table *); extern int udp_v4_get_port(struct sock *sk, unsigned short snum); extern int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); extern int udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); #ifdef CONFIG_COMPAT extern int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); extern int compat_udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); #endif diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 090675e269ee..716153941fc4 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1281,7 +1281,7 @@ int ip6mr_sk_done(struct sock *sk) * MOSPF/PIM router set up we can clean this up. */ -int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int optlen) +int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen) { int ret; struct mif6ctl vif; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index f5e0682b402d..14f54eb5a7fc 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -123,7 +123,7 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk, } static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct ipv6_pinfo *np = inet6_sk(sk); struct net *net = sock_net(sk); @@ -773,7 +773,7 @@ e_inval: } int ipv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int err; @@ -801,7 +801,7 @@ EXPORT_SYMBOL(ipv6_setsockopt); #ifdef CONFIG_COMPAT int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int err; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 7d675b8d82d3..4f24570b0869 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -957,7 +957,7 @@ static int rawv6_geticmpfilter(struct sock *sk, int level, int optname, static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct raw6_sock *rp = raw6_sk(sk); int val; @@ -1000,7 +1000,7 @@ static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, } static int rawv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { switch(level) { case SOL_RAW: @@ -1024,7 +1024,7 @@ static int rawv6_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_COMPAT static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { switch (level) { case SOL_RAW: diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index b265b7047d3e..3a60f12b34ed 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1044,7 +1044,7 @@ void udpv6_destroy_sock(struct sock *sk) * Socket option code for UDP */ int udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) return udp_lib_setsockopt(sk, level, optname, optval, optlen, @@ -1054,7 +1054,7 @@ int udpv6_setsockopt(struct sock *sk, int level, int optname, #ifdef CONFIG_COMPAT int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { if (level == SOL_UDP || level == SOL_UDPLITE) return udp_lib_setsockopt(sk, level, optname, optval, optlen, diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 6bb303471e20..d7571046bfc4 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h @@ -16,10 +16,10 @@ extern int udp_v6_get_port(struct sock *sk, unsigned short snum); extern int udpv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); extern int udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); #ifdef CONFIG_COMPAT extern int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen); + char __user *optval, unsigned int optlen); extern int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); #endif diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index f1118d92a191..66c7a20011f3 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -1292,7 +1292,7 @@ const char *ipx_device_name(struct ipx_interface *intrfc) * socket object. */ static int ipx_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; int opt; diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 50b43c57d5d8..dd35641835f4 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -1826,7 +1826,7 @@ static int irda_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned lon * */ static int irda_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct irda_sock *self = irda_sk(sk); diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index d985d163dcfc..bada1b9c670b 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -1387,7 +1387,7 @@ static int iucv_sock_release(struct socket *sock) /* getsockopt and setsockopt */ static int iucv_sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct iucv_sock *iucv = iucv_sk(sk); diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index c45eee1c0e8d..7aa4fd170104 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -973,7 +973,7 @@ static int llc_ui_ioctl(struct socket *sock, unsigned int cmd, * Set various connection specific parameters. */ static int llc_ui_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct llc_sock *llc = llc_sk(sk); diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c index 8ab829f86574..f042ae521557 100644 --- a/net/netfilter/nf_sockopt.c +++ b/net/netfilter/nf_sockopt.c @@ -113,7 +113,7 @@ static int nf_sockopt(struct sock *sk, u_int8_t pf, int val, } int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt, - int len) + unsigned int len) { return nf_sockopt(sk, pf, val, opt, &len, 0); } @@ -154,7 +154,7 @@ static int compat_nf_sockopt(struct sock *sk, u_int8_t pf, int val, } int compat_nf_setsockopt(struct sock *sk, u_int8_t pf, - int val, char __user *opt, int len) + int val, char __user *opt, unsigned int len) { return compat_nf_sockopt(sk, pf, val, opt, &len, 0); } diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index dd85320907cb..19e98007691c 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1150,7 +1150,7 @@ static void netlink_update_socket_mc(struct netlink_sock *nlk, } static int netlink_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct netlink_sock *nlk = nlk_sk(sk); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index ce1a34b99c23..7a834952f67f 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -301,7 +301,7 @@ void nr_destroy_socket(struct sock *sk) */ static int nr_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct nr_sock *nr = nr_sk(sk); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d3d52c66cdc2..1238949e66a9 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1701,7 +1701,7 @@ static void packet_flush_mclist(struct sock *sk) } static int -packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen) +packet_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct packet_sock *po = pkt_sk(sk); diff --git a/net/phonet/pep.c b/net/phonet/pep.c index b8252d289cd7..5f32d217535b 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -742,7 +742,7 @@ static int pep_init(struct sock *sk) } static int pep_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct pep_sock *pn = pep_sk(sk); int val = 0, err = 0; diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index 6b58aeff4c7a..98e05382fd3c 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -248,7 +248,7 @@ static int rds_cong_monitor(struct rds_sock *rs, char __user *optval, } static int rds_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct rds_sock *rs = rds_sk_to_rs(sock->sk); int ret; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 1e166c9685aa..502cce76621d 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -370,7 +370,7 @@ void rose_destroy_socket(struct sock *sk) */ static int rose_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct rose_sock *rose = rose_sk(sk); diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index bfe493ebf27c..a86afceaa94f 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -507,7 +507,7 @@ out: * set RxRPC socket options */ static int rxrpc_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct rxrpc_sock *rx = rxrpc_sk(sock->sk); unsigned min_sec_level; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 89af37a6c871..c8d05758661d 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2027,7 +2027,8 @@ out: * instead a error will be indicated to the user. */ static int sctp_setsockopt_disable_fragments(struct sock *sk, - char __user *optval, int optlen) + char __user *optval, + unsigned int optlen) { int val; @@ -2043,7 +2044,7 @@ static int sctp_setsockopt_disable_fragments(struct sock *sk, } static int sctp_setsockopt_events(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { if (optlen > sizeof(struct sctp_event_subscribe)) return -EINVAL; @@ -2064,7 +2065,7 @@ static int sctp_setsockopt_events(struct sock *sk, char __user *optval, * association is closed. */ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_sock *sp = sctp_sk(sk); @@ -2318,7 +2319,8 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, } static int sctp_setsockopt_peer_addr_params(struct sock *sk, - char __user *optval, int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_paddrparams params; struct sctp_transport *trans = NULL; @@ -2430,7 +2432,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, */ static int sctp_setsockopt_delayed_ack(struct sock *sk, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { struct sctp_sack_info params; struct sctp_transport *trans = NULL; @@ -2546,7 +2548,7 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk, * by the change). With TCP-style sockets, this option is inherited by * sockets derived from a listener socket. */ -static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int optlen) +static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, unsigned int optlen) { struct sctp_initmsg sinit; struct sctp_sock *sp = sctp_sk(sk); @@ -2583,7 +2585,8 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char __user *optval, int opt * to this call if the caller is using the UDP model. */ static int sctp_setsockopt_default_send_param(struct sock *sk, - char __user *optval, int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_sndrcvinfo info; struct sctp_association *asoc; @@ -2622,7 +2625,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, * association peer's addresses. */ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_prim prim; struct sctp_transport *trans; @@ -2651,7 +2654,7 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, * integer boolean flag. */ static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { int val; @@ -2676,7 +2679,8 @@ static int sctp_setsockopt_nodelay(struct sock *sk, char __user *optval, * be changed. * */ -static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int optlen) { +static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, unsigned int optlen) +{ struct sctp_rtoinfo rtoinfo; struct sctp_association *asoc; @@ -2728,7 +2732,7 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int opt * See [SCTP] for more information. * */ -static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int optlen) +static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, unsigned int optlen) { struct sctp_assocparams assocparams; @@ -2800,7 +2804,7 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int o * addresses and a user will receive both PF_INET6 and PF_INET type * addresses on the socket. */ -static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int optlen) +static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsigned int optlen) { int val; struct sctp_sock *sp = sctp_sk(sk); @@ -2844,7 +2848,7 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int op * changed (effecting future associations only). * assoc_value: This parameter specifies the maximum size in bytes. */ -static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen) +static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen) { struct sctp_assoc_value params; struct sctp_association *asoc; @@ -2899,7 +2903,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optl * set primary request: */ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_sock *sp; struct sctp_endpoint *ep; @@ -2950,7 +2954,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva } static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_setadaptation adaptation; @@ -2979,7 +2983,7 @@ static int sctp_setsockopt_adaptation_layer(struct sock *sk, char __user *optval * saved with outbound messages. */ static int sctp_setsockopt_context(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_assoc_value params; struct sctp_sock *sp; @@ -3030,7 +3034,7 @@ static int sctp_setsockopt_context(struct sock *sk, char __user *optval, */ static int sctp_setsockopt_fragment_interleave(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { int val; @@ -3063,7 +3067,7 @@ static int sctp_setsockopt_fragment_interleave(struct sock *sk, */ static int sctp_setsockopt_partial_delivery_point(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { u32 val; @@ -3096,7 +3100,7 @@ static int sctp_setsockopt_partial_delivery_point(struct sock *sk, */ static int sctp_setsockopt_maxburst(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_assoc_value params; struct sctp_sock *sp; @@ -3140,8 +3144,8 @@ static int sctp_setsockopt_maxburst(struct sock *sk, * will only effect future associations on the socket. */ static int sctp_setsockopt_auth_chunk(struct sock *sk, - char __user *optval, - int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_authchunk val; @@ -3172,8 +3176,8 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk, * endpoint requires the peer to use. */ static int sctp_setsockopt_hmac_ident(struct sock *sk, - char __user *optval, - int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_hmacalgo *hmacs; u32 idents; @@ -3215,7 +3219,7 @@ out: */ static int sctp_setsockopt_auth_key(struct sock *sk, char __user *optval, - int optlen) + unsigned int optlen) { struct sctp_authkey *authkey; struct sctp_association *asoc; @@ -3260,8 +3264,8 @@ out: * the association shared key. */ static int sctp_setsockopt_active_key(struct sock *sk, - char __user *optval, - int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_authkeyid val; struct sctp_association *asoc; @@ -3288,8 +3292,8 @@ static int sctp_setsockopt_active_key(struct sock *sk, * This set option will delete a shared secret key from use. */ static int sctp_setsockopt_del_key(struct sock *sk, - char __user *optval, - int optlen) + char __user *optval, + unsigned int optlen) { struct sctp_authkeyid val; struct sctp_association *asoc; @@ -3332,7 +3336,7 @@ static int sctp_setsockopt_del_key(struct sock *sk, * optlen - the size of the buffer. */ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int retval = 0; diff --git a/net/socket.c b/net/socket.c index 41e8847508aa..75655365b5fd 100644 --- a/net/socket.c +++ b/net/socket.c @@ -2391,7 +2391,7 @@ int kernel_getsockopt(struct socket *sock, int level, int optname, } int kernel_setsockopt(struct socket *sock, int level, int optname, - char *optval, int optlen) + char *optval, unsigned int optlen) { mm_segment_t oldfs = get_fs(); int err; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e8254e809b79..e6d9abf7440e 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1658,7 +1658,7 @@ restart: */ static int setsockopt(struct socket *sock, - int lvl, int opt, char __user *ov, int ol) + int lvl, int opt, char __user *ov, unsigned int ol) { struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 5e6c072c64d3..7fa9c7ad3d3b 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -409,7 +409,7 @@ static void x25_destroy_socket(struct sock *sk) */ static int x25_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, int optlen) + char __user *optval, unsigned int optlen) { int opt; struct sock *sk = sock->sk; -- cgit v1.2.3 From d99927f4d93f36553699573b279e0ff98ad7dea6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 24 Sep 2009 10:49:24 +0000 Subject: net: Fix sock_wfree() race Commit 2b85a34e911bf483c27cfdd124aeb1605145dc80 (net: No more expensive sock_hold()/sock_put() on each tx) opens a window in sock_wfree() where another cpu might free the socket we are working on. A fix is to call sk->sk_write_space(sk) while still holding a reference on sk. Reported-by: Jike Song Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/sock.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/core/sock.c b/net/core/sock.c index 77fbfed332e8..7626b6aacd68 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1228,17 +1228,22 @@ void __init sk_init(void) void sock_wfree(struct sk_buff *skb) { struct sock *sk = skb->sk; - int res; + unsigned int len = skb->truesize; - /* In case it might be waiting for more memory. */ - res = atomic_sub_return(skb->truesize, &sk->sk_wmem_alloc); - if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) + if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) { + /* + * Keep a reference on sk_wmem_alloc, this will be released + * after sk_write_space() call + */ + atomic_sub(len - 1, &sk->sk_wmem_alloc); sk->sk_write_space(sk); + len = 1; + } /* - * if sk_wmem_alloc reached 0, we are last user and should - * free this sock, as sk_free() call could not do it. + * if sk_wmem_alloc reaches 0, we must finish what sk_free() + * could not do because of in-flight packets */ - if (res == 0) + if (atomic_sub_and_test(len, &sk->sk_wmem_alloc)) __sk_free(sk); } EXPORT_SYMBOL(sock_wfree); -- cgit v1.2.3 From 298bf12ddb25841804f26234a43b89da1b1c0e21 Mon Sep 17 00:00:00 2001 From: Sascha Hlusiak Date: Tue, 29 Sep 2009 11:27:05 +0000 Subject: sit: fix off-by-one in ipip6_tunnel_get_prl When requesting all prl entries (kprl.addr == INADDR_ANY) and there are more prl entries than there is space passed from userspace, the existing code would always copy cmax+1 entries, which is more than can be handled. This patch makes the kernel copy only exactly cmax entries. Signed-off-by: Sascha Hlusiak Acked-By: Fred L. Templin Signed-off-by: David S. Miller --- net/ipv6/sit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d65e0c496cc0..dbd19a78ca73 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -274,7 +274,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t, c = 0; for (prl = t->prl; prl; prl = prl->next) { - if (c > cmax) + if (c >= cmax) break; if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr) continue; -- cgit v1.2.3 From 013820a360b63a0a18fa13afb858b9f1af7e64fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Denis-Courmont?= Date: Wed, 30 Sep 2009 16:41:34 -0700 Subject: Phonet: fix mutex imbalance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Rémi Denis-Courmont port_mutex was unlocked twice. Signed-off-by: Rémi Denis-Courmont Signed-off-by: David S. Miller --- net/phonet/socket.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/phonet/socket.c b/net/phonet/socket.c index 07aa9f08d5fb..aa5b5a972bff 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -407,7 +407,6 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport) return -EADDRINUSE; found: - mutex_unlock(&port_mutex); pn->sobject = pn_object(pn_addr(pn->sobject), sport); return 0; } -- cgit v1.2.3 From 81bbb3d4048cf577b5babcb0834230de391a35c5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 30 Sep 2009 16:42:42 -0700 Subject: net: restore tx timestamping for accelerated vlans Since commit 9b22ea560957de1484e6b3e8538f7eef202e3596 ( net: fix packet socket delivery in rx irq handler ) We lost rx timestamping of packets received on accelerated vlans. Effect is that tcpdump on real dev can show strange timings, since it gets rx timestamps too late (ie at skb dequeueing time, not at skb queueing time) 14:47:26.986871 IP 192.168.20.110 > 192.168.20.141: icmp 64: echo request seq 1 14:47:26.986786 IP 192.168.20.141 > 192.168.20.110: icmp 64: echo reply seq 1 14:47:27.986888 IP 192.168.20.110 > 192.168.20.141: icmp 64: echo request seq 2 14:47:27.986781 IP 192.168.20.141 > 192.168.20.110: icmp 64: echo reply seq 2 14:47:28.986896 IP 192.168.20.110 > 192.168.20.141: icmp 64: echo request seq 3 14:47:28.986780 IP 192.168.20.141 > 192.168.20.110: icmp 64: echo reply seq 3 Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 560c8c9c03ab..b8f74cfb1bfd 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2288,6 +2288,9 @@ int netif_receive_skb(struct sk_buff *skb) int ret = NET_RX_DROP; __be16 type; + if (!skb->tstamp.tv64) + net_timestamp(skb); + if (skb->vlan_tci && vlan_hwaccel_do_receive(skb)) return NET_RX_SUCCESS; @@ -2295,9 +2298,6 @@ int netif_receive_skb(struct sk_buff *skb) if (netpoll_receive_skb(skb)) return NET_RX_DROP; - if (!skb->tstamp.tv64) - net_timestamp(skb); - if (!skb->iif) skb->iif = skb->dev->ifindex; -- cgit v1.2.3 From 8c185ab6185bf5e67766edb000ce428269364c86 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Sun, 27 Sep 2009 10:57:02 +0000 Subject: ax25: Fix possible oops in ax25_make_new In ax25_make_new, if kmemdup of digipeat returns an error, there would be an oops in sk_free while calling sk_destruct, because sk_protinfo is NULL at the moment; move sk->sk_destruct initialization after this. BTW of reported-by: Bernard Pidoux F6BVP Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- net/ax25/af_ax25.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index cd1c3dc0fe01..f45460730371 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -901,7 +901,6 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) sock_init_data(NULL, sk); - sk->sk_destruct = ax25_free_sock; sk->sk_type = osk->sk_type; sk->sk_priority = osk->sk_priority; sk->sk_protocol = osk->sk_protocol; @@ -939,6 +938,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) } sk->sk_protinfo = ax25; + sk->sk_destruct = ax25_free_sock; ax25->sk = sk; return sk; -- cgit v1.2.3 From 417bc4b855f04dd4ad27a7cabe3e7996a7b78ddb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 1 Oct 2009 09:29:45 -0700 Subject: pktgen: Fix delay handling After last pktgen changes, delay handling is wrong. pktgen actually sends packets at full line speed. Fix is to update pkt_dev->next_tx even if spin() returns early, so that next spin() calls have a chance to see a positive delay. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/pktgen.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 4d11c28ca8ca..b69455217ed6 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2105,15 +2105,17 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) static void spin(struct pktgen_dev *pkt_dev, ktime_t spin_until) { ktime_t start_time, end_time; - s32 remaining; + s64 remaining; struct hrtimer_sleeper t; hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); hrtimer_set_expires(&t.timer, spin_until); remaining = ktime_to_us(hrtimer_expires_remaining(&t.timer)); - if (remaining <= 0) + if (remaining <= 0) { + pkt_dev->next_tx = ktime_add_ns(spin_until, pkt_dev->delay); return; + } start_time = ktime_now(); if (remaining < 100) -- cgit v1.2.3 From 4fdb78d3093a347456e108b77d56d493d29071b2 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 1 Oct 2009 15:02:20 -0700 Subject: net/ipv4/tcp.c: fix min() type mismatch warning net/ipv4/tcp.c: In function 'do_tcp_setsockopt': net/ipv4/tcp.c:2050: warning: comparison of distinct pointer types lacks a cast Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 5a15e7629d8e..7bb8479b1eaf 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2047,7 +2047,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level, return -EINVAL; val = strncpy_from_user(name, optval, - min(TCP_CA_NAME_MAX-1, optlen)); + min_t(long, TCP_CA_NAME_MAX-1, optlen)); if (val < 0) return -EFAULT; name[val] = 0; -- cgit v1.2.3 From 89e95a613c8a045ce0c5b992ba19f10613f6ab2f Mon Sep 17 00:00:00 2001 From: Ori Finkelman Date: Thu, 1 Oct 2009 06:41:59 +0000 Subject: IPv4 TCP fails to send window scale option when window scale is zero Acknowledge TCP window scale support by inserting the proper option in SYN/ACK and SYN headers even if our window scale is zero. This fixes the following observed behavior: 1. Client sends a SYN with TCP window scaling option and non zero window scale value to a Linux box. 2. Linux box notes large receive window from client. 3. Linux decides on a zero value of window scale for its part. 4. Due to compare against requested window scale size option, Linux does not to send windows scale TCP option header on SYN/ACK at all. With the following result: Client box thinks TCP window scaling is not supported, since SYN/ACK had no TCP window scale option, while Linux thinks that TCP window scaling is supported (and scale might be non zero), since SYN had TCP window scale option and we have a mismatched idea between the client and server regarding window sizes. Probably it also fixes up the following bug (not observed in practice): 1. Linux box opens TCP connection to some server. 2. Linux decides on zero value of window scale. 3. Due to compare against computed window scale size option, Linux does not to set windows scale TCP option header on SYN. With the expected result that the server OS does not use window scale option due to not receiving such an option in the SYN headers, leading to suboptimal performance. Signed-off-by: Gilad Ben-Yossef Signed-off-by: Ori Finkelman Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 5200aab0ca97..fcd278a7080e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -361,6 +361,7 @@ static inline int tcp_urg_mode(const struct tcp_sock *tp) #define OPTION_SACK_ADVERTISE (1 << 0) #define OPTION_TS (1 << 1) #define OPTION_MD5 (1 << 2) +#define OPTION_WSCALE (1 << 3) struct tcp_out_options { u8 options; /* bit field of OPTION_* */ @@ -427,7 +428,7 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, TCPOLEN_SACK_PERM); } - if (unlikely(opts->ws)) { + if (unlikely(OPTION_WSCALE & opts->options)) { *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | @@ -494,8 +495,8 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, } if (likely(sysctl_tcp_window_scaling)) { opts->ws = tp->rx_opt.rcv_wscale; - if (likely(opts->ws)) - size += TCPOLEN_WSCALE_ALIGNED; + opts->options |= OPTION_WSCALE; + size += TCPOLEN_WSCALE_ALIGNED; } if (likely(sysctl_tcp_sack)) { opts->options |= OPTION_SACK_ADVERTISE; @@ -537,8 +538,8 @@ static unsigned tcp_synack_options(struct sock *sk, if (likely(ireq->wscale_ok)) { opts->ws = ireq->rcv_wscale; - if (likely(opts->ws)) - size += TCPOLEN_WSCALE_ALIGNED; + opts->options |= OPTION_WSCALE; + size += TCPOLEN_WSCALE_ALIGNED; } if (likely(doing_ts)) { opts->options |= OPTION_TS; -- cgit v1.2.3 From 914a9ab386a288d0f22252fc268ecbc048cdcbd5 Mon Sep 17 00:00:00 2001 From: Atis Elsts Date: Thu, 1 Oct 2009 15:16:49 -0700 Subject: net: Use sk_mark for routing lookup in more places This patch against v2.6.31 adds support for route lookup using sk_mark in some more places. The benefits from this patch are the following. First, SO_MARK option now has effect on UDP sockets too. Second, ip_queue_xmit() and inet_sk_rebuild_header() could fail to do routing lookup correctly if TCP sockets with SO_MARK were used. Signed-off-by: Atis Elsts Acked-by: Eric Dumazet --- net/ipv4/af_inet.c | 1 + net/ipv4/ip_output.c | 1 + net/ipv4/udp.c | 1 + 3 files changed, 3 insertions(+) (limited to 'net') diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 58c4b0f7c4aa..57737b8d1711 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1119,6 +1119,7 @@ int inet_sk_rebuild_header(struct sock *sk) { struct flowi fl = { .oif = sk->sk_bound_dev_if, + .mark = sk->sk_mark, .nl_u = { .ip4_u = { .daddr = daddr, diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 9fe5d7b81580..f9895180f481 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -335,6 +335,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) { struct flowi fl = { .oif = sk->sk_bound_dev_if, + .mark = sk->sk_mark, .nl_u = { .ip4_u = { .daddr = daddr, .saddr = inet->saddr, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 3326aff65906..6ec6a8a4a224 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -696,6 +696,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (rt == NULL) { struct flowi fl = { .oif = ipc.oif, + .mark = sk->sk_mark, .nl_u = { .ip4_u = { .daddr = faddr, .saddr = saddr, -- cgit v1.2.3 From 42324c62704365d6a3e89138dea55909d2f26afe Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 1 Oct 2009 15:26:00 -0700 Subject: net: splice() from tcp to pipe should take into account O_NONBLOCK tcp_splice_read() doesnt take into account socket's O_NONBLOCK flag Before this patch : splice(socket,0,pipe,0,128*1024,SPLICE_F_MOVE); causes a random endless block (if pipe is full) and splice(socket,0,pipe,0,128*1024,SPLICE_F_MOVE | SPLICE_F_NONBLOCK); will return 0 immediately if the TCP buffer is empty. User application has no way to instruct splice() that socket should be in blocking mode but pipe in nonblock more. Many projects cannot use splice(tcp -> pipe) because of this flaw. http://git.samba.org/?p=samba.git;a=history;f=source3/lib/recvfile.c;h=ea0159642137390a0f7e57a123684e6e63e47581;hb=HEAD http://lkml.indiana.edu/hypermail/linux/kernel/0807.2/0687.html Linus introduced SPLICE_F_NONBLOCK in commit 29e350944fdc2dfca102500790d8ad6d6ff4f69d (splice: add SPLICE_F_NONBLOCK flag ) It doesn't make the splice itself necessarily nonblocking (because the actual file descriptors that are spliced from/to may block unless they have the O_NONBLOCK flag set), but it makes the splice pipe operations nonblocking. Linus intention was clear : let SPLICE_F_NONBLOCK control the splice pipe mode only This patch instruct tcp_splice_read() to use the underlying file O_NONBLOCK flag, as other socket operations do. Users will then call : splice(socket,0,pipe,0,128*1024,SPLICE_F_MOVE | SPLICE_F_NONBLOCK ); to block on data coming from socket (if file is in blocking mode), and not block on pipe output (to avoid deadlock) First version of this patch was submitted by Octavian Purdila Reported-by: Volker Lendecke Reported-by: Jason Gunthorpe Signed-off-by: Eric Dumazet Signed-off-by: Octavian Purdila Acked-by: Linus Torvalds Acked-by: Jens Axboe Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7bb8479b1eaf..64d0af675823 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -580,7 +580,7 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, lock_sock(sk); - timeo = sock_rcvtimeo(sk, flags & SPLICE_F_NONBLOCK); + timeo = sock_rcvtimeo(sk, sock->file->f_flags & O_NONBLOCK); while (tss.len) { ret = __tcp_splice_read(sk, &tss); if (ret < 0) -- cgit v1.2.3 From a99bbaf5ee6bad1aca0c88ea65ec6e5373e86184 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sun, 4 Oct 2009 16:11:37 +0400 Subject: headers: remove sched.h from poll.h Signed-off-by: Alexey Dobriyan Signed-off-by: Linus Torvalds --- net/rfkill/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/rfkill/core.c b/net/rfkill/core.c index dbeaf2983822..ba2efb960c60 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 896a7cf8d846a9e86fb823be16f4f14ffeb7f074 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 2 Oct 2009 20:24:59 +0000 Subject: pktgen: Fix multiqueue handling It is not currently possible to instruct pktgen to use one selected tx queue. When Robert added multiqueue support in commit 45b270f8, he added an interval (queue_map_min, queue_map_max), and his code doesnt take into account the case of min = max, to select one tx queue exactly. I suspect a high performance setup on a eight txqueue device wants to use exactly eight cpus, and assign one tx queue to each sender. This patchs makes pktgen select the right tx queue, not the first one. Also updates Documentation to reflect Robert changes. Signed-off-by: Eric Dumazet Signed-off-by: Robert Olsson Signed-off-by: David S. Miller --- net/core/pktgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/pktgen.c b/net/core/pktgen.c index b69455217ed6..421857c8c071 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2212,7 +2212,7 @@ static void set_cur_queue_map(struct pktgen_dev *pkt_dev) if (pkt_dev->flags & F_QUEUE_MAP_CPU) pkt_dev->cur_queue_map = smp_processor_id(); - else if (pkt_dev->queue_map_min < pkt_dev->queue_map_max) { + else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) { __u16 t; if (pkt_dev->flags & F_QUEUE_MAP_RND) { t = random32() % -- cgit v1.2.3 From 9240d7154e766ce6f3b615e81ed28f7562f509a5 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 3 Oct 2009 01:39:18 +0000 Subject: pktgen: restore nanosec delays Commit fd29cf72 (pktgen: convert to use ktime_t) inadvertantly converted "delay" parameter from nanosec to microsec. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/pktgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 421857c8c071..86acdba0a97d 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -964,7 +964,7 @@ static ssize_t pktgen_if_write(struct file *file, if (value == 0x7FFFFFFF) pkt_dev->delay = ULLONG_MAX; else - pkt_dev->delay = (u64)value * NSEC_PER_USEC; + pkt_dev->delay = (u64)value; sprintf(pg_result, "OK: delay=%llu", (unsigned long long) pkt_dev->delay); -- cgit v1.2.3 From a160ee69c6a4622ed30c377a978554015e9931cb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 5 Oct 2009 02:22:23 -0700 Subject: wext: let get_wireless_stats() sleep A number of drivers (recently including cfg80211-based ones) assume that all wireless handlers, including statistics, can sleep and they often also implicitly assume that the rtnl is held around their invocation. This is almost always true now except when reading from sysfs: BUG: sleeping function called from invalid context at kernel/mutex.c:280 in_atomic(): 1, irqs_disabled(): 0, pid: 10450, name: head 2 locks held by head/10450: #0: (&buffer->mutex){+.+.+.}, at: [] sysfs_read_file+0x24/0xf4 #1: (dev_base_lock){++.?..}, at: [] wireless_show+0x1a/0x4c Pid: 10450, comm: head Not tainted 2.6.32-rc3 #1 Call Trace: [] __might_sleep+0xf0/0xf7 [] mutex_lock_nested+0x1a/0x33 [] wdev_lock+0xd/0xf [cfg80211] [] cfg80211_wireless_stats+0x45/0x12d [cfg80211] [] get_wireless_stats+0x16/0x1c [] wireless_show+0x2a/0x4c Fix this by using the rtnl instead of dev_base_lock. Reported-by: Miles Lane Signed-off-by: Johannes Berg Signed-off-by: David S. Miller --- net/core/net-sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 821d30918cfc..427ded841224 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -366,13 +366,13 @@ static ssize_t wireless_show(struct device *d, char *buf, const struct iw_statistics *iw; ssize_t ret = -EINVAL; - read_lock(&dev_base_lock); + rtnl_lock(); if (dev_isalive(dev)) { iw = get_wireless_stats(dev); if (iw) ret = (*format)(iw, buf); } - read_unlock(&dev_base_lock); + rtnl_unlock(); return ret; } -- cgit v1.2.3 From a21090cff296eb82b6de09304d64de466bdcaefc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 7 Oct 2009 03:18:17 -0700 Subject: ipv4: arp_notify address list bug This fixes a bug with arp_notify. If arp_notify is enabled, kernel will crash if address is changed and no IP address is assigned. http://bugzilla.kernel.org/show_bug.cgi?id=14330 Reported-by: Hannes Frederic Sowa Signed-off-by: Stephen Hemminger Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index e92f1fd28aa5..5df2f6a0b0f0 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1077,12 +1077,16 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, ip_mc_up(in_dev); /* fall through */ case NETDEV_CHANGEADDR: - if (IN_DEV_ARP_NOTIFY(in_dev)) - arp_send(ARPOP_REQUEST, ETH_P_ARP, - in_dev->ifa_list->ifa_address, - dev, - in_dev->ifa_list->ifa_address, - NULL, dev->dev_addr, NULL); + /* Send gratuitous ARP to notify of link change */ + if (IN_DEV_ARP_NOTIFY(in_dev)) { + struct in_ifaddr *ifa = in_dev->ifa_list; + + if (ifa) + arp_send(ARPOP_REQUEST, ETH_P_ARP, + ifa->ifa_address, dev, + ifa->ifa_address, NULL, + dev->dev_addr, NULL); + } break; case NETDEV_DOWN: ip_mc_down(in_dev); -- cgit v1.2.3 From fbc44bf7177dfd61381da55405550b693943a432 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 1 Oct 2009 22:06:29 +0200 Subject: mac80211: fix vlan and optimise RX When receiving data frames, we can send them only to the interface they belong to based on transmitting station (this doesn't work for probe requests). Also, don't try to handle other frames for AP_VLAN at all since those interface should only receive data. Additionally, the transmit side must check that the station we're sending a frame to is actually on the interface we're transmitting on, and not transmit packets to functions that live on other interfaces, so validate that as well. Another bug fix is needed in sta_info.c where in the VLAN case when adding/removing stations we overwrite the sdata variable we still need. Signed-off-by: Johannes Berg Cc: stable@kernel.org Signed-off-by: John W. Linville --- net/mac80211/rx.c | 10 ++++++++-- net/mac80211/sta_info.c | 2 ++ net/mac80211/tx.c | 3 ++- 3 files changed, 12 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c01588f9d453..865fbc09be1a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2164,11 +2164,17 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, skb = rx.skb; - list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (rx.sdata && ieee80211_is_data(hdr->frame_control)) { + rx.flags |= IEEE80211_RX_RA_MATCH; + prepares = prepare_for_handlers(rx.sdata, &rx, hdr); + if (prepares) + prev = rx.sdata; + } else list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (!netif_running(sdata->dev)) continue; - if (sdata->vif.type == NL80211_IFTYPE_MONITOR) + if (sdata->vif.type == NL80211_IFTYPE_MONITOR || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN) continue; rx.flags |= IEEE80211_RX_RA_MATCH; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index eec001491e66..594f2318c3d8 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -361,6 +361,7 @@ int sta_info_insert(struct sta_info *sta) u.ap); drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, &sta->sta); + sdata = sta->sdata; } #ifdef CONFIG_MAC80211_VERBOSE_DEBUG @@ -496,6 +497,7 @@ static void __sta_info_unlink(struct sta_info **sta) drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE, &(*sta)->sta); + sdata = (*sta)->sdata; } if (ieee80211_vif_is_mesh(&sdata->vif)) { diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index fd4028296613..db4bda681ec9 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1704,7 +1704,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, if (!is_multicast_ether_addr(hdr.addr1)) { rcu_read_lock(); sta = sta_info_get(local, hdr.addr1); - if (sta) + /* XXX: in the future, use sdata to look up the sta */ + if (sta && sta->sdata == sdata) sta_flags = get_sta_flags(sta); rcu_read_unlock(); } -- cgit v1.2.3 From 0819663d164e090de315c5e619f4e23c27aaff88 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 6 Oct 2009 15:52:35 +0200 Subject: mac80211: use kfree_skb() to free struct sk_buff pointers kfree_skb() should be used to free struct sk_buff pointers. Signed-off-by: Roel Kluin Acked-by: Johannes Berg Cc: stable@kernel.org Signed-off-by: John W. Linville --- net/mac80211/util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/util.c b/net/mac80211/util.c index dd6564321369..aeb65b3d2295 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -339,7 +339,7 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (WARN_ON(!info->control.vif)) { - kfree(skb); + kfree_skb(skb); return; } @@ -367,7 +367,7 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); if (WARN_ON(!info->control.vif)) { - kfree(skb); + kfree_skb(skb); continue; } -- cgit v1.2.3 From ad61df918c44316940404891d5082c63e79c256a Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 8 Oct 2009 01:21:46 -0700 Subject: netlink: fix typo in initialization Commit 9ef1d4c7c7aca1cd436612b6ca785b726ffb8ed8 ("[NETLINK]: Missing initializations in dumped data") introduced a typo in initialization. This patch fixes this. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- net/sched/cls_api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 6a536949cdc0..7cf6c0fbc7a6 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -350,7 +350,7 @@ static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, tcm = NLMSG_DATA(nlh); tcm->tcm_family = AF_UNSPEC; tcm->tcm__pad1 = 0; - tcm->tcm__pad1 = 0; + tcm->tcm__pad2 = 0; tcm->tcm_ifindex = qdisc_dev(tp->q)->ifindex; tcm->tcm_parent = tp->classid; tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol); -- cgit v1.2.3 From 8a8e05e5d8f6155788761961fc9845328863c16d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 8 Oct 2009 21:02:02 +0200 Subject: cfg80211: fix netns error unwinding bug The error unwinding code in set_netns has a bug that will make it run into a BUG_ON if passed a bad wiphy index, fix by not trying to unlock a wiphy that doesn't exist. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/nl80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index eddab097435c..ca3c92a0a14f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4029,7 +4029,7 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) rdev = cfg80211_get_dev_from_info(info); if (IS_ERR(rdev)) { err = PTR_ERR(rdev); - goto out; + goto out_rtnl; } net = get_net_ns_by_pid(pid); @@ -4049,6 +4049,7 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info) put_net(net); out: cfg80211_unlock_rdev(rdev); + out_rtnl: rtnl_unlock(); return err; } -- cgit v1.2.3 From d43c36dc6b357fa1806800f18aa30123c747a6d1 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 7 Oct 2009 17:09:06 +0400 Subject: headers: remove sched.h from interrupt.h After m68k's task_thread_info() doesn't refer to current, it's possible to remove sched.h from interrupt.h and not break m68k! Many thanks to Heiko Carstens for allowing this. Signed-off-by: Alexey Dobriyan --- net/irda/ircomm/ircomm_tty_attach.c | 1 + net/irda/irlan/irlan_common.c | 1 + net/irda/irlan/irlan_eth.c | 1 + net/irda/irnet/irnet_irda.c | 1 + net/irda/irnet/irnet_ppp.c | 1 + net/mac80211/rc80211_pid_debugfs.c | 1 + net/netfilter/nf_conntrack_core.c | 1 + net/sunrpc/xprtrdma/svc_rdma_transport.c | 1 + net/wireless/core.c | 1 + 9 files changed, 9 insertions(+) (limited to 'net') diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index eafc010907c2..3c1754023022 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -30,6 +30,7 @@ ********************************************************************/ #include +#include #include #include diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 62116829b817..315ead3cb926 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 7b6b631f647f..d340110f5c0c 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c index cf9a4b531a98..cccc2e93234f 100644 --- a/net/irda/irnet/irnet_irda.c +++ b/net/irda/irnet/irnet_irda.c @@ -9,6 +9,7 @@ */ #include "irnet_irda.h" /* Private header */ +#include #include #include diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c index 68cbcb19cbd8..7dea882dbb75 100644 --- a/net/irda/irnet/irnet_ppp.c +++ b/net/irda/irnet/irnet_ppp.c @@ -13,6 +13,7 @@ * 2) as a control channel (write commands, read events) */ +#include #include #include "irnet_ppp.h" /* Private header */ /* Please put other headers in irnet.h - Thanks */ diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index a59043fbb0ff..45667054a5f3 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c @@ -6,6 +6,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 7c9ec3dee96e..ca6e68dcd8a8 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 0cf5e8c27a10..3fa5751af0ec 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include diff --git a/net/wireless/core.c b/net/wireless/core.c index 45b2be3274db..a595f712b5bf 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include "nl80211.h" -- cgit v1.2.3 From 53f7e35f8b7fc2f5620a863ac613bcf3080cb6ba Mon Sep 17 00:00:00 2001 From: jamal Date: Sun, 11 Oct 2009 04:21:38 +0000 Subject: pkt_sched: pedit use proper struct This probably deserves to go into -stable. Pedit will reject a policy that is large because it uses the wrong structure in the policy validation. This fixes it. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/sched/act_pedit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 96c0ed115e2a..6b0359a500e6 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -34,7 +34,7 @@ static struct tcf_hashinfo pedit_hash_info = { }; static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = { - [TCA_PEDIT_PARMS] = { .len = sizeof(struct tcf_pedit) }, + [TCA_PEDIT_PARMS] = { .len = sizeof(struct tc_pedit) }, }; static int tcf_pedit_init(struct nlattr *nla, struct nlattr *est, -- cgit v1.2.3 From 5e4708bcb5d5360730e31b14e5e36429fc7d48b2 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 11 Oct 2009 05:21:10 +0200 Subject: mac80211: fix logic error ibss merge bssid check Signed-off-by: Felix Fietkau Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 920ec8792f4b..812cbaba324f 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -544,7 +544,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) "%pM\n", bss->cbss.bssid, ifibss->bssid); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ - if (bss && memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) { + if (bss && !memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) { printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" " based on configured SSID\n", sdata->dev->name, bss->cbss.bssid); -- cgit v1.2.3 From 51f98f1313d2fc4b1d3a3e1f4db7cf4925b29df6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 11 Oct 2009 11:47:57 +0200 Subject: mac80211: fix ibss race When a scan completes, we call ieee80211_sta_find_ibss(), which is also called from other places. When the scan was done in software, there's no problem as both run from the single-threaded mac80211 workqueue and are thus serialised against each other, but with hardware scan the completion can be in a different context and race against callers of this function from the workqueue (e.g. due to beacon RX). So instead of calling ieee80211_sta_find_ibss() directly, just arm the timer and have it fire, scheduling the work, which will invoke ieee80211_sta_find_ibss() (if that is appropriate in the current state). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 812cbaba324f..6eaf69823439 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -829,7 +829,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) if (!sdata->u.ibss.ssid_len) continue; sdata->u.ibss.last_scan_completed = jiffies; - ieee80211_sta_find_ibss(sdata); + mod_timer(&sdata->u.ibss.timer, 0); } mutex_unlock(&local->iflist_mtx); } -- cgit v1.2.3 From d20ef63d32461332958661df73e21c0ca42601b0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 11 Oct 2009 15:10:40 +0200 Subject: mac80211: document ieee80211_rx() context requirement ieee80211_rx() must be called with softirqs disabled since the networking stack requires this for netif_rx() and some code in mac80211 can assume that it can not be processing its own tasklet and this call at the same time. It may be possible to remove this requirement after a careful audit of mac80211 and doing any needed locking improvements in it along with disabling softirqs around netif_rx(). An alternative might be to push all packet processing to process context in mac80211, instead of to the tasklet, and add other synchronisation. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 865fbc09be1a..7170bf4565a8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2453,6 +2453,8 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_supported_band *sband; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); + WARN_ON_ONCE(softirq_count() == 0); + if (WARN_ON(status->band < 0 || status->band >= IEEE80211_NUM_BANDS)) goto drop; -- cgit v1.2.3 From 6d01a026b7d3009a418326bdcf313503a314f1ea Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 13 Oct 2009 00:27:40 -0700 Subject: tcp: fix tcp_defer_accept to consider the timeout I was trying to use TCP_DEFER_ACCEPT and noticed that if the client does not talk, the connection is never accepted and remains in SYN_RECV state until the retransmits expire, where it finally is deleted. This is bad when some firewall such as netfilter sits between the client and the server because the firewall sees the connection in ESTABLISHED state while the server will finally silently drop it without sending an RST. This behaviour contradicts the man page which says it should wait only for some time : TCP_DEFER_ACCEPT (since Linux 2.4) Allows a listener to be awakened only when data arrives on the socket. Takes an integer value (seconds), this can bound the maximum number of attempts TCP will make to complete the connection. This option should not be used in code intended to be portable. Also, looking at ipv4/tcp.c, a retransmit counter is correctly computed : case TCP_DEFER_ACCEPT: icsk->icsk_accept_queue.rskq_defer_accept = 0; if (val > 0) { /* Translate value in seconds to number of * retransmits */ while (icsk->icsk_accept_queue.rskq_defer_accept < 32 && val > ((TCP_TIMEOUT_INIT / HZ) << icsk->icsk_accept_queue.rskq_defer_accept)) icsk->icsk_accept_queue.rskq_defer_accept++; icsk->icsk_accept_queue.rskq_defer_accept++; } break; ==> rskq_defer_accept is used as a counter of retransmits. But in tcp_minisocks.c, this counter is only checked. And in fact, I have found no location which updates it. So I think that what was intended was to decrease it in tcp_minisocks whenever it is checked, which the trivial patch below does. Signed-off-by: Willy Tarreau Signed-off-by: David S. Miller --- net/ipv4/tcp_minisocks.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 624c3c9b3c2b..e320afea07fc 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -644,6 +644,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, /* If TCP_DEFER_ACCEPT is set, drop bare ACK. */ if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) { + inet_csk(sk)->icsk_accept_queue.rskq_defer_accept--; inet_rsk(req)->acked = 1; return NULL; } -- cgit v1.2.3 From 85584672012ee0c3b7b8e033a1ecf7c11878e45f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 9 Oct 2009 04:43:40 +0000 Subject: udp: Fix udp_poll() and ioctl() udp_poll() can in some circumstances drop frames with incorrect checksums. Problem is we now have to lock the socket while dropping frames, or risk sk_forward corruption. This bug is present since commit 95766fff6b9a78d1 ([UDP]: Add memory accounting.) While we are at it, we can correct ioctl(SIOCINQ) to also drop bad frames. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/udp.c | 73 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 6ec6a8a4a224..d0d436d6216c 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -841,6 +841,42 @@ out: return ret; } + +/** + * first_packet_length - return length of first packet in receive queue + * @sk: socket + * + * Drops all bad checksum frames, until a valid one is found. + * Returns the length of found skb, or 0 if none is found. + */ +static unsigned int first_packet_length(struct sock *sk) +{ + struct sk_buff_head list_kill, *rcvq = &sk->sk_receive_queue; + struct sk_buff *skb; + unsigned int res; + + __skb_queue_head_init(&list_kill); + + spin_lock_bh(&rcvq->lock); + while ((skb = skb_peek(rcvq)) != NULL && + udp_lib_checksum_complete(skb)) { + UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, + IS_UDPLITE(sk)); + __skb_unlink(skb, rcvq); + __skb_queue_tail(&list_kill, skb); + } + res = skb ? skb->len : 0; + spin_unlock_bh(&rcvq->lock); + + if (!skb_queue_empty(&list_kill)) { + lock_sock(sk); + __skb_queue_purge(&list_kill); + sk_mem_reclaim_partial(sk); + release_sock(sk); + } + return res; +} + /* * IOCTL requests applicable to the UDP protocol */ @@ -857,21 +893,16 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) case SIOCINQ: { - struct sk_buff *skb; - unsigned long amount; + unsigned int amount = first_packet_length(sk); - amount = 0; - spin_lock_bh(&sk->sk_receive_queue.lock); - skb = skb_peek(&sk->sk_receive_queue); - if (skb != NULL) { + if (amount) /* * We will only return the amount * of this packet since that is all * that will be read. */ - amount = skb->len - sizeof(struct udphdr); - } - spin_unlock_bh(&sk->sk_receive_queue.lock); + amount -= sizeof(struct udphdr); + return put_user(amount, (int __user *)arg); } @@ -1540,29 +1571,11 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) { unsigned int mask = datagram_poll(file, sock, wait); struct sock *sk = sock->sk; - int is_lite = IS_UDPLITE(sk); /* Check for false positives due to checksum errors */ - if ((mask & POLLRDNORM) && - !(file->f_flags & O_NONBLOCK) && - !(sk->sk_shutdown & RCV_SHUTDOWN)) { - struct sk_buff_head *rcvq = &sk->sk_receive_queue; - struct sk_buff *skb; - - spin_lock_bh(&rcvq->lock); - while ((skb = skb_peek(rcvq)) != NULL && - udp_lib_checksum_complete(skb)) { - UDP_INC_STATS_BH(sock_net(sk), - UDP_MIB_INERRORS, is_lite); - __skb_unlink(skb, rcvq); - kfree_skb(skb); - } - spin_unlock_bh(&rcvq->lock); - - /* nothing to see, move along */ - if (skb == NULL) - mask &= ~(POLLIN | POLLRDNORM); - } + if ((mask & POLLRDNORM) && !(file->f_flags & O_NONBLOCK) && + !(sk->sk_shutdown & RCV_SHUTDOWN) && !first_packet_length(sk)) + mask &= ~(POLLIN | POLLRDNORM); return mask; -- cgit v1.2.3 From 77238f2b942b38ab4e7f3aced44084493e4a8675 Mon Sep 17 00:00:00 2001 From: Tomoki Sekiyama Date: Sun, 18 Oct 2009 23:17:37 -0700 Subject: AF_UNIX: Fix deadlock on connecting to shutdown socket I found a deadlock bug in UNIX domain socket, which makes able to DoS attack against the local machine by non-root users. How to reproduce: 1. Make a listening AF_UNIX/SOCK_STREAM socket with an abstruct namespace(*), and shutdown(2) it. 2. Repeat connect(2)ing to the listening socket from the other sockets until the connection backlog is full-filled. 3. connect(2) takes the CPU forever. If every core is taken, the system hangs. PoC code: (Run as many times as cores on SMP machines.) int main(void) { int ret; int csd; int lsd; struct sockaddr_un sun; /* make an abstruct name address (*) */ memset(&sun, 0, sizeof(sun)); sun.sun_family = PF_UNIX; sprintf(&sun.sun_path[1], "%d", getpid()); /* create the listening socket and shutdown */ lsd = socket(AF_UNIX, SOCK_STREAM, 0); bind(lsd, (struct sockaddr *)&sun, sizeof(sun)); listen(lsd, 1); shutdown(lsd, SHUT_RDWR); /* connect loop */ alarm(15); /* forcely exit the loop after 15 sec */ for (;;) { csd = socket(AF_UNIX, SOCK_STREAM, 0); ret = connect(csd, (struct sockaddr *)&sun, sizeof(sun)); if (-1 == ret) { perror("connect()"); break; } puts("Connection OK"); } return 0; } (*) Make sun_path[0] = 0 to use the abstruct namespace. If a file-based socket is used, the system doesn't deadlock because of context switches in the file system layer. Why this happens: Error checks between unix_socket_connect() and unix_wait_for_peer() are inconsistent. The former calls the latter to wait until the backlog is processed. Despite the latter returns without doing anything when the socket is shutdown, the former doesn't check the shutdown state and just retries calling the latter forever. Patch: The patch below adds shutdown check into unix_socket_connect(), so connect(2) to the shutdown socket will return -ECONREFUSED. Signed-off-by: Tomoki Sekiyama Signed-off-by: Masanori Yoshida Signed-off-by: David S. Miller --- net/unix/af_unix.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 51ab497115eb..fc820cd75453 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1074,6 +1074,8 @@ restart: err = -ECONNREFUSED; if (other->sk_state != TCP_LISTEN) goto out_unlock; + if (other->sk_shutdown & RCV_SHUTDOWN) + goto out_unlock; if (unix_recvq_full(other)) { err = -EAGAIN; -- cgit v1.2.3 From a1a2ad9151c26d92e5c733a33d52108f5d3a5b57 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 19 Oct 2009 19:12:36 -0700 Subject: Revert "tcp: fix tcp_defer_accept to consider the timeout" This reverts commit 6d01a026b7d3009a418326bdcf313503a314f1ea. Julian Anastasov, Willy Tarreau and Eric Dumazet have come up with a more correct way to deal with this. Signed-off-by: David S. Miller --- net/ipv4/tcp_minisocks.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index e320afea07fc..624c3c9b3c2b 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -644,7 +644,6 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, /* If TCP_DEFER_ACCEPT is set, drop bare ACK. */ if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) { - inet_csk(sk)->icsk_accept_queue.rskq_defer_accept--; inet_rsk(req)->acked = 1; return NULL; } -- cgit v1.2.3 From d1b99ba41d6c5aa1ed2fc634323449dd656899e9 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Mon, 19 Oct 2009 10:01:56 +0000 Subject: tcp: accept socket after TCP_DEFER_ACCEPT period Willy Tarreau and many other folks in recent years were concerned what happens when the TCP_DEFER_ACCEPT period expires for clients which sent ACK packet. They prefer clients that actively resend ACK on our SYN-ACK retransmissions to be converted from open requests to sockets and queued to the listener for accepting after the deferring period is finished. Then application server can decide to wait longer for data or to properly terminate the connection with FIN if read() returns EAGAIN which is an indication for accepting after the deferring period. This change still can have side effects for applications that expect always to see data on the accepted socket. Others can be prepared to work in both modes (with or without TCP_DEFER_ACCEPT period) and their data processing can ignore the read=EAGAIN notification and to allocate resources for clients which proved to have no data to send during the deferring period. OTOH, servers that use TCP_DEFER_ACCEPT=1 as flag (not as a timeout) to wait for data will notice clients that didn't send data for 3 seconds but that still resend ACKs. Thanks to Willy Tarreau for the initial idea and to Eric Dumazet for the review and testing the change. Signed-off-by: Julian Anastasov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp_minisocks.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 624c3c9b3c2b..4c03598ed924 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -641,8 +641,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, if (!(flg & TCP_FLAG_ACK)) return NULL; - /* If TCP_DEFER_ACCEPT is set, drop bare ACK. */ - if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && + /* While TCP_DEFER_ACCEPT is active, drop bare ACK. */ + if (req->retrans < inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) { inet_rsk(req)->acked = 1; return NULL; -- cgit v1.2.3 From 0c3d79bce48034018e840468ac5a642894a521a3 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Mon, 19 Oct 2009 10:03:58 +0000 Subject: tcp: reduce SYN-ACK retrans for TCP_DEFER_ACCEPT Change SYN-ACK retransmitting code for the TCP_DEFER_ACCEPT users to not retransmit SYN-ACKs during the deferring period if ACK from client was received. The goal is to reduce traffic during the deferring period. When the period is finished we continue with sending SYN-ACKs (at least one) but this time any traffic from client will change the request to established socket allowing application to terminate it properly. Also, do not drop acked request if sending of SYN-ACK fails. Signed-off-by: Julian Anastasov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/inet_connection_sock.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 4351ca2cf0b8..537731b3bcb3 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -446,6 +446,28 @@ extern int sysctl_tcp_synack_retries; EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_hash_add); +/* Decide when to expire the request and when to resend SYN-ACK */ +static inline void syn_ack_recalc(struct request_sock *req, const int thresh, + const int max_retries, + const u8 rskq_defer_accept, + int *expire, int *resend) +{ + if (!rskq_defer_accept) { + *expire = req->retrans >= thresh; + *resend = 1; + return; + } + *expire = req->retrans >= thresh && + (!inet_rsk(req)->acked || req->retrans >= max_retries); + /* + * Do not resend while waiting for data after ACK, + * start to resend on end of deferring period to give + * last chance for data or ACK to create established socket. + */ + *resend = !inet_rsk(req)->acked || + req->retrans >= rskq_defer_accept - 1; +} + void inet_csk_reqsk_queue_prune(struct sock *parent, const unsigned long interval, const unsigned long timeout, @@ -501,9 +523,15 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, reqp=&lopt->syn_table[i]; while ((req = *reqp) != NULL) { if (time_after_eq(now, req->expires)) { - if ((req->retrans < thresh || - (inet_rsk(req)->acked && req->retrans < max_retries)) - && !req->rsk_ops->rtx_syn_ack(parent, req)) { + int expire = 0, resend = 0; + + syn_ack_recalc(req, thresh, max_retries, + queue->rskq_defer_accept, + &expire, &resend); + if (!expire && + (!resend || + !req->rsk_ops->rtx_syn_ack(parent, req) || + inet_rsk(req)->acked)) { unsigned long timeo; if (req->retrans++ == 0) -- cgit v1.2.3 From b103cf34382f26ff48a87931b83f13b177b47c1a Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Mon, 19 Oct 2009 10:10:40 +0000 Subject: tcp: fix TCP_DEFER_ACCEPT retrans calculation Fix TCP_DEFER_ACCEPT conversion between seconds and retransmission to match the TCP SYN-ACK retransmission periods because the time is converted to such retransmissions. The old algorithm selects one more retransmission in some cases. Allow up to 255 retransmissions. Signed-off-by: Julian Anastasov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 55 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 64d0af675823..9b2756fbdf9b 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -326,6 +326,43 @@ void tcp_enter_memory_pressure(struct sock *sk) EXPORT_SYMBOL(tcp_enter_memory_pressure); +/* Convert seconds to retransmits based on initial and max timeout */ +static u8 secs_to_retrans(int seconds, int timeout, int rto_max) +{ + u8 res = 0; + + if (seconds > 0) { + int period = timeout; + + res = 1; + while (seconds > period && res < 255) { + res++; + timeout <<= 1; + if (timeout > rto_max) + timeout = rto_max; + period += timeout; + } + } + return res; +} + +/* Convert retransmits to seconds based on initial and max timeout */ +static int retrans_to_secs(u8 retrans, int timeout, int rto_max) +{ + int period = 0; + + if (retrans > 0) { + period = timeout; + while (--retrans) { + timeout <<= 1; + if (timeout > rto_max) + timeout = rto_max; + period += timeout; + } + } + return period; +} + /* * Wait for a TCP event. * @@ -2163,16 +2200,10 @@ static int do_tcp_setsockopt(struct sock *sk, int level, break; case TCP_DEFER_ACCEPT: - icsk->icsk_accept_queue.rskq_defer_accept = 0; - if (val > 0) { - /* Translate value in seconds to number of - * retransmits */ - while (icsk->icsk_accept_queue.rskq_defer_accept < 32 && - val > ((TCP_TIMEOUT_INIT / HZ) << - icsk->icsk_accept_queue.rskq_defer_accept)) - icsk->icsk_accept_queue.rskq_defer_accept++; - icsk->icsk_accept_queue.rskq_defer_accept++; - } + /* Translate value in seconds to number of retransmits */ + icsk->icsk_accept_queue.rskq_defer_accept = + secs_to_retrans(val, TCP_TIMEOUT_INIT / HZ, + TCP_RTO_MAX / HZ); break; case TCP_WINDOW_CLAMP: @@ -2353,8 +2384,8 @@ static int do_tcp_getsockopt(struct sock *sk, int level, val = (val ? : sysctl_tcp_fin_timeout) / HZ; break; case TCP_DEFER_ACCEPT: - val = !icsk->icsk_accept_queue.rskq_defer_accept ? 0 : - ((TCP_TIMEOUT_INIT / HZ) << (icsk->icsk_accept_queue.rskq_defer_accept - 1)); + val = retrans_to_secs(icsk->icsk_accept_queue.rskq_defer_accept, + TCP_TIMEOUT_INIT / HZ, TCP_RTO_MAX / HZ); break; case TCP_WINDOW_CLAMP: val = tp->window_clamp; -- cgit v1.2.3 From f74c77cb1124a11acf69c98d10c0fdc22f322664 Mon Sep 17 00:00:00 2001 From: Dave Young Date: Sun, 18 Oct 2009 20:24:41 +0000 Subject: bluetooth: scheduling while atomic bug fix Due to driver core changes dev_set_drvdata will call kzalloc which should be in might_sleep context, but hci_conn_add will be called in atomic context Like dev_set_name move dev_set_drvdata to work queue function. oops as following: Oct 2 17:41:59 darkstar kernel: [ 438.001341] BUG: sleeping function called from invalid context at mm/slqb.c:1546 Oct 2 17:41:59 darkstar kernel: [ 438.001345] in_atomic(): 1, irqs_disabled(): 0, pid: 2133, name: sdptool Oct 2 17:41:59 darkstar kernel: [ 438.001348] 2 locks held by sdptool/2133: Oct 2 17:41:59 darkstar kernel: [ 438.001350] #0: (sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP){+.+.+.}, at: [] lock_sock+0xa/0xc [l2cap] Oct 2 17:41:59 darkstar kernel: [ 438.001360] #1: (&hdev->lock){+.-.+.}, at: [] l2cap_sock_connect+0x103/0x26b [l2cap] Oct 2 17:41:59 darkstar kernel: [ 438.001371] Pid: 2133, comm: sdptool Not tainted 2.6.31-mm1 #2 Oct 2 17:41:59 darkstar kernel: [ 438.001373] Call Trace: Oct 2 17:41:59 darkstar kernel: [ 438.001381] [] __might_sleep+0xde/0xe5 Oct 2 17:41:59 darkstar kernel: [ 438.001386] [] __kmalloc+0x4a/0x15a Oct 2 17:41:59 darkstar kernel: [ 438.001392] [] ? kzalloc+0xb/0xd Oct 2 17:41:59 darkstar kernel: [ 438.001396] [] kzalloc+0xb/0xd Oct 2 17:41:59 darkstar kernel: [ 438.001400] [] device_private_init+0x15/0x3d Oct 2 17:41:59 darkstar kernel: [ 438.001405] [] dev_set_drvdata+0x18/0x26 Oct 2 17:41:59 darkstar kernel: [ 438.001414] [] hci_conn_init_sysfs+0x40/0xd9 [bluetooth] Oct 2 17:41:59 darkstar kernel: [ 438.001422] [] ? hci_conn_add+0x128/0x186 [bluetooth] Oct 2 17:41:59 darkstar kernel: [ 438.001429] [] hci_conn_add+0x177/0x186 [bluetooth] Oct 2 17:41:59 darkstar kernel: [ 438.001437] [] hci_connect+0x3c/0xfb [bluetooth] Oct 2 17:41:59 darkstar kernel: [ 438.001442] [] l2cap_sock_connect+0x174/0x26b [l2cap] Oct 2 17:41:59 darkstar kernel: [ 438.001448] [] sys_connect+0x60/0x7a Oct 2 17:41:59 darkstar kernel: [ 438.001453] [] ? lock_release_non_nested+0x84/0x1de Oct 2 17:41:59 darkstar kernel: [ 438.001458] [] ? might_fault+0x47/0x81 Oct 2 17:41:59 darkstar kernel: [ 438.001462] [] ? might_fault+0x47/0x81 Oct 2 17:41:59 darkstar kernel: [ 438.001468] [] ? __copy_from_user_ll+0x11/0xce Oct 2 17:41:59 darkstar kernel: [ 438.001472] [] sys_socketcall+0x82/0x17b Oct 2 17:41:59 darkstar kernel: [ 438.001477] [] syscall_call+0x7/0xb Signed-off-by: Dave Young Signed-off-by: David S. Miller --- net/bluetooth/hci_sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 7f939ce29801..2bc6f6a8de68 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -92,6 +92,8 @@ static void add_conn(struct work_struct *work) dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle); + dev_set_drvdata(&conn->dev, conn); + if (device_add(&conn->dev) < 0) { BT_ERR("Failed to register connection device"); return; @@ -144,8 +146,6 @@ void hci_conn_init_sysfs(struct hci_conn *conn) conn->dev.class = bt_class; conn->dev.parent = &hdev->dev; - dev_set_drvdata(&conn->dev, conn); - device_initialize(&conn->dev); INIT_WORK(&conn->work_add, add_conn); -- cgit v1.2.3 From 45054dc1bf2367ccb0e7c0486037907cd9395f8b Mon Sep 17 00:00:00 2001 From: Dave Young Date: Sun, 18 Oct 2009 20:28:30 +0000 Subject: bluetooth: static lock key fix When shutdown ppp connection, lockdep waring about non-static key will happen, it is caused by the lock is not initialized properly at that time. Fix with tuning the lock/skb_queue_head init order [ 94.339261] INFO: trying to register non-static key. [ 94.342509] the code is fine but needs lockdep annotation. [ 94.342509] turning off the locking correctness validator. [ 94.342509] Pid: 0, comm: swapper Not tainted 2.6.31-mm1 #2 [ 94.342509] Call Trace: [ 94.342509] [] register_lock_class+0x58/0x241 [ 94.342509] [] ? __lock_acquire+0xb57/0xb73 [ 94.342509] [] __lock_acquire+0xac/0xb73 [ 94.342509] [] ? lock_release_non_nested+0x17b/0x1de [ 94.342509] [] lock_acquire+0x67/0x84 [ 94.342509] [] ? skb_dequeue+0x15/0x41 [ 94.342509] [] _spin_lock_irqsave+0x2f/0x3f [ 94.342509] [] ? skb_dequeue+0x15/0x41 [ 94.342509] [] skb_dequeue+0x15/0x41 [ 94.342509] [] ? _read_unlock+0x1d/0x20 [ 94.342509] [] skb_queue_purge+0x14/0x1b [ 94.342509] [] l2cap_recv_frame+0xea1/0x115a [l2cap] [ 94.342509] [] ? __lock_acquire+0xb57/0xb73 [ 94.342509] [] ? mark_lock+0x1e/0x1c7 [ 94.342509] [] ? hci_rx_task+0xd2/0x1bc [bluetooth] [ 94.342509] [] l2cap_recv_acldata+0xb1/0x1c6 [l2cap] [ 94.342509] [] hci_rx_task+0x106/0x1bc [bluetooth] [ 94.342509] [] ? l2cap_recv_acldata+0x0/0x1c6 [l2cap] [ 94.342509] [] tasklet_action+0x69/0xc1 [ 94.342509] [] __do_softirq+0x94/0x11e [ 94.342509] [] do_softirq+0x36/0x5a [ 94.342509] [] irq_exit+0x35/0x68 [ 94.342509] [] do_IRQ+0x72/0x89 [ 94.342509] [] common_interrupt+0x2e/0x34 [ 94.342509] [] ? pm_qos_add_requirement+0x63/0x9d [ 94.342509] [] ? acpi_idle_enter_bm+0x209/0x238 [ 94.342509] [] cpuidle_idle_call+0x5c/0x94 [ 94.342509] [] cpu_idle+0x4e/0x6f [ 94.342509] [] rest_init+0x53/0x55 [ 94.342509] [] start_kernel+0x2f0/0x2f5 [ 94.342509] [] i386_start_kernel+0x91/0x96 Reported-by: Oliver Hartkopp Signed-off-by: Dave Young Tested-by: Oliver Hartkopp Signed-off-by: David S. Miller --- net/bluetooth/l2cap.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 555d9da1869b..77e9fb130adb 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -555,12 +555,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) conn->feat_mask = 0; - setup_timer(&conn->info_timer, l2cap_info_timeout, - (unsigned long) conn); - spin_lock_init(&conn->lock); rwlock_init(&conn->chan_list.lock); + setup_timer(&conn->info_timer, l2cap_info_timeout, + (unsigned long) conn); + conn->disc_reason = 0x13; return conn; @@ -783,6 +783,9 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) /* Default config options */ pi->conf_len = 0; pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; + skb_queue_head_init(TX_QUEUE(sk)); + skb_queue_head_init(SREJ_QUEUE(sk)); + INIT_LIST_HEAD(SREJ_LIST(sk)); } static struct proto l2cap_proto = { -- cgit v1.2.3 From 55b8050353c4a212c94d7156e2bd5885225b869b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 19 Oct 2009 06:41:58 +0000 Subject: net: Fix IP_MULTICAST_IF ipv4/ipv6 setsockopt(IP_MULTICAST_IF) have dubious __dev_get_by_index() calls. This function should be called only with RTNL or dev_base_lock held, or reader could see a corrupt hash chain and eventually enter an endless loop. Fix is to call dev_get_by_index()/dev_put(). If this happens to be performance critical, we could define a new dev_exist_by_index() function to avoid touching dev refcount. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/ip_sockglue.c | 7 +++---- net/ipv6/ipv6_sockglue.c | 6 +++++- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 0c0b6e363a20..e982b5c1ee17 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -634,17 +634,16 @@ static int do_ip_setsockopt(struct sock *sk, int level, break; } dev = ip_dev_find(sock_net(sk), mreq.imr_address.s_addr); - if (dev) { + if (dev) mreq.imr_ifindex = dev->ifindex; - dev_put(dev); - } } else - dev = __dev_get_by_index(sock_net(sk), mreq.imr_ifindex); + dev = dev_get_by_index(sock_net(sk), mreq.imr_ifindex); err = -EADDRNOTAVAIL; if (!dev) break; + dev_put(dev); err = -EINVAL; if (sk->sk_bound_dev_if && diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 14f54eb5a7fc..4f7aaf6996a3 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -496,13 +496,17 @@ done: goto e_inval; if (val) { + struct net_device *dev; + if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) goto e_inval; - if (__dev_get_by_index(net, val) == NULL) { + dev = dev_get_by_index(net, val); + if (!dev) { retv = -ENODEV; break; } + dev_put(dev); } np->mcast_oif = val; retv = 0; -- cgit v1.2.3 From b6b39e8f3fbbb31001b836afec87bcaf4811a7bf Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 19 Oct 2009 19:41:06 +0000 Subject: tcp: Try to catch MSG_PEEK bug This patch tries to print out more information when we hit the MSG_PEEK bug in tcp_recvmsg. It's been around since at least 2005 and it's about time that we finally fix it. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 9b2756fbdf9b..90b2e0649bfb 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1442,7 +1442,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, goto found_ok_skb; if (tcp_hdr(skb)->fin) goto found_fin_ok; - WARN_ON(!(flags & MSG_PEEK)); + if (WARN_ON(!(flags & MSG_PEEK))) + printk(KERN_INFO "recvmsg bug 2: copied %X " + "seq %X\n", *seq, TCP_SKB_CB(skb)->seq); } /* Well, if we have backlog, try to process it now yet. */ -- cgit v1.2.3 From e95646c3ec33c8ec0693992da4332a6b32eb7e31 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 30 Sep 2009 11:17:21 +0200 Subject: virtio: let header files include virtio_ids.h Rusty, commit 3ca4f5ca73057a617f9444a91022d7127041970a virtio: add virtio IDs file moved all device IDs into a single file. While the change itself is a very good one, it can break userspace applications. For example if a userspace tool wanted to get the ID of virtio_net it used to include virtio_net.h. This does no longer work, since virtio_net.h does not include virtio_ids.h. This patch moves all "#include " from the C files into the header files, making the header files compatible with the old ones. In addition, this patch exports virtio_ids.h to userspace. CC: Fernando Luis Vazquez Cao Signed-off-by: Christian Borntraeger Signed-off-by: Rusty Russell --- net/9p/trans_virtio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index b2e07f0dd298..ea1e3daabefe 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #define VIRTQUEUE_NUM 128 -- cgit v1.2.3 From c62f4c453ab4b0240ab857bfd089da2c01ad91e7 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Thu, 22 Oct 2009 21:37:56 -0700 Subject: net: use WARN() for the WARN_ON in commit b6b39e8f3fbbb Commit b6b39e8f3fbbb (tcp: Try to catch MSG_PEEK bug) added a printk() to the WARN_ON() that's in tcp.c. This patch changes this combination to WARN(); the advantage of WARN() is that the printk message shows up inside the message, so that kerneloops.org will collect the message. In addition, this gets rid of an extra if() statement. Signed-off-by: Arjan van de Ven Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 90b2e0649bfb..98440ad82558 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1442,9 +1442,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, goto found_ok_skb; if (tcp_hdr(skb)->fin) goto found_fin_ok; - if (WARN_ON(!(flags & MSG_PEEK))) - printk(KERN_INFO "recvmsg bug 2: copied %X " - "seq %X\n", *seq, TCP_SKB_CB(skb)->seq); + WARN(!(flags & MSG_PEEK), KERN_INFO "recvmsg bug 2: " + "copied %X seq %X\n", *seq, + TCP_SKB_CB(skb)->seq); } /* Well, if we have backlog, try to process it now yet. */ -- cgit v1.2.3 From 66ed1e5ec1d979e572554643063734a7664261bb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 24 Oct 2009 06:55:20 -0700 Subject: pktgen: Dont leak kernel memory While playing with pktgen, I realized IP ID was not filled and a random value was taken, possibly leaking 2 bytes of kernel memory. We can use an increasing ID, this can help diagnostics anyway. Also clear packet payload, instead of leaking kernel memory. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/pktgen.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 86acdba0a97d..6eb8d47cbf3a 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -335,6 +335,7 @@ struct pktgen_dev { __u32 cur_src_mac_offset; __be32 cur_saddr; __be32 cur_daddr; + __u16 ip_id; __u16 cur_udp_dst; __u16 cur_udp_src; __u16 cur_queue_map; @@ -2630,6 +2631,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, iph->protocol = IPPROTO_UDP; /* UDP */ iph->saddr = pkt_dev->cur_saddr; iph->daddr = pkt_dev->cur_daddr; + iph->id = htons(pkt_dev->ip_id); + pkt_dev->ip_id++; iph->frag_off = 0; iplen = 20 + 8 + datalen; iph->tot_len = htons(iplen); @@ -2641,24 +2644,26 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev, skb->dev = odev; skb->pkt_type = PACKET_HOST; - if (pkt_dev->nfrags <= 0) + if (pkt_dev->nfrags <= 0) { pgh = (struct pktgen_hdr *)skb_put(skb, datalen); - else { + memset(pgh + 1, 0, datalen - sizeof(struct pktgen_hdr)); + } else { int frags = pkt_dev->nfrags; - int i; + int i, len; pgh = (struct pktgen_hdr *)(((char *)(udph)) + 8); if (frags > MAX_SKB_FRAGS) frags = MAX_SKB_FRAGS; if (datalen > frags * PAGE_SIZE) { - skb_put(skb, datalen - frags * PAGE_SIZE); + len = datalen - frags * PAGE_SIZE; + memset(skb_put(skb, len), 0, len); datalen = frags * PAGE_SIZE; } i = 0; while (datalen > 0) { - struct page *page = alloc_pages(GFP_KERNEL, 0); + struct page *page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0); skb_shinfo(skb)->frags[i].page = page; skb_shinfo(skb)->frags[i].page_offset = 0; skb_shinfo(skb)->frags[i].size = -- cgit v1.2.3 From d419b9f0fa69e79ccba3e5e79a58a52ae0c2ed6a Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Mon, 19 Oct 2009 14:55:37 -0700 Subject: mac80211: fix ibss joining Recent commit "mac80211: fix logic error ibss merge bssid check" fixed joining of ibss cell when static bssid is provided. In this case ifibss->bssid is set before the cell is joined and comparing that address to a bss should thus always succeed. Unfortunately this change broke the other case of joining a ibss cell without providing a static bssid where the value of ifibss->bssid is not set before the cell is joined. Since ifibss->bssid may be set before or after joining the cell we do not learn anything by comparing it to a known bss. Remove this check. Signed-off-by: Reinette Chatre Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 6eaf69823439..ca8ecce31d34 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -538,13 +538,12 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) WLAN_CAPABILITY_PRIVACY, capability); + if (bss) { #ifdef CONFIG_MAC80211_IBSS_DEBUG - if (bss) printk(KERN_DEBUG " sta_find_ibss: selected %pM current " "%pM\n", bss->cbss.bssid, ifibss->bssid); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ - if (bss && !memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) { printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" " based on configured SSID\n", sdata->dev->name, bss->cbss.bssid); @@ -552,8 +551,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) ieee80211_sta_join_ibss(sdata, bss); ieee80211_rx_bss_put(local, bss); return; - } else if (bss) - ieee80211_rx_bss_put(local, bss); + } #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG " did not try to join ibss\n"); -- cgit v1.2.3 From 2ef6e4440926668cfa9eac4b79e63528ebcbe0c1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Oct 2009 15:08:12 +0900 Subject: mac80211: keep auth state when assoc fails When association fails, we should stay authenticated, which in mac80211 is represented by the existence of the mlme work struct, so we cannot free that, instead we need to just set it to idle. (Brought to you by the hacking session at Kernel Summit 2009 in Tokyo, Japan. -- JWL) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 8d26e9bf8964..dc5049d58c51 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1457,8 +1457,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (status_code != WLAN_STATUS_SUCCESS) { printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", sdata->dev->name, status_code); - list_del(&wk->list); - kfree(wk); + wk->state = IEEE80211_MGD_STATE_IDLE; return RX_MGMT_CFG80211_ASSOC; } -- cgit v1.2.3 From 7d930bc33653d5592dc386a76a38f39c2e962344 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 20 Oct 2009 15:08:53 +0900 Subject: cfg80211: sme: deauthenticate on assoc failure When the in-kernel SME gets an association failure from the AP we don't deauthenticate, and thus get into a very confused state which will lead to warnings later on. Fix this by actually deauthenticating when the AP indicates an association failure. (Brought to you by the hacking session at Kernel Summit 2009 in Tokyo, Japan. -- JWL) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/core.h | 1 + net/wireless/mlme.c | 9 +++++++++ net/wireless/sme.c | 21 +++++++++++++++++++-- 3 files changed, 29 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/wireless/core.h b/net/wireless/core.h index 2a33d8bc886b..68b321997d4c 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -358,6 +358,7 @@ int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); void cfg80211_conn_work(struct work_struct *work); +void cfg80211_sme_failed_assoc(struct wireless_dev *wdev); bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev); /* internal helpers */ diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 79d2eec54cec..0a6b7a0eca6b 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -62,6 +62,7 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) u8 *ie = mgmt->u.assoc_resp.variable; int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); struct cfg80211_internal_bss *bss = NULL; + bool need_connect_result = true; wdev_lock(wdev); @@ -94,6 +95,14 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) } WARN_ON(!bss); + } else if (wdev->conn) { + cfg80211_sme_failed_assoc(wdev); + need_connect_result = false; + /* + * do not call connect_result() now because the + * sme will schedule work that does it later. + */ + goto out; } if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) { diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 93c3ed329204..ece378d531ef 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -26,6 +26,7 @@ struct cfg80211_conn { CFG80211_CONN_AUTHENTICATING, CFG80211_CONN_ASSOCIATE_NEXT, CFG80211_CONN_ASSOCIATING, + CFG80211_CONN_DEAUTH_ASSOC_FAIL, } state; u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; u8 *ie; @@ -148,6 +149,12 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev) NULL, 0, WLAN_REASON_DEAUTH_LEAVING); return err; + case CFG80211_CONN_DEAUTH_ASSOC_FAIL: + __cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid, + NULL, 0, + WLAN_REASON_DEAUTH_LEAVING); + /* return an error so that we call __cfg80211_connect_result() */ + return -EINVAL; default: return 0; } @@ -158,6 +165,7 @@ void cfg80211_conn_work(struct work_struct *work) struct cfg80211_registered_device *rdev = container_of(work, struct cfg80211_registered_device, conn_work); struct wireless_dev *wdev; + u8 bssid[ETH_ALEN]; rtnl_lock(); cfg80211_lock_rdev(rdev); @@ -173,10 +181,10 @@ void cfg80211_conn_work(struct work_struct *work) wdev_unlock(wdev); continue; } + memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN); if (cfg80211_conn_do_work(wdev)) __cfg80211_connect_result( - wdev->netdev, - wdev->conn->params.bssid, + wdev->netdev, bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, false, NULL); @@ -337,6 +345,15 @@ bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev) return true; } +void cfg80211_sme_failed_assoc(struct wireless_dev *wdev) +{ + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + wdev->conn->state = CFG80211_CONN_DEAUTH_ASSOC_FAIL; + schedule_work(&rdev->conn_work); +} + void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, const u8 *req_ie, size_t req_ie_len, const u8 *resp_ie, size_t resp_ie_len, -- cgit v1.2.3 From f99288d1761fb3b0decb0fdc4d746406addd29d5 Mon Sep 17 00:00:00 2001 From: Andrey Yurovsky Date: Tue, 20 Oct 2009 12:17:34 -0700 Subject: mac80211: trivial: fix spelling in mesh_hwmp Fix a typo in the description of hwmp_route_info_get(), no function changes. Signed-off-by: Andrey Yurovsky Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index e12a786e26b8..29b82e98effa 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -259,7 +259,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, * @hwmp_ie: hwmp information element (PREP or PREQ) * * This function updates the path routing information to the originator and the - * transmitter of a HWMP PREQ or PREP fram. + * transmitter of a HWMP PREQ or PREP frame. * * Returns: metric to frame originator or 0 if the frame should not be further * processed -- cgit v1.2.3 From 9b1ce526eb917c8b5c8497c327768130ee683392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Smedman?= Date: Sat, 24 Oct 2009 20:55:09 +0200 Subject: mac80211: fix for incorrect sequence number on hostapd injected frames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When hostapd injects a frame, e.g. an authentication or association response, mac80211 looks for a suitable access point virtual interface to associate the frame with based on its source address. This makes it possible e.g. to correctly assign sequence numbers to the frames. A small typo in the ethernet address comparison statement caused a failure to find a suitable ap interface. Sequence numbers on such frames where therefore left unassigned causing some clients (especially windows-based 11b/g clients) to reject them and fail to authenticate or associate with the access point. This patch fixes the typo in the address comparison statement. Signed-off-by: Björn Smedman Reviewed-by: Johannes Berg Cc: stable@kernel.org Signed-off-by: John W. Linville --- net/mac80211/tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index db4bda681ec9..eaa4118de988 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1445,7 +1445,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, if (tmp_sdata->vif.type != NL80211_IFTYPE_AP) continue; if (compare_ether_addr(tmp_sdata->dev->dev_addr, - hdr->addr2)) { + hdr->addr2) == 0) { dev_hold(tmp_sdata->dev); dev_put(sdata->dev); sdata = tmp_sdata; -- cgit v1.2.3 From 55888dfb6ba7e318bb3d6a44d25009906206bf6a Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Wed, 28 Oct 2009 08:59:47 +0000 Subject: AF_RAW: Augment raw_send_hdrinc to expand skb to fit iphdr->ihl (v2) Augment raw_send_hdrinc to correct for incorrect ip header length values A series of oopses was reported to me recently. Apparently when using AF_RAW sockets to send data to peers that were reachable via ipsec encapsulation, people could panic or BUG halt their systems. I've tracked the problem down to user space sending an invalid ip header over an AF_RAW socket with IP_HDRINCL set to 1. Basically what happens is that userspace sends down an ip frame that includes only the header (no data), but sets the ip header ihl value to a large number, one that is larger than the total amount of data passed to the sendmsg call. In raw_send_hdrincl, we allocate an skb based on the size of the data in the msghdr that was passed in, but assume the data is all valid. Later during ipsec encapsulation, xfrm4_tranport_output moves the entire frame back in the skbuff to provide headroom for the ipsec headers. During this operation, the skb->transport_header is repointed to a spot computed by skb->network_header + the ip header length (ihl). Since so little data was passed in relative to the value of ihl provided by the raw socket, we point transport header to an unknown location, resulting in various crashes. This fix for this is pretty straightforward, simply validate the value of of iph->ihl when sending over a raw socket. If (iph->ihl*4U) > user data buffer size, drop the frame and return -EINVAL. I just confirmed this fixes the reported crashes. Signed-off-by: Neil Horman Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/raw.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 757c9171e7c2..ab996f9c0fe0 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -352,13 +352,24 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, skb->ip_summed = CHECKSUM_NONE; skb->transport_header = skb->network_header; - err = memcpy_fromiovecend((void *)iph, from, 0, length); - if (err) - goto error_fault; + err = -EFAULT; + if (memcpy_fromiovecend((void *)iph, from, 0, length)) + goto error_free; - /* We don't modify invalid header */ iphlen = iph->ihl * 4; - if (iphlen >= sizeof(*iph) && iphlen <= length) { + + /* + * We don't want to modify the ip header, but we do need to + * be sure that it won't cause problems later along the network + * stack. Specifically we want to make sure that iph->ihl is a + * sane value. If ihl points beyond the length of the buffer passed + * in, reject the frame as invalid + */ + err = -EINVAL; + if (iphlen > length) + goto error_free; + + if (iphlen >= sizeof(*iph)) { if (!iph->saddr) iph->saddr = rt->rt_src; iph->check = 0; @@ -381,8 +392,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, out: return 0; -error_fault: - err = -EFAULT; +error_free: kfree_skb(skb); error: IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); -- cgit v1.2.3 From b5dd884e682cae6b8c037f9d11f3b623b4cf2011 Mon Sep 17 00:00:00 2001 From: Gabor Gombas Date: Thu, 29 Oct 2009 03:19:11 -0700 Subject: net: Fix 'Re: PACKET_TX_RING: packet size is too long' Currently PACKET_TX_RING forces certain amount of every frame to remain unused. This probably originates from an early version of the PACKET_TX_RING patch that in fact used the extra space when the (since removed) CONFIG_PACKET_MMAP_ZERO_COPY option was enabled. The current code does not make any use of this extra space. This patch removes the extra space reservation and lets userspace make use of the full frame size. Signed-off-by: Gabor Gombas Signed-off-by: David S. Miller --- net/packet/af_packet.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'net') diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 1238949e66a9..48b18dad6763 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -982,10 +982,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) goto out_put; size_max = po->tx_ring.frame_size - - sizeof(struct skb_shared_info) - - po->tp_hdrlen - - LL_ALLOCATED_SPACE(dev) - - sizeof(struct sockaddr_ll); + - (po->tp_hdrlen - sizeof(struct sockaddr_ll)); if (size_max > dev->mtu + reserve) size_max = dev->mtu + reserve; -- cgit v1.2.3 From b0c110ca8e89f2c9cd52ec7fb1b98c5b7aa78496 Mon Sep 17 00:00:00 2001 From: jamal Date: Sun, 18 Oct 2009 02:12:33 +0000 Subject: net: Fix RPF to work with policy routing Policy routing is not looked up by mark on reverse path filtering. This fixes it. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/ipv4/fib_frontend.c | 5 ++++- net/ipv4/route.c | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index e2f950592566..aa00398be80e 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -229,14 +229,17 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, */ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, - struct net_device *dev, __be32 *spec_dst, u32 *itag) + struct net_device *dev, __be32 *spec_dst, + u32 *itag, u32 mark) { struct in_device *in_dev; struct flowi fl = { .nl_u = { .ip4_u = { .daddr = src, .saddr = dst, .tos = tos } }, + .mark = mark, .iif = oif }; + struct fib_result res; int no_addr, rpf; int ret; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index bb4199252026..5b1050a5d874 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1854,7 +1854,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, goto e_inval; spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); } else if (fib_validate_source(saddr, 0, tos, 0, - dev, &spec_dst, &itag) < 0) + dev, &spec_dst, &itag, 0) < 0) goto e_inval; rth = dst_alloc(&ipv4_dst_ops); @@ -1967,7 +1967,7 @@ static int __mkroute_input(struct sk_buff *skb, err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res), - in_dev->dev, &spec_dst, &itag); + in_dev->dev, &spec_dst, &itag, skb->mark); if (err < 0) { ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr, saddr); @@ -2141,7 +2141,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, int result; result = fib_validate_source(saddr, daddr, tos, net->loopback_dev->ifindex, - dev, &spec_dst, &itag); + dev, &spec_dst, &itag, skb->mark); if (result < 0) goto martian_source; if (result) @@ -2170,7 +2170,7 @@ brd_input: spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); else { err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, - &itag); + &itag, skb->mark); if (err < 0) goto martian_source; if (err) -- cgit v1.2.3 From 9d410c796067686b1e032d54ce475b7055537138 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 30 Oct 2009 05:03:53 +0000 Subject: net: fix sk_forward_alloc corruption On UDP sockets, we must call skb_free_datagram() with socket locked, or risk sk_forward_alloc corruption. This requirement is not respected in SUNRPC. Add a convenient helper, skb_free_datagram_locked() and use it in SUNRPC Reported-by: Francis Moreau Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/datagram.c | 10 +++++++++- net/ipv4/udp.c | 4 +--- net/ipv6/udp.c | 4 +--- net/sunrpc/svcsock.c | 10 +++++----- 4 files changed, 16 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/core/datagram.c b/net/core/datagram.c index 1c6cf3a1a4f6..4ade3011bb3c 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -224,6 +224,15 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb) consume_skb(skb); sk_mem_reclaim_partial(sk); } +EXPORT_SYMBOL(skb_free_datagram); + +void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb) +{ + lock_sock(sk); + skb_free_datagram(sk, skb); + release_sock(sk); +} +EXPORT_SYMBOL(skb_free_datagram_locked); /** * skb_kill_datagram - Free a datagram skbuff forcibly @@ -752,5 +761,4 @@ unsigned int datagram_poll(struct file *file, struct socket *sock, EXPORT_SYMBOL(datagram_poll); EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec); EXPORT_SYMBOL(skb_copy_datagram_iovec); -EXPORT_SYMBOL(skb_free_datagram); EXPORT_SYMBOL(skb_recv_datagram); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d0d436d6216c..0fa9f70e4b19 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -999,9 +999,7 @@ try_again: err = ulen; out_free: - lock_sock(sk); - skb_free_datagram(sk, skb); - release_sock(sk); + skb_free_datagram_locked(sk, skb); out: return err; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 3a60f12b34ed..cf538ed5ef6a 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -288,9 +288,7 @@ try_again: err = ulen; out_free: - lock_sock(sk); - skb_free_datagram(sk, skb); - release_sock(sk); + skb_free_datagram_locked(sk, skb); out: return err; diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index ccc5e83cae5d..1c246a4f491e 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -111,7 +111,7 @@ static void svc_release_skb(struct svc_rqst *rqstp) rqstp->rq_xprt_ctxt = NULL; dprintk("svc: service %p, releasing skb %p\n", rqstp, skb); - skb_free_datagram(svsk->sk_sk, skb); + skb_free_datagram_locked(svsk->sk_sk, skb); } } @@ -578,7 +578,7 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) "svc: received unknown control message %d/%d; " "dropping RPC reply datagram\n", cmh->cmsg_level, cmh->cmsg_type); - skb_free_datagram(svsk->sk_sk, skb); + skb_free_datagram_locked(svsk->sk_sk, skb); return 0; } @@ -588,18 +588,18 @@ static int svc_udp_recvfrom(struct svc_rqst *rqstp) if (csum_partial_copy_to_xdr(&rqstp->rq_arg, skb)) { local_bh_enable(); /* checksum error */ - skb_free_datagram(svsk->sk_sk, skb); + skb_free_datagram_locked(svsk->sk_sk, skb); return 0; } local_bh_enable(); - skb_free_datagram(svsk->sk_sk, skb); + skb_free_datagram_locked(svsk->sk_sk, skb); } else { /* we can use it in-place */ rqstp->rq_arg.head[0].iov_base = skb->data + sizeof(struct udphdr); rqstp->rq_arg.head[0].iov_len = len; if (skb_checksum_complete(skb)) { - skb_free_datagram(svsk->sk_sk, skb); + skb_free_datagram_locked(svsk->sk_sk, skb); return 0; } rqstp->rq_xprt_ctxt = skb; -- cgit v1.2.3 From 2e9526b352061ee0fd2a1580a2e3a5af960dabc4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 30 Oct 2009 05:51:48 +0000 Subject: gre: Fix dev_addr clobbering for gretap Nathan Neulinger noticed that gretap devices get their MAC address from the local IP address, which results in invalid MAC addresses half of the time. This is because gretap is still using the tunnel netdev ops rather than the correct tap netdev ops struct. This patch also fixes changelink to not clobber the MAC address for the gretap case. Signed-off-by: Herbert Xu Acked-by: Stephen Hemminger Tested-by: Nathan Neulinger Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 41ada9904d31..143333852624 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1464,7 +1464,7 @@ static void ipgre_tap_setup(struct net_device *dev) ether_setup(dev); - dev->netdev_ops = &ipgre_netdev_ops; + dev->netdev_ops = &ipgre_tap_netdev_ops; dev->destructor = free_netdev; dev->iflink = 0; @@ -1525,25 +1525,29 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[], if (t->dev != dev) return -EEXIST; } else { - unsigned nflags = 0; - t = nt; - if (ipv4_is_multicast(p.iph.daddr)) - nflags = IFF_BROADCAST; - else if (p.iph.daddr) - nflags = IFF_POINTOPOINT; + if (dev->type != ARPHRD_ETHER) { + unsigned nflags = 0; - if ((dev->flags ^ nflags) & - (IFF_POINTOPOINT | IFF_BROADCAST)) - return -EINVAL; + if (ipv4_is_multicast(p.iph.daddr)) + nflags = IFF_BROADCAST; + else if (p.iph.daddr) + nflags = IFF_POINTOPOINT; + + if ((dev->flags ^ nflags) & + (IFF_POINTOPOINT | IFF_BROADCAST)) + return -EINVAL; + } ipgre_tunnel_unlink(ign, t); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; t->parms.i_key = p.i_key; - memcpy(dev->dev_addr, &p.iph.saddr, 4); - memcpy(dev->broadcast, &p.iph.daddr, 4); + if (dev->type != ARPHRD_ETHER) { + memcpy(dev->dev_addr, &p.iph.saddr, 4); + memcpy(dev->broadcast, &p.iph.daddr, 4); + } ipgre_tunnel_link(ign, t); netdev_state_change(dev); } -- cgit v1.2.3 From f446d10f214091408b7300f15c9adf60569edf28 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 28 Oct 2009 15:12:32 +0100 Subject: mac80211: fix BSS leak The IBSS code leaks a BSS struct after telling cfg80211 about a given BSS by passing a frame. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ibss.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index ca8ecce31d34..f1362f32c17d 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -73,6 +73,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt; u8 *pos; struct ieee80211_supported_band *sband; + struct cfg80211_bss *bss; u32 bss_change; u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; @@ -177,8 +178,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, mod_timer(&ifibss->timer, round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); - cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel, - mgmt, skb->len, 0, GFP_KERNEL); + bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel, + mgmt, skb->len, 0, GFP_KERNEL); + cfg80211_put_bss(bss); cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL); } -- cgit v1.2.3 From 2171abc58644e09dbba546d91366b12743115396 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Oct 2009 08:34:00 +0100 Subject: mac80211: fix addba timer The addba timer function acquires the sta spinlock, but at the same time we try to del_timer_sync() it under the spinlock which can produce deadlocks. To fix this, always del_timer_sync() the timer in ieee80211_process_addba_resp() and add it again after checking the conditions, if necessary. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index bd765f30dba2..b09948ceec4a 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -666,26 +666,25 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, state = &sta->ampdu_mlme.tid_state_tx[tid]; + del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); + spin_lock_bh(&sta->lock); - if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - spin_unlock_bh(&sta->lock); - return; - } + if (!(*state & HT_ADDBA_REQUESTED_MSK)) + goto timer_still_needed; if (mgmt->u.action.u.addba_resp.dialog_token != sta->ampdu_mlme.tid_tx[tid]->dialog_token) { - spin_unlock_bh(&sta->lock); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - return; + goto timer_still_needed; } - del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ + if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) == WLAN_STATUS_SUCCESS) { u8 curstate = *state; @@ -699,5 +698,11 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, } else { ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); } + + goto out; + + timer_still_needed: + add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); + out: spin_unlock_bh(&sta->lock); } -- cgit v1.2.3 From 372362ade2fe5c33d749e017f1c5bc8140769a3e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 29 Oct 2009 10:09:28 +0100 Subject: mac80211: fix reason code output endianness When HT debugging is enabled and we receive a DelBA frame we print out the reason code in the wrong byte order. Fix that so we don't get weird values printed. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ht.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 0891bfb06996..48ef1a282b91 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -153,7 +153,7 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, if (net_ratelimit()) printk(KERN_DEBUG "delba from %pM (%s) tid %d reason code %d\n", mgmt->sa, initiator ? "initiator" : "recipient", tid, - mgmt->u.action.u.delba.reason_code); + le16_to_cpu(mgmt->u.action.u.delba.reason_code)); #endif /* CONFIG_MAC80211_HT_DEBUG */ if (initiator == WLAN_BACK_INITIATOR) -- cgit v1.2.3 From 3e2796a90cf349527e50b3bc4d0b2f4019b1ce7a Mon Sep 17 00:00:00 2001 From: Eric Van Hensbergen Date: Mon, 2 Nov 2009 08:39:28 -0600 Subject: 9p: fix readdir corner cases The patch below also addresses a couple of other corner cases in readdir seen with a large (e.g. 64k) msize. I'm not sure what people think of my co-opting of fid->aux here. I'd be happy to rework if there's a better way. When the size of the user supplied buffer passed to readdir is smaller than the data returned in one go by the 9P read request, v9fs_dir_readdir() currently discards extra data so that, on the next call, a 9P read request will be issued with offset < previous offset + bytes returned, which voilates the constraint described in paragraph 3 of read(5) description. This patch preseves the leftover data in fid->aux for use in the next call. Signed-off-by: Jim Garlick Signed-off-by: Eric Van Hensbergen --- net/9p/client.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/9p/client.c b/net/9p/client.c index 5bf5f227dbe0..8af95b2dddd6 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -582,11 +582,9 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt) memset(&fid->qid, 0, sizeof(struct p9_qid)); fid->mode = -1; - fid->rdir_fpos = 0; fid->uid = current_fsuid(); fid->clnt = clnt; - fid->aux = NULL; - + fid->rdir = NULL; spin_lock_irqsave(&clnt->lock, flags); list_add(&fid->flist, &clnt->fidlist); spin_unlock_irqrestore(&clnt->lock, flags); @@ -609,6 +607,7 @@ static void p9_fid_destroy(struct p9_fid *fid) spin_lock_irqsave(&clnt->lock, flags); list_del(&fid->flist); spin_unlock_irqrestore(&clnt->lock, flags); + kfree(fid->rdir); kfree(fid); } -- cgit v1.2.3 From 7400f42e9d765fa0656b432f3ab1245f9710f190 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 31 Oct 2009 07:40:37 +0100 Subject: cfg80211: fix NULL ptr deref commit 211a4d12abf86fe0df4cd68fc6327cbb58f56f81 Author: Johannes Berg Date: Tue Oct 20 15:08:53 2009 +0900 cfg80211: sme: deauthenticate on assoc failure introduced a potential NULL pointer dereference that some people have been hitting for some reason -- the params.bssid pointer is not guaranteed to be non-NULL for what seems to be a race between various ways of reaching the same thing. While I'm trying to analyse the problem more let's first fix the crash. I think the real fix may be to avoid doing _anything_ if it ended up being NULL, but right now I'm not sure yet. I think http://bugzilla.kernel.org/show_bug.cgi?id=14342 might also be this issue. Reported-by: Parag Warudkar Tested-by: Parag Warudkar Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/sme.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/wireless/sme.c b/net/wireless/sme.c index ece378d531ef..9f0b2800a9d7 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -165,7 +165,7 @@ void cfg80211_conn_work(struct work_struct *work) struct cfg80211_registered_device *rdev = container_of(work, struct cfg80211_registered_device, conn_work); struct wireless_dev *wdev; - u8 bssid[ETH_ALEN]; + u8 bssid_buf[ETH_ALEN], *bssid = NULL; rtnl_lock(); cfg80211_lock_rdev(rdev); @@ -181,7 +181,10 @@ void cfg80211_conn_work(struct work_struct *work) wdev_unlock(wdev); continue; } - memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN); + if (wdev->conn->params.bssid) { + memcpy(bssid_buf, wdev->conn->params.bssid, ETH_ALEN); + bssid = bssid_buf; + } if (cfg80211_conn_do_work(wdev)) __cfg80211_connect_result( wdev->netdev, bssid, -- cgit v1.2.3 From c1f9a764cf47686b1f5a0cf87ada68d90056136a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 1 Nov 2009 19:25:40 +0100 Subject: mac80211: check interface is down before type change For some strange reason the netif_running() check ended up after the actual type change instead of before, potentially causing all kinds of problems if the interface is up while changing the type; one of the problems manifests itself as a warning: WARNING: at net/mac80211/iface.c:651 ieee80211_teardown_sdata+0xda/0x1a0 [mac80211]() Hardware name: Aspire one Pid: 2596, comm: wpa_supplicant Tainted: G W 2.6.31-10-generic #32-Ubuntu Call Trace: [] warn_slowpath_common+0x6d/0xa0 [] warn_slowpath_null+0x15/0x20 [] ieee80211_teardown_sdata+0xda/0x1a0 [mac80211] [] ieee80211_if_change_type+0x4a/0xc0 [mac80211] [] ieee80211_change_iface+0x61/0xa0 [mac80211] [] cfg80211_wext_siwmode+0xc7/0x120 [cfg80211] [] ioctl_standard_call+0x58/0xf0 (http://www.kerneloops.org/searchweek.php?search=ieee80211_teardown_sdata) Cc: Arjan van de Ven Cc: stable@kernel.org Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5608f6c68413..7b5131bd6fa1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -72,6 +72,9 @@ static int ieee80211_change_iface(struct wiphy *wiphy, struct ieee80211_sub_if_data *sdata; int ret; + if (netif_running(dev)) + return -EBUSY; + if (!nl80211_type_check(type)) return -EINVAL; @@ -81,9 +84,6 @@ static int ieee80211_change_iface(struct wiphy *wiphy, if (ret) return ret; - if (netif_running(sdata->dev)) - return -EBUSY; - if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) ieee80211_sdata_set_mesh_id(sdata, params->mesh_id_len, -- cgit v1.2.3 From 1056bd51674e529813213186471bb4ac6689a755 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Nov 2009 20:46:52 -0800 Subject: bridge: prevent bridging wrong device The bridge code assumes ethernet addressing, so be more strict in the what is allowed. This showed up when GRE had a bug and was not using correct address format. Add some more comments for increased clarity. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_if.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index b1b3b0fbf41c..4a9f52732655 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -377,12 +377,16 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) struct net_bridge_port *p; int err = 0; - if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER) + /* Don't allow bridging non-ethernet like devices */ + if ((dev->flags & IFF_LOOPBACK) || + dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN) return -EINVAL; + /* No bridging of bridges */ if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) return -ELOOP; + /* Device is already being bridged */ if (dev->br_port != NULL) return -EBUSY; -- cgit v1.2.3 From b4ec824021493ba6cb7eeb61572f4d2f8a80a52e Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Nov 2009 20:56:07 -0800 Subject: rose: device refcount leak While hunting dev_put() for net-next-2.6, I found a device refcount leak in ROSE, ioctl(SIOCADDRT) error path. Fix is to not touch device refcount, as we hold RTNL Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/rose/rose_route.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c index 9478d9b3d977..f3e21989b88c 100644 --- a/net/rose/rose_route.c +++ b/net/rose/rose_route.c @@ -578,18 +578,18 @@ static int rose_clear_routes(void) /* * Check that the device given is a valid AX.25 interface that is "up". + * called whith RTNL */ -static struct net_device *rose_ax25_dev_get(char *devname) +static struct net_device *rose_ax25_dev_find(char *devname) { struct net_device *dev; - if ((dev = dev_get_by_name(&init_net, devname)) == NULL) + if ((dev = __dev_get_by_name(&init_net, devname)) == NULL) return NULL; if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) return dev; - dev_put(dev); return NULL; } @@ -720,27 +720,23 @@ int rose_rt_ioctl(unsigned int cmd, void __user *arg) case SIOCADDRT: if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) return -EFAULT; - if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) + if ((dev = rose_ax25_dev_find(rose_route.device)) == NULL) return -EINVAL; - if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */ - dev_put(dev); + if (rose_dev_exists(&rose_route.address)) /* Can't add routes to ourself */ return -EINVAL; - } if (rose_route.mask > 10) /* Mask can't be more than 10 digits */ return -EINVAL; if (rose_route.ndigis > AX25_MAX_DIGIS) return -EINVAL; err = rose_add_node(&rose_route, dev); - dev_put(dev); return err; case SIOCDELRT: if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct))) return -EFAULT; - if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL) + if ((dev = rose_ax25_dev_find(rose_route.device)) == NULL) return -EINVAL; err = rose_del_node(&rose_route, dev); - dev_put(dev); return err; case SIOCRSCLRRT: -- cgit v1.2.3 From f9dd09c7f7199685601d75882447a6598be8a3e0 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Fri, 6 Nov 2009 00:43:42 -0800 Subject: netfilter: nf_nat: fix NAT issue in 2.6.30.4+ Vitezslav Samel discovered that since 2.6.30.4+ active FTP can not work over NAT. The "cause" of the problem was a fix of unacknowledged data detection with NAT (commit a3a9f79e361e864f0e9d75ebe2a0cb43d17c4272). However, actually, that fix uncovered a long standing bug in TCP conntrack: when NAT was enabled, we simply updated the max of the right edge of the segments we have seen (td_end), by the offset NAT produced with changing IP/port in the data. However, we did not update the other parameter (td_maxend) which is affected by the NAT offset. Thus that could drift away from the correct value and thus resulted breaking active FTP. The patch below fixes the issue by *not* updating the conntrack parameters from NAT, but instead taking into account the NAT offsets in conntrack in a consistent way. (Updating from NAT would be more harder and expensive because it'd need to re-calculate parameters we already calculated in conntrack.) Signed-off-by: Jozsef Kadlecsik Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_nat_core.c | 3 ++ net/ipv4/netfilter/nf_nat_helper.c | 34 ++++++++++++------ net/netfilter/nf_conntrack_core.c | 8 +++++ net/netfilter/nf_conntrack_proto_tcp.c | 64 ++++++++++++++-------------------- 4 files changed, 60 insertions(+), 49 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 68afc6ecd343..fe1a64479dd0 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -750,6 +750,8 @@ static int __init nf_nat_init(void) BUG_ON(nfnetlink_parse_nat_setup_hook != NULL); rcu_assign_pointer(nfnetlink_parse_nat_setup_hook, nfnetlink_parse_nat_setup); + BUG_ON(nf_ct_nat_offset != NULL); + rcu_assign_pointer(nf_ct_nat_offset, nf_nat_get_offset); return 0; cleanup_extend: @@ -764,6 +766,7 @@ static void __exit nf_nat_cleanup(void) nf_ct_extend_unregister(&nat_extend); rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL); rcu_assign_pointer(nfnetlink_parse_nat_setup_hook, NULL); + rcu_assign_pointer(nf_ct_nat_offset, NULL); synchronize_net(); } diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 09172a65d9b6..f9520fa3aba9 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -73,6 +73,28 @@ adjust_tcp_sequence(u32 seq, DUMP_OFFSET(this_way); } +/* Get the offset value, for conntrack */ +s16 nf_nat_get_offset(const struct nf_conn *ct, + enum ip_conntrack_dir dir, + u32 seq) +{ + struct nf_conn_nat *nat = nfct_nat(ct); + struct nf_nat_seq *this_way; + s16 offset; + + if (!nat) + return 0; + + this_way = &nat->seq[dir]; + spin_lock_bh(&nf_nat_seqofs_lock); + offset = after(seq, this_way->correction_pos) + ? this_way->offset_after : this_way->offset_before; + spin_unlock_bh(&nf_nat_seqofs_lock); + + return offset; +} +EXPORT_SYMBOL_GPL(nf_nat_get_offset); + /* Frobs data inside this packet, which is linear. */ static void mangle_contents(struct sk_buff *skb, unsigned int dataoff, @@ -189,11 +211,6 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb, adjust_tcp_sequence(ntohl(tcph->seq), (int)rep_len - (int)match_len, ct, ctinfo); - /* Tell TCP window tracking about seq change */ - nf_conntrack_tcp_update(skb, ip_hdrlen(skb), - ct, CTINFO2DIR(ctinfo), - (int)rep_len - (int)match_len); - nf_conntrack_event_cache(IPCT_NATSEQADJ, ct); } return 1; @@ -415,12 +432,7 @@ nf_nat_seq_adjust(struct sk_buff *skb, tcph->seq = newseq; tcph->ack_seq = newack; - if (!nf_nat_sack_adjust(skb, tcph, ct, ctinfo)) - return 0; - - nf_conntrack_tcp_update(skb, ip_hdrlen(skb), ct, dir, seqoff); - - return 1; + return nf_nat_sack_adjust(skb, tcph, ct, ctinfo); } /* Setup NAT on this expected conntrack so it follows master. */ diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 7c9ec3dee96e..0cdfb388a191 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1350,6 +1350,11 @@ err_stat: return ret; } +s16 (*nf_ct_nat_offset)(const struct nf_conn *ct, + enum ip_conntrack_dir dir, + u32 seq); +EXPORT_SYMBOL_GPL(nf_ct_nat_offset); + int nf_conntrack_init(struct net *net) { int ret; @@ -1367,6 +1372,9 @@ int nf_conntrack_init(struct net *net) /* For use by REJECT target */ rcu_assign_pointer(ip_ct_attach, nf_conntrack_attach); rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); + + /* Howto get NAT offsets */ + rcu_assign_pointer(nf_ct_nat_offset, NULL); } return 0; diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 97a82ba75376..ba2b76937283 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -492,6 +492,21 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff, } } +#ifdef CONFIG_NF_NAT_NEEDED +static inline s16 nat_offset(const struct nf_conn *ct, + enum ip_conntrack_dir dir, + u32 seq) +{ + typeof(nf_ct_nat_offset) get_offset = rcu_dereference(nf_ct_nat_offset); + + return get_offset != NULL ? get_offset(ct, dir, seq) : 0; +} +#define NAT_OFFSET(pf, ct, dir, seq) \ + (pf == NFPROTO_IPV4 ? nat_offset(ct, dir, seq) : 0) +#else +#define NAT_OFFSET(pf, ct, dir, seq) 0 +#endif + static bool tcp_in_window(const struct nf_conn *ct, struct ip_ct_tcp *state, enum ip_conntrack_dir dir, @@ -506,6 +521,7 @@ static bool tcp_in_window(const struct nf_conn *ct, struct ip_ct_tcp_state *receiver = &state->seen[!dir]; const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple; __u32 seq, ack, sack, end, win, swin; + s16 receiver_offset; bool res; /* @@ -519,11 +535,16 @@ static bool tcp_in_window(const struct nf_conn *ct, if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM) tcp_sack(skb, dataoff, tcph, &sack); + /* Take into account NAT sequence number mangling */ + receiver_offset = NAT_OFFSET(pf, ct, !dir, ack - 1); + ack -= receiver_offset; + sack -= receiver_offset; + pr_debug("tcp_in_window: START\n"); pr_debug("tcp_in_window: "); nf_ct_dump_tuple(tuple); - pr_debug("seq=%u ack=%u sack=%u win=%u end=%u\n", - seq, ack, sack, win, end); + pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", + seq, ack, receiver_offset, sack, receiver_offset, win, end); pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, @@ -613,8 +634,8 @@ static bool tcp_in_window(const struct nf_conn *ct, pr_debug("tcp_in_window: "); nf_ct_dump_tuple(tuple); - pr_debug("seq=%u ack=%u sack =%u win=%u end=%u\n", - seq, ack, sack, win, end); + pr_debug("seq=%u ack=%u+(%d) sack=%u+(%d) win=%u end=%u\n", + seq, ack, receiver_offset, sack, receiver_offset, win, end); pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " "receiver end=%u maxend=%u maxwin=%u scale=%i\n", sender->td_end, sender->td_maxend, sender->td_maxwin, @@ -700,7 +721,7 @@ static bool tcp_in_window(const struct nf_conn *ct, before(seq, sender->td_maxend + 1) ? after(end, sender->td_end - receiver->td_maxwin - 1) ? before(sack, receiver->td_end + 1) ? - after(ack, receiver->td_end - MAXACKWINDOW(sender)) ? "BUG" + after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG" : "ACK is under the lower bound (possible overly delayed ACK)" : "ACK is over the upper bound (ACKed data not seen yet)" : "SEQ is under the lower bound (already ACKed data retransmitted)" @@ -715,39 +736,6 @@ static bool tcp_in_window(const struct nf_conn *ct, return res; } -#ifdef CONFIG_NF_NAT_NEEDED -/* Update sender->td_end after NAT successfully mangled the packet */ -/* Caller must linearize skb at tcp header. */ -void nf_conntrack_tcp_update(const struct sk_buff *skb, - unsigned int dataoff, - struct nf_conn *ct, int dir, - s16 offset) -{ - const struct tcphdr *tcph = (const void *)skb->data + dataoff; - const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[dir]; - const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[!dir]; - __u32 end; - - end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph); - - spin_lock_bh(&ct->lock); - /* - * We have to worry for the ack in the reply packet only... - */ - if (ct->proto.tcp.seen[dir].td_end + offset == end) - ct->proto.tcp.seen[dir].td_end = end; - ct->proto.tcp.last_end = end; - spin_unlock_bh(&ct->lock); - pr_debug("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i " - "receiver end=%u maxend=%u maxwin=%u scale=%i\n", - sender->td_end, sender->td_maxend, sender->td_maxwin, - sender->td_scale, - receiver->td_end, receiver->td_maxend, receiver->td_maxwin, - receiver->td_scale); -} -EXPORT_SYMBOL_GPL(nf_conntrack_tcp_update); -#endif - #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 -- cgit v1.2.3 From 887e671f324d9898aaedb29a6ece6c853c394067 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 6 Nov 2009 00:50:39 -0800 Subject: decnet: netdevice refcount leak While working on device refcount stuff, I found a device refcount leak through DECNET. This nasty bug can be used to hold refcounts on any !DECNET netdevice. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/decnet/sysctl_net_decnet.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c index 26b0ab1e9f56..2036568beea9 100644 --- a/net/decnet/sysctl_net_decnet.c +++ b/net/decnet/sysctl_net_decnet.c @@ -263,11 +263,10 @@ static int dn_def_dev_strategy(ctl_table *table, return -ENODEV; rv = -ENODEV; - if (dev->dn_ptr != NULL) { + if (dev->dn_ptr != NULL) rv = dn_dev_set_default(dev, 1); - if (rv) - dev_put(dev); - } + if (rv) + dev_put(dev); } return rv; -- cgit v1.2.3 From 539054a8fa5141c9a4e9ac6a86d249e3f2bdef45 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 6 Nov 2009 18:08:32 -0800 Subject: netfilter: xt_connlimit: fix regression caused by zero family value Commit v2.6.28-rc1~717^2~109^2~2 was slightly incomplete; not all instances of par->match->family were changed to par->family. References: http://bugzilla.netfilter.org/show_bug.cgi?id=610 Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/xt_connlimit.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 680980954395..38f03f75a636 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -103,7 +103,7 @@ static int count_them(struct xt_connlimit_data *data, const struct nf_conntrack_tuple *tuple, const union nf_inet_addr *addr, const union nf_inet_addr *mask, - const struct xt_match *match) + u_int8_t family) { const struct nf_conntrack_tuple_hash *found; struct xt_connlimit_conn *conn; @@ -113,8 +113,7 @@ static int count_them(struct xt_connlimit_data *data, bool addit = true; int matches = 0; - - if (match->family == NFPROTO_IPV6) + if (family == NFPROTO_IPV6) hash = &data->iphash[connlimit_iphash6(addr, mask)]; else hash = &data->iphash[connlimit_iphash(addr->ip & mask->ip)]; @@ -157,8 +156,7 @@ static int count_them(struct xt_connlimit_data *data, continue; } - if (same_source_net(addr, mask, &conn->tuple.src.u3, - match->family)) + if (same_source_net(addr, mask, &conn->tuple.src.u3, family)) /* same source network -> be counted! */ ++matches; nf_ct_put(found_ct); @@ -207,7 +205,7 @@ connlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par) spin_lock_bh(&info->data->lock); connections = count_them(info->data, tuple_ptr, &addr, - &info->mask, par->match); + &info->mask, par->family); spin_unlock_bh(&info->data->lock); if (connections < 0) { -- cgit v1.2.3 From 23ca0c989e46924393f1d54bec84801d035dd28e Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 6 Nov 2009 10:37:41 +0000 Subject: ipip: Fix handling of DF packets when pmtudisc is OFF RFC 2003 requires the outer header to have DF set if DF is set on the inner header, even when PMTU discovery is off for the tunnel. Our implementation does exactly that. For this to work properly the IPIP gateway also needs to engate in PMTU when the inner DF bit is set. As otherwise the original host would not be able to carry out its PMTU successfully since part of the path is only visible to the gateway. Unfortunately when the tunnel PMTU discovery setting is off, we do not collect the necessary soft state, resulting in blackholes when the original host tries to perform PMTU discovery. This problem is not reproducible on the IPIP gateway itself as the inner packet usually has skb->local_df set. This is not correctly cleared (an unrelated bug) when the packet passes through the tunnel, which allows fragmentation to occur. For hosts behind the IPIP gateway it is readily visible with a simple ping. This patch fixes the problem by performing PMTU discovery for all packets with the inner DF bit set, regardless of the PMTU discovery setting on the tunnel itself. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 08ccd344de7a..ae40ed1ba560 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -438,25 +438,27 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_error; } - if (tiph->frag_off) + df |= old_iph->frag_off & htons(IP_DF); + + if (df) { mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr); - else - mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; - if (mtu < 68) { - stats->collisions++; - ip_rt_put(rt); - goto tx_error; - } - if (skb_dst(skb)) - skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); + if (mtu < 68) { + stats->collisions++; + ip_rt_put(rt); + goto tx_error; + } - df |= (old_iph->frag_off&htons(IP_DF)); + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu); - if ((old_iph->frag_off&htons(IP_DF)) && mtu < ntohs(old_iph->tot_len)) { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); - ip_rt_put(rt); - goto tx_error; + if ((old_iph->frag_off & htons(IP_DF)) && + mtu < ntohs(old_iph->tot_len)) { + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); + ip_rt_put(rt); + goto tx_error; + } } if (tunnel->err_count > 0) { -- cgit v1.2.3 From 6755aebaaf9fc5416acfd4578ab7a1e122ecbc74 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 6 Nov 2009 00:23:01 +0000 Subject: can: should not use __dev_get_by_index() without locks bcm_proc_getifname() is called with RTNL and dev_base_lock not held. It calls __dev_get_by_index() without locks, and this is illegal (might crash) Close the race by holding dev_base_lock and copying dev->name in the protected section. Signed-off-by: Eric Dumazet Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller --- net/can/bcm.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/can/bcm.c b/net/can/bcm.c index 597da4f8f888..e8d58f33fe09 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -132,23 +132,27 @@ static inline struct bcm_sock *bcm_sk(const struct sock *sk) /* * procfs functions */ -static char *bcm_proc_getifname(int ifindex) +static char *bcm_proc_getifname(char *result, int ifindex) { struct net_device *dev; if (!ifindex) return "any"; - /* no usage counting */ + read_lock(&dev_base_lock); dev = __dev_get_by_index(&init_net, ifindex); if (dev) - return dev->name; + strcpy(result, dev->name); + else + strcpy(result, "???"); + read_unlock(&dev_base_lock); - return "???"; + return result; } static int bcm_proc_show(struct seq_file *m, void *v) { + char ifname[IFNAMSIZ]; struct sock *sk = (struct sock *)m->private; struct bcm_sock *bo = bcm_sk(sk); struct bcm_op *op; @@ -157,7 +161,7 @@ static int bcm_proc_show(struct seq_file *m, void *v) seq_printf(m, " / sk %p", sk); seq_printf(m, " / bo %p", bo); seq_printf(m, " / dropped %lu", bo->dropped_usr_msgs); - seq_printf(m, " / bound %s", bcm_proc_getifname(bo->ifindex)); + seq_printf(m, " / bound %s", bcm_proc_getifname(ifname, bo->ifindex)); seq_printf(m, " <<<\n"); list_for_each_entry(op, &bo->rx_ops, list) { @@ -169,7 +173,7 @@ static int bcm_proc_show(struct seq_file *m, void *v) continue; seq_printf(m, "rx_op: %03X %-5s ", - op->can_id, bcm_proc_getifname(op->ifindex)); + op->can_id, bcm_proc_getifname(ifname, op->ifindex)); seq_printf(m, "[%d]%c ", op->nframes, (op->flags & RX_CHECK_DLC)?'d':' '); if (op->kt_ival1.tv64) @@ -194,7 +198,8 @@ static int bcm_proc_show(struct seq_file *m, void *v) list_for_each_entry(op, &bo->tx_ops, list) { seq_printf(m, "tx_op: %03X %s [%d] ", - op->can_id, bcm_proc_getifname(op->ifindex), + op->can_id, + bcm_proc_getifname(ifname, op->ifindex), op->nframes); if (op->kt_ival1.tv64) -- cgit v1.2.3 From 1c622ae67bfc729891f5cd80795b15b87e6ac471 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 13 Nov 2009 09:31:35 +0100 Subject: netfilter: xt_osf: fix xt_osf_remove_callback() return value Return a negative error value. Signed-off-by: Roel Kluin Signed-off-by: Patrick McHardy --- net/netfilter/xt_osf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 63e190504656..4d1a41bbd5d7 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -118,7 +118,7 @@ static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb, { struct xt_osf_user_finger *f; struct xt_osf_finger *sf; - int err = ENOENT; + int err = -ENOENT; if (!osf_attrs[OSF_ATTR_FINGER]) return -EINVAL; -- cgit v1.2.3 From 7378396cd172cc058fa62220c6486419046c4e0c Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 13 Nov 2009 09:34:44 +0100 Subject: netfilter: nf_log: fix sleeping function called from invalid context in seq_show() [ 171.925285] BUG: sleeping function called from invalid context at kernel/mutex.c:280 [ 171.925296] in_atomic(): 1, irqs_disabled(): 0, pid: 671, name: grep [ 171.925306] 2 locks held by grep/671: [ 171.925312] #0: (&p->lock){+.+.+.}, at: [] seq_read+0x25/0x36c [ 171.925340] #1: (rcu_read_lock){.+.+..}, at: [] seq_start+0x0/0x44 [ 171.925372] Pid: 671, comm: grep Not tainted 2.6.31.6-4-netbook #3 [ 171.925380] Call Trace: [ 171.925398] [] ? __debug_show_held_locks+0x1e/0x20 [ 171.925414] [] __might_sleep+0xfb/0x102 [ 171.925430] [] mutex_lock_nested+0x1c/0x2ad [ 171.925444] [] seq_show+0x74/0x127 [ 171.925456] [] seq_read+0x1b4/0x36c [ 171.925469] [] ? seq_read+0x0/0x36c [ 171.925483] [] proc_reg_read+0x60/0x74 [ 171.925496] [] ? proc_reg_read+0x0/0x74 [ 171.925510] [] vfs_read+0x87/0x110 [ 171.925523] [] sys_read+0x3b/0x60 [ 171.925538] [] syscall_call+0x7/0xb Fix it by replacing RCU with nf_log_mutex. Reported-by: "Yin, Kangkai" Signed-off-by: Wu Fengguang Signed-off-by: Patrick McHardy --- net/netfilter/nf_log.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index c93494fef8ef..d65d3481919c 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -128,9 +128,8 @@ EXPORT_SYMBOL(nf_log_packet); #ifdef CONFIG_PROC_FS static void *seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) { - rcu_read_lock(); + mutex_lock(&nf_log_mutex); if (*pos >= ARRAY_SIZE(nf_loggers)) return NULL; @@ -149,9 +148,8 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos) } static void seq_stop(struct seq_file *s, void *v) - __releases(RCU) { - rcu_read_unlock(); + mutex_unlock(&nf_log_mutex); } static int seq_show(struct seq_file *s, void *v) @@ -161,7 +159,7 @@ static int seq_show(struct seq_file *s, void *v) struct nf_logger *t; int ret; - logger = rcu_dereference(nf_loggers[*pos]); + logger = nf_loggers[*pos]; if (!logger) ret = seq_printf(s, "%2lld NONE (", *pos); @@ -171,22 +169,16 @@ static int seq_show(struct seq_file *s, void *v) if (ret < 0) return ret; - mutex_lock(&nf_log_mutex); list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) { ret = seq_printf(s, "%s", t->name); - if (ret < 0) { - mutex_unlock(&nf_log_mutex); + if (ret < 0) return ret; - } if (&t->list[*pos] != nf_loggers_l[*pos].prev) { ret = seq_printf(s, ","); - if (ret < 0) { - mutex_unlock(&nf_log_mutex); + if (ret < 0) return ret; - } } } - mutex_unlock(&nf_log_mutex); return seq_printf(s, ")\n"); } -- cgit v1.2.3 From d792c1006fe92448217b71513d3955868358271d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 13 Nov 2009 13:56:33 -0800 Subject: tcp: provide more information on the tcp receive_queue bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The addition of rcv_nxt allows to discern whether the skb was out of place or tp->copied. Also catch fancy combination of flags if necessary (sadly we might miss the actual causer flags as it might have already returned). Btw, we perhaps would want to forward copied_seq in somewhere or otherwise we might have some nice loop with WARN stuff within but where to do that safely I don't know at this stage until more is known (but it is not made significantly worse by this patch). Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- net/ipv4/tcp.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 98440ad82558..f1813bc71088 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -1183,7 +1183,9 @@ void tcp_cleanup_rbuf(struct sock *sk, int copied) #if TCP_DEBUG struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); - WARN_ON(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)); + WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq), + KERN_INFO "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n", + tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt); #endif if (inet_csk_ack_scheduled(sk)) { @@ -1430,11 +1432,13 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* Now that we have two receive queues this * shouldn't happen. */ - if (before(*seq, TCP_SKB_CB(skb)->seq)) { - printk(KERN_INFO "recvmsg bug: copied %X " - "seq %X\n", *seq, TCP_SKB_CB(skb)->seq); + if (WARN(before(*seq, TCP_SKB_CB(skb)->seq), + KERN_INFO "recvmsg bug: copied %X " + "seq %X rcvnxt %X fl %X\n", *seq, + TCP_SKB_CB(skb)->seq, tp->rcv_nxt, + flags)) break; - } + offset = *seq - TCP_SKB_CB(skb)->seq; if (tcp_hdr(skb)->syn) offset--; @@ -1443,8 +1447,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (tcp_hdr(skb)->fin) goto found_fin_ok; WARN(!(flags & MSG_PEEK), KERN_INFO "recvmsg bug 2: " - "copied %X seq %X\n", *seq, - TCP_SKB_CB(skb)->seq); + "copied %X seq %X rcvnxt %X fl %X\n", + *seq, TCP_SKB_CB(skb)->seq, + tp->rcv_nxt, flags); } /* Well, if we have backlog, try to process it now yet. */ -- cgit v1.2.3 From 1e360a60b24ad8f8685af66fa6de10ce46693a4b Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 13 Nov 2009 10:52:55 -0500 Subject: SUNRPC: Address buffer overrun in rpc_uaddr2sockaddr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The size of buf[] must account for the string termination needed for the first strict_strtoul() call. Introduced in commit a02d6926. Fábio Olivé Leite points out that strict_strtoul() requires _either_ '\n\0' _or_ '\0' termination, so use the simpler '\0' here instead. See http://bugzilla.kernel.org/show_bug.cgi?id=14546 . Reported-by: argp@census-labs.com Signed-off-by: Chuck Lever Signed-off-by: Fábio Olivé Leite Signed-off-by: Trond Myklebust --- net/sunrpc/addr.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c index 22e8fd89477f..c7450c8f0a7c 100644 --- a/net/sunrpc/addr.c +++ b/net/sunrpc/addr.c @@ -306,24 +306,25 @@ EXPORT_SYMBOL_GPL(rpc_sockaddr2uaddr); * @sap: buffer into which to plant socket address * @salen: size of buffer * + * @uaddr does not have to be '\0'-terminated, but strict_strtoul() and + * rpc_pton() require proper string termination to be successful. + * * Returns the size of the socket address if successful; otherwise * zero is returned. */ size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, struct sockaddr *sap, const size_t salen) { - char *c, buf[RPCBIND_MAXUADDRLEN]; + char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')]; unsigned long portlo, porthi; unsigned short port; - if (uaddr_len > sizeof(buf)) + if (uaddr_len > RPCBIND_MAXUADDRLEN) return 0; memcpy(buf, uaddr, uaddr_len); - buf[uaddr_len] = '\n'; - buf[uaddr_len + 1] = '\0'; - + buf[uaddr_len] = '\0'; c = strrchr(buf, '.'); if (unlikely(c == NULL)) return 0; @@ -332,9 +333,7 @@ size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, if (unlikely(portlo > 255)) return 0; - c[0] = '\n'; - c[1] = '\0'; - + *c = '\0'; c = strrchr(buf, '.'); if (unlikely(c == NULL)) return 0; @@ -345,8 +344,7 @@ size_t rpc_uaddr2sockaddr(const char *uaddr, const size_t uaddr_len, port = (unsigned short)((porthi << 8) | portlo); - c[0] = '\0'; - + *c = '\0'; if (rpc_pton(buf, strlen(buf), sap, salen) == 0) return 0; -- cgit v1.2.3 From 409b95aff3583c05ac7a9247fa3d8c9aa7f9cae3 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 10 Nov 2009 08:57:34 +0000 Subject: sctp: Set source addresses on the association before adding transports Recent commit 8da645e101a8c20c6073efda3c7cc74eec01b87f sctp: Get rid of an extra routing lookup when adding a transport introduced a regression in the connection setup. The behavior was different between IPv4 and IPv6. IPv4 case ended up working because the route lookup routing returned a NULL route, which triggered another route lookup later in the output patch that succeeded. In the IPv6 case, a valid route was returned for first call, but we could not find a valid source address at the time since the source addresses were not set on the association yet. Thus resulted in a hung connection. The solution is to set the source addresses on the association prior to adding peers. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/associola.c | 4 +--- net/sctp/sm_statefuns.c | 15 +++++++++------ net/sctp/socket.c | 22 ++++++++++++---------- 3 files changed, 22 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 8450960df24f..7eed77a39d0d 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1485,15 +1485,13 @@ void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len) * local endpoint and the remote peer. */ int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc, - gfp_t gfp) + sctp_scope_t scope, gfp_t gfp) { - sctp_scope_t scope; int flags; /* Use scoping rules to determine the subset of addresses from * the endpoint. */ - scope = sctp_scope(&asoc->peer.active_path->ipaddr); flags = (PF_INET6 == asoc->base.sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0; if (asoc->peer.ipv4_address) flags |= SCTP_ADDR4_PEERSUPP; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index c8fae1983dd1..d4df45022ffa 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -384,6 +384,11 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, if (!new_asoc) goto nomem; + if (sctp_assoc_set_bind_addr_from_ep(new_asoc, + sctp_scope(sctp_source(chunk)), + GFP_ATOMIC) < 0) + goto nomem_init; + /* The call, sctp_process_init(), can fail on memory allocation. */ if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type, sctp_source(chunk), @@ -401,9 +406,6 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep, len = ntohs(err_chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); - if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0) - goto nomem_init; - repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len); if (!repl) goto nomem_init; @@ -1452,6 +1454,10 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( if (!new_asoc) goto nomem; + if (sctp_assoc_set_bind_addr_from_ep(new_asoc, + sctp_scope(sctp_source(chunk)), GFP_ATOMIC) < 0) + goto nomem; + /* In the outbound INIT ACK the endpoint MUST copy its current * Verification Tag and Peers Verification tag into a reserved * place (local tie-tag and per tie-tag) within the state cookie. @@ -1488,9 +1494,6 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( sizeof(sctp_chunkhdr_t); } - if (sctp_assoc_set_bind_addr_from_ep(new_asoc, GFP_ATOMIC) < 0) - goto nomem; - repl = sctp_make_init_ack(new_asoc, chunk, GFP_ATOMIC, len); if (!repl) goto nomem; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index c8d05758661d..bf705ba97231 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1080,6 +1080,13 @@ static int __sctp_connect(struct sock* sk, err = -ENOMEM; goto out_free; } + + err = sctp_assoc_set_bind_addr_from_ep(asoc, scope, + GFP_KERNEL); + if (err < 0) { + goto out_free; + } + } /* Prime the peer's transport structures. */ @@ -1095,11 +1102,6 @@ static int __sctp_connect(struct sock* sk, walk_size += af->sockaddr_len; } - err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL); - if (err < 0) { - goto out_free; - } - /* In case the user of sctp_connectx() wants an association * id back, assign one now. */ @@ -1689,6 +1691,11 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, goto out_unlock; } asoc = new_asoc; + err = sctp_assoc_set_bind_addr_from_ep(asoc, scope, GFP_KERNEL); + if (err < 0) { + err = -ENOMEM; + goto out_free; + } /* If the SCTP_INIT ancillary data is specified, set all * the association init values accordingly. @@ -1718,11 +1725,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, err = -ENOMEM; goto out_free; } - err = sctp_assoc_set_bind_addr_from_ep(asoc, GFP_KERNEL); - if (err < 0) { - err = -ENOMEM; - goto out_free; - } } /* ASSERT: we have a valid association at this point. */ -- cgit v1.2.3 From f9c67811ebc00a42f62f5d542d3abd36bd49ae35 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 11 Nov 2009 08:19:24 +0000 Subject: sctp: Fix regression introduced by new sctp_connectx api A new (unrealeased to the user) sctp_connectx api c6ba68a26645dbc5029a9faa5687ebe6fcfc53e4 sctp: support non-blocking version of the new sctp_connectx() API introduced a regression cought by the user regression test suite. In particular, the API requires the user library to re-allocate the buffer and could potentially trigger a SIGFAULT. This change corrects that regression by passing the original address buffer to the kernel unmodified, but still allows for a returned association id. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/socket.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index bf705ba97231..3a95fcb17a9e 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1276,22 +1276,30 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, } /* - * New (hopefully final) interface for the API. The option buffer is used - * both for the returned association id and the addresses. + * New (hopefully final) interface for the API. + * We use the sctp_getaddrs_old structure so that use-space library + * can avoid any unnecessary allocations. The only defferent part + * is that we store the actual length of the address buffer into the + * addrs_num structure member. That way we can re-use the existing + * code. */ SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len, char __user *optval, int __user *optlen) { + struct sctp_getaddrs_old param; sctp_assoc_t assoc_id = 0; int err = 0; - if (len < sizeof(assoc_id)) + if (len < sizeof(param)) return -EINVAL; + if (copy_from_user(¶m, optval, sizeof(param))) + return -EFAULT; + err = __sctp_setsockopt_connectx(sk, - (struct sockaddr __user *)(optval + sizeof(assoc_id)), - len - sizeof(assoc_id), &assoc_id); + (struct sockaddr __user *)param.addrs, + param.addr_num, &assoc_id); if (err == 0 || err == -EINPROGRESS) { if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) -- cgit v1.2.3 From a78102e74e782914039cd8a6939532649825a2e3 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 11 Nov 2009 11:54:37 +0000 Subject: sctp: Set socket source address when additing first transport Recent commits sctp: Get rid of an extra routing lookup when adding a transport and sctp: Set source addresses on the association before adding transports changed when routes are added to the sctp transports. As such, we didn't set the socket source address correctly when adding the first transport. The first transport is always the primary/active one, so when adding it, set the socket source address. This was causing regression failures in SCTP tests. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/transport.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/sctp/transport.c b/net/sctp/transport.c index c256e4839316..3b141bb32faf 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -308,7 +308,8 @@ void sctp_transport_route(struct sctp_transport *transport, /* Initialize sk->sk_rcv_saddr, if the transport is the * association's active path for getsockname(). */ - if (asoc && (transport == asoc->peer.active_path)) + if (asoc && (!asoc->peer.primary_path || + (transport == asoc->peer.active_path))) opt->pf->af->to_sk_saddr(&transport->saddr, asoc->base.sk); } else -- cgit v1.2.3 From d0490cfdf440fded2c292cfb8bb9272fc9ef6943 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 11 Nov 2009 02:03:54 +0000 Subject: ipmr: missing dev_put() on error path in vif_add() The other error paths in front of this one have a dev_put() but this one got missed. Found by smatch static checker. Signed-off-by: Dan Carpenter Acked-by: Wang Chen Signed-off-by: David S. Miller --- net/ipv4/ipmr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 630a56df7b47..99508d66a642 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -483,8 +483,10 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock) return -EINVAL; } - if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) + if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) { + dev_put(dev); return -EADDRNOTAVAIL; + } IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++; ip_rt_multicast_event(in_dev); -- cgit v1.2.3 From 93f19c9fc8c98bb6d2e9825115989603ffd5cd1f Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 3 Sep 2009 12:34:19 +0300 Subject: Bluetooth: Set general bonding security for ACL by default This patch fixes double pairing issues with Secure Simple Paring support. It was observed that when pairing with SSP enabled, that the confirmation will be asked twice. http://www.spinics.net/lists/linux-bluetooth/msg02473.html This also causes bug when initiating SSP connection from Windows Vista. The reason is because bluetoothd does not store link keys since HCIGETAUTHINFO returns 0. Setting default to general bonding fixes these issues. Signed-off-by: Andrei Emeltchenko Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_conn.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index a9750984f772..b7c4224f4e7d 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -211,6 +211,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) conn->type = type; conn->mode = HCI_CM_ACTIVE; conn->state = BT_OPEN; + conn->auth_type = HCI_AT_GENERAL_BONDING; conn->power_save = 1; conn->disc_timeout = HCI_DISCONN_TIMEOUT; -- cgit v1.2.3 From a0e55a32afc2130e5ae506755e4b8eb42a23b568 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 29 Sep 2009 01:42:23 -0300 Subject: Bluetooth: Select Basic Mode as default for SOCK_SEQPACKET The default mode for SOCK_SEQPACKET is Basic Mode. So when no mode has been specified, Basic Mode shall be used. This is important for current application to keep working as expected and not cause a regression. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 77e9fb130adb..076caa10d2f6 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2205,7 +2205,7 @@ static int l2cap_build_conf_req(struct sock *sk, void *data) { struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_conf_req *req = data; - struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_ERTM }; + struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; void *ptr = req->data; BT_DBG("sk %p", sk); -- cgit v1.2.3 From 68ae6639b6dff117ba37f648f1611a4629abadf0 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Sat, 17 Oct 2009 21:41:01 -0300 Subject: Bluetooth: Fix regression with L2CAP configuration in Basic Mode Basic Mode is the default mode of operation of a L2CAP entity. In this case the RFC (Retransmission and Flow Control) configuration option should not be used at all. Normally remote L2CAP implementation should just ignore this option, but it can cause various side effects with other Bluetooth stacks that are not capable of handling unknown options. Signed-off-by: Gustavo F. Padovan Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 076caa10d2f6..947f8bbb4bb3 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2394,6 +2394,10 @@ done: rfc.monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; pi->conf_state |= L2CAP_CONF_MODE_DONE; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + break; case L2CAP_MODE_STREAMING: @@ -2401,6 +2405,10 @@ done: pi->max_pdu_size = rfc.max_pdu_size; pi->conf_state |= L2CAP_CONF_MODE_DONE; + + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, + sizeof(rfc), (unsigned long) &rfc); + break; default: @@ -2410,9 +2418,6 @@ done: rfc.mode = pi->mode; } - l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, - sizeof(rfc), (unsigned long) &rfc); - if (result == L2CAP_CONF_SUCCESS) pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; } -- cgit v1.2.3 From 91e9c07bd635353d1a278bdb38dbb56ac371bcb8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 15 Nov 2009 23:30:24 +0000 Subject: net: Fix the rollback test in dev_change_name() net: Fix the rollback test in dev_change_name() In dev_change_name() an err variable is used for storing the original call_netdevice_notifiers() errno (negative) and testing for a rollback error later, but the test for non-zero is wrong, because the err might have positive value as well - from dev_alloc_name(). It means the rollback for a netdevice with a number > 0 will never happen. (The err test is reordered btw. to make it more readable.) Signed-off-by: Jarek Poplawski Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/dev.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index b8f74cfb1bfd..fe10551d3671 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -942,14 +942,15 @@ rollback: ret = notifier_to_errno(ret); if (ret) { - if (err) { - printk(KERN_ERR - "%s: name change rollback failed: %d.\n", - dev->name, ret); - } else { + /* err >= 0 after dev_alloc_name() or stores the first errno */ + if (err >= 0) { err = ret; memcpy(dev->name, oldname, IFNAMSIZ); goto rollback; + } else { + printk(KERN_ERR + "%s: name change rollback failed: %d.\n", + dev->name, ret); } } -- cgit v1.2.3 From 69c0cab120a85471054614418b447349caba22d7 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 17 Nov 2009 05:18:18 -0800 Subject: gro: Fix illegal merging of trailer trash When we've merged skb's with page frags, and subsequently receive a trailer skb (< MSS) that is not completely non-linear (this can occur on Intel NICs if the packet size falls below the threshold), GRO ends up producing an illegal GSO skb with a frag_list. This is harmless unless the skb is then forwarded through an interface that requires software GSO, whereupon the GSO code will BUG. This patch detects this case in GRO and avoids merging the trailer skb. Reported-by: Mark Wagner Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/core/skbuff.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 80a96166df39..ec85681a7dd8 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2701,7 +2701,8 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) NAPI_GRO_CB(skb)->free = 1; goto done; - } + } else if (skb_gro_len(p) != pinfo->gso_size) + return -E2BIG; headroom = skb_headroom(p); nskb = netdev_alloc_skb(p->dev, headroom + skb_gro_offset(p)); -- cgit v1.2.3 From 6b863d1d3239eff0f45c2e6e672f5b56db828db0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 17 Nov 2009 06:45:04 -0800 Subject: vlan: Fix register_vlan_dev() error path In case register_netdevice() returns an error, and a new vlan_group was allocated and inserted in vlan_group_hash[] we call vlan_group_free() without deleting group from hash table. Future lookups can give infinite loops or crashes. We must delete the vlan_group using RCU safe procedure. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/8021q/vlan.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 8836575f9d79..a29c5ab5815c 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -281,8 +281,11 @@ out_uninit_applicant: if (ngrp) vlan_gvrp_uninit_applicant(real_dev); out_free_group: - if (ngrp) - vlan_group_free(ngrp); + if (ngrp) { + hlist_del_rcu(&ngrp->hlist); + /* Free the group, after all cpu's are done. */ + call_rcu(&ngrp->rcu, vlan_rcu_free); + } return err; } -- cgit v1.2.3 From 8ade00824607fcfa8842572012d4393b40a74a94 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 18 Nov 2009 17:15:06 +0100 Subject: mac80211: fix addba timer (again...) commit 2171abc58644e09dbba546d91366b12743115396 Author: Johannes Berg Date: Thu Oct 29 08:34:00 2009 +0100 mac80211: fix addba timer left a problem in there, even if the timer was never started it could be deleted and then added. Linus pointed out that del_timer_sync() isn't actually needed if we make the timer able to deal with no longer being needed when it gets queued _while_ we're in the locked section that also deletes it. For that the timer function only needs to check the HT_ADDBA_RECEIVED_MSK bit as well as the HT_ADDBA_REQUESTED_MSK bit, only if the former is clear should it do anything. Cc: Linus Torvalds Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index b09948ceec4a..206fd82f0c76 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -173,12 +173,14 @@ static void sta_addba_resp_timer_expired(unsigned long data) /* check if the TID waits for addBA response */ spin_lock_bh(&sta->lock); - if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + if ((*state & (HT_ADDBA_REQUESTED_MSK | HT_ADDBA_RECEIVED_MSK)) != + HT_ADDBA_REQUESTED_MSK) { spin_unlock_bh(&sta->lock); *state = HT_AGG_STATE_IDLE; #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "timer expired on tid %d but we are not " - "expecting addBA response there", tid); + "(or no longer) expecting addBA response there", + tid); #endif return; } @@ -666,21 +668,21 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, state = &sta->ampdu_mlme.tid_state_tx[tid]; - del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); - spin_lock_bh(&sta->lock); if (!(*state & HT_ADDBA_REQUESTED_MSK)) - goto timer_still_needed; + goto out; if (mgmt->u.action.u.addba_resp.dialog_token != sta->ampdu_mlme.tid_tx[tid]->dialog_token) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - goto timer_still_needed; + goto out; } + del_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); + #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ @@ -699,10 +701,6 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, ___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR); } - goto out; - - timer_still_needed: - add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); out: spin_unlock_bh(&sta->lock); } -- cgit v1.2.3 From ceb99fe071eb688255798d89be337affffa2b103 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 19 Nov 2009 14:29:39 +0100 Subject: mac80211: fix resume When mac80211 resumes, it currently first sets suspended to false so the driver can start doing things and we can receive frames. However, if we actually receive frames then it can end up starting some work which adds timers and then later runs into a BUG_ON in the timer code because it tries add_timer() on a pending timer. Fix this by keeping track of the resuming process by introducing a new variable 'resuming' which gets set to true early on instead of setting 'suspended' to false, and allow queueing work but not receiving frames while resuming. Reported-by: Maxim Levitsky Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 8 ++++++++ net/mac80211/util.c | 19 +++++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 588005c84a6d..a910bf1f092f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -661,6 +661,14 @@ struct ieee80211_local { */ bool suspended; + /* + * Resuming is true while suspended, but when we're reprogramming the + * hardware -- at that time it's allowed to use ieee80211_queue_work() + * again even though some other parts of the stack are still suspended + * and we still drop received frames to avoid waking the stack. + */ + bool resuming; + /* * quiescing is true during the suspend process _only_ to * ease timer cancelling etc. diff --git a/net/mac80211/util.c b/net/mac80211/util.c index aeb65b3d2295..e6c08da8da26 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -520,9 +520,9 @@ EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); */ static bool ieee80211_can_queue_work(struct ieee80211_local *local) { - if (WARN(local->suspended, "queueing ieee80211 work while " - "going to suspend\n")) - return false; + if (WARN(local->suspended && !local->resuming, + "queueing ieee80211 work while going to suspend\n")) + return false; return true; } @@ -1025,13 +1025,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) struct sta_info *sta; unsigned long flags; int res; - bool from_suspend = local->suspended; - /* - * We're going to start the hardware, at that point - * we are no longer suspended and can RX frames. - */ - local->suspended = false; + if (local->suspended) + local->resuming = true; /* restart hardware */ if (local->open_count) { @@ -1129,11 +1125,14 @@ int ieee80211_reconfig(struct ieee80211_local *local) * If this is for hw restart things are still running. * We may want to change that later, however. */ - if (!from_suspend) + if (!local->suspended) return 0; #ifdef CONFIG_PM + /* first set suspended false, then resuming */ local->suspended = false; + mb(); + local->resuming = false; list_for_each_entry(sdata, &local->interfaces, list) { switch(sdata->vif.type) { -- cgit v1.2.3 From d667b9cfd09a2ca61f74a9edc73d08d2ad0d14da Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 19 Nov 2009 04:59:03 +0000 Subject: netfilter: xt_osf: fix xt_osf_remove_callback() return value Return a negative error value. Signed-off-by: Roel Kluin Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/xt_osf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 63e190504656..4d1a41bbd5d7 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -118,7 +118,7 @@ static int xt_osf_remove_callback(struct sock *ctnl, struct sk_buff *skb, { struct xt_osf_user_finger *f; struct xt_osf_finger *sf; - int err = ENOENT; + int err = -ENOENT; if (!osf_attrs[OSF_ATTR_FINGER]) return -EINVAL; -- cgit v1.2.3 From 6440fe059ee8b49b548c8c2c1447530075d07e10 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 19 Nov 2009 04:59:05 +0000 Subject: netfilter: nf_log: fix sleeping function called from invalid context in seq_show() [ 171.925285] BUG: sleeping function called from invalid context at kernel/mutex.c:280 [ 171.925296] in_atomic(): 1, irqs_disabled(): 0, pid: 671, name: grep [ 171.925306] 2 locks held by grep/671: [ 171.925312] #0: (&p->lock){+.+.+.}, at: [] seq_read+0x25/0x36c [ 171.925340] #1: (rcu_read_lock){.+.+..}, at: [] seq_start+0x0/0x44 [ 171.925372] Pid: 671, comm: grep Not tainted 2.6.31.6-4-netbook #3 [ 171.925380] Call Trace: [ 171.925398] [] ? __debug_show_held_locks+0x1e/0x20 [ 171.925414] [] __might_sleep+0xfb/0x102 [ 171.925430] [] mutex_lock_nested+0x1c/0x2ad [ 171.925444] [] seq_show+0x74/0x127 [ 171.925456] [] seq_read+0x1b4/0x36c [ 171.925469] [] ? seq_read+0x0/0x36c [ 171.925483] [] proc_reg_read+0x60/0x74 [ 171.925496] [] ? proc_reg_read+0x0/0x74 [ 171.925510] [] vfs_read+0x87/0x110 [ 171.925523] [] sys_read+0x3b/0x60 [ 171.925538] [] syscall_call+0x7/0xb Fix it by replacing RCU with nf_log_mutex. Reported-by: "Yin, Kangkai" Signed-off-by: Wu Fengguang Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_log.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index c93494fef8ef..d65d3481919c 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -128,9 +128,8 @@ EXPORT_SYMBOL(nf_log_packet); #ifdef CONFIG_PROC_FS static void *seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) { - rcu_read_lock(); + mutex_lock(&nf_log_mutex); if (*pos >= ARRAY_SIZE(nf_loggers)) return NULL; @@ -149,9 +148,8 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos) } static void seq_stop(struct seq_file *s, void *v) - __releases(RCU) { - rcu_read_unlock(); + mutex_unlock(&nf_log_mutex); } static int seq_show(struct seq_file *s, void *v) @@ -161,7 +159,7 @@ static int seq_show(struct seq_file *s, void *v) struct nf_logger *t; int ret; - logger = rcu_dereference(nf_loggers[*pos]); + logger = nf_loggers[*pos]; if (!logger) ret = seq_printf(s, "%2lld NONE (", *pos); @@ -171,22 +169,16 @@ static int seq_show(struct seq_file *s, void *v) if (ret < 0) return ret; - mutex_lock(&nf_log_mutex); list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) { ret = seq_printf(s, "%s", t->name); - if (ret < 0) { - mutex_unlock(&nf_log_mutex); + if (ret < 0) return ret; - } if (&t->list[*pos] != nf_loggers_l[*pos].prev) { ret = seq_printf(s, ","); - if (ret < 0) { - mutex_unlock(&nf_log_mutex); + if (ret < 0) return ret; - } } } - mutex_unlock(&nf_log_mutex); return seq_printf(s, ")\n"); } -- cgit v1.2.3 From 8fa539bd911e8a7faa7cd77b5192229c9666d9b8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 23 Nov 2009 13:37:23 +0100 Subject: netfilter: xt_limit: fix invalid return code in limit_mt_check() Commit acc738fe (netfilter: xtables: avoid pointer to self) introduced an invalid return value in limit_mt_check(). Signed-off-by: Patrick McHardy --- net/netfilter/xt_limit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c index 2e8089ecd0af..2773be6a71dd 100644 --- a/net/netfilter/xt_limit.c +++ b/net/netfilter/xt_limit.c @@ -112,7 +112,7 @@ static bool limit_mt_check(const struct xt_mtchk_param *par) priv = kmalloc(sizeof(*priv), GFP_KERNEL); if (priv == NULL) - return -ENOMEM; + return false; /* For SMP, we only want to use one set of state. */ r->master = priv; -- cgit v1.2.3 From 593f63b0be70762bd4354bde147b8e169c5a2f57 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 23 Nov 2009 01:44:37 +0000 Subject: pktgen: Fix device name compares Commit e6fce5b916cd7f7f7 (pktgen: multiqueue etc.) tried to relax the pktgen restriction of one device per kernel thread, adding a '@' tag to device names. Problem is we dont perform check on full pktgen device name. This allows adding many time same 'device' to pktgen thread pgset "add_device eth0@0" one session later : pgset "add_device eth0@0" (This doesnt find previous device) This consumes ~1.5 MBytes of vmalloc memory per round and also triggers this warning : [ 673.186380] proc_dir_entry 'pktgen/eth0@0' already registered [ 673.186383] Modules linked in: pktgen ixgbe ehci_hcd psmouse mdio mousedev evdev [last unloaded: pktgen] [ 673.186406] Pid: 6219, comm: bash Tainted: G W 2.6.32-rc7-03302-g41cec6f-dirty #16 [ 673.186410] Call Trace: [ 673.186417] [] warn_slowpath_common+0x7b/0xc0 [ 673.186422] [] warn_slowpath_fmt+0x41/0x50 [ 673.186426] [] proc_register+0x109/0x210 [ 673.186433] [] ? apic_timer_interrupt+0xe/0x20 [ 673.186438] [] proc_create_data+0x75/0xd0 [ 673.186444] [] pktgen_thread_write+0x568/0x640 [pktgen] [ 673.186449] [] ? pktgen_thread_write+0x0/0x640 [pktgen] [ 673.186453] [] proc_reg_write+0x84/0xc0 [ 673.186458] [] vfs_write+0xb8/0x180 [ 673.186463] [] sys_write+0x51/0x90 [ 673.186468] [] system_call_fastpath+0x16/0x1b [ 673.186470] ---[ end trace ccbb991b0a8d994d ]--- Solution to this problem is to use a odevname field (includes @ tag and suffix), instead of using netdevice name. Signed-off-by: Eric Dumazet Signed-off-by: Robert Olsson Signed-off-by: David S. Miller --- net/core/pktgen.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 6eb8d47cbf3a..54c634fab6c3 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -363,6 +363,7 @@ struct pktgen_dev { * device name (not when the inject is * started as it used to do.) */ + char odevname[32]; struct flow_state *flows; unsigned cflows; /* Concurrent flows (config) */ unsigned lflow; /* Flow length (config) */ @@ -528,7 +529,7 @@ static int pktgen_if_show(struct seq_file *seq, void *v) seq_printf(seq, " frags: %d delay: %llu clone_skb: %d ifname: %s\n", pkt_dev->nfrags, (unsigned long long) pkt_dev->delay, - pkt_dev->clone_skb, pkt_dev->odev->name); + pkt_dev->clone_skb, pkt_dev->odevname); seq_printf(seq, " flows: %u flowlen: %u\n", pkt_dev->cflows, pkt_dev->lflow); @@ -1688,13 +1689,13 @@ static int pktgen_thread_show(struct seq_file *seq, void *v) if_lock(t); list_for_each_entry(pkt_dev, &t->if_list, list) if (pkt_dev->running) - seq_printf(seq, "%s ", pkt_dev->odev->name); + seq_printf(seq, "%s ", pkt_dev->odevname); seq_printf(seq, "\nStopped: "); list_for_each_entry(pkt_dev, &t->if_list, list) if (!pkt_dev->running) - seq_printf(seq, "%s ", pkt_dev->odev->name); + seq_printf(seq, "%s ", pkt_dev->odevname); if (t->result[0]) seq_printf(seq, "\nResult: %s\n", t->result); @@ -1994,7 +1995,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) "queue_map_min (zero-based) (%d) exceeds valid range " "[0 - %d] for (%d) queues on %s, resetting\n", pkt_dev->queue_map_min, (ntxq ?: 1) - 1, ntxq, - pkt_dev->odev->name); + pkt_dev->odevname); pkt_dev->queue_map_min = ntxq - 1; } if (pkt_dev->queue_map_max >= ntxq) { @@ -2002,7 +2003,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev) "queue_map_max (zero-based) (%d) exceeds valid range " "[0 - %d] for (%d) queues on %s, resetting\n", pkt_dev->queue_map_max, (ntxq ?: 1) - 1, ntxq, - pkt_dev->odev->name); + pkt_dev->odevname); pkt_dev->queue_map_max = ntxq - 1; } @@ -3262,7 +3263,7 @@ static int pktgen_stop_device(struct pktgen_dev *pkt_dev) if (!pkt_dev->running) { printk(KERN_WARNING "pktgen: interface: %s is already " - "stopped\n", pkt_dev->odev->name); + "stopped\n", pkt_dev->odevname); return -EINVAL; } @@ -3464,7 +3465,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev) default: /* Drivers are not supposed to return other values! */ if (net_ratelimit()) pr_info("pktgen: %s xmit error: %d\n", - odev->name, ret); + pkt_dev->odevname, ret); pkt_dev->errors++; /* fallthru */ case NETDEV_TX_LOCKED: @@ -3572,7 +3573,7 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, if_lock(t); list_for_each_entry(p, &t->if_list, list) - if (strncmp(p->odev->name, ifname, IFNAMSIZ) == 0) { + if (strncmp(p->odevname, ifname, IFNAMSIZ) == 0) { pkt_dev = p; break; } @@ -3628,6 +3629,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname) if (!pkt_dev) return -ENOMEM; + strcpy(pkt_dev->odevname, ifname); pkt_dev->flows = vmalloc(MAX_CFLOWS * sizeof(struct flow_state)); if (pkt_dev->flows == NULL) { kfree(pkt_dev); -- cgit v1.2.3 From 45ba564d765d6165330e9bb14a197bdd348c114d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 23 Nov 2009 11:27:30 +0100 Subject: rfkill: fix miscdev ops The /dev/rfkill ops don't refer to the module, so it is possible to unload the module while file descriptors are open. Fix this oversight. Reported-by: Maxim Levitsky Cc: stable@kernel.org Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/rfkill/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/rfkill/core.c b/net/rfkill/core.c index dbeaf2983822..7cb57ff6bafa 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -1188,6 +1188,7 @@ static long rfkill_fop_ioctl(struct file *file, unsigned int cmd, #endif static const struct file_operations rfkill_fops = { + .owner = THIS_MODULE, .open = rfkill_fop_open, .read = rfkill_fop_read, .write = rfkill_fop_write, -- cgit v1.2.3 From 3e9848403ad59c53b31facb30b43ca80135ae0b9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 24 Nov 2009 14:50:53 -0800 Subject: pktgen: Fix netdevice unregister When multi queue compatable names are used by pktgen (eg eth0@0), we currently cannot unload a NIC driver if one of its device is currently in use. Allow pktgen_find_dev() to find pktgen devices by their suffix (netdev name) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- net/core/pktgen.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 54c634fab6c3..6e79e96cb4f2 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -427,7 +427,7 @@ static const char version[] = static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *i); static int pktgen_add_device(struct pktgen_thread *t, const char *ifname); static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, - const char *ifname); + const char *ifname, bool exact); static int pktgen_device_event(struct notifier_block *, unsigned long, void *); static void pktgen_run_all_threads(void); static void pktgen_reset_all_threads(void); @@ -1818,9 +1818,10 @@ static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove) { struct pktgen_thread *t; struct pktgen_dev *pkt_dev = NULL; + bool exact = (remove == FIND); list_for_each_entry(t, &pktgen_threads, th_list) { - pkt_dev = pktgen_find_dev(t, ifname); + pkt_dev = pktgen_find_dev(t, ifname, exact); if (pkt_dev) { if (remove) { if_lock(t); @@ -3567,13 +3568,18 @@ static int pktgen_thread_worker(void *arg) } static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, - const char *ifname) + const char *ifname, bool exact) { struct pktgen_dev *p, *pkt_dev = NULL; - if_lock(t); + size_t len = strlen(ifname); + if_lock(t); list_for_each_entry(p, &t->if_list, list) - if (strncmp(p->odevname, ifname, IFNAMSIZ) == 0) { + if (strncmp(p->odevname, ifname, len) == 0) { + if (p->odevname[len]) { + if (exact || p->odevname[len] != '@') + continue; + } pkt_dev = p; break; } -- cgit v1.2.3 From 5fdd4baef6195a1f2960e901c8877e2105f832ca Mon Sep 17 00:00:00 2001 From: Andrei Pelinescu-Onciul Date: Sun, 29 Nov 2009 00:14:02 -0800 Subject: sctp: on T3_RTX retransmit all the in-flight chunks When retransmitting due to T3 timeout, retransmit all the in-flight chunks for the corresponding transport/path, including chunks sent less then 1 rto ago. This is the correct behaviour according to rfc4960 section 6.3.3 E3 and "Note: Any DATA chunks that were sent to the address for which the T3-rtx timer expired but did not fit in one MTU (rule E3 above) should be marked for retransmission and sent as soon as cwnd allows (normally, when a SACK arrives). ". This fixes problems when more then one path is present and the T3 retransmission of the first chunk that timeouts stops the T3 timer for the initial active path, leaving all the other in-flight chunks waiting forever or until a new chunk is transmitted on the same path and timeouts (and this will happen only if the cwnd allows sending new chunks, but since cwnd was dropped to MTU by the timeout => it will wait until the first heartbeat). Example: 10 packets in flight, sent at 0.1 s intervals on the primary path. The primary path is down and the first packet timeouts. The first packet is retransmitted on another path, the T3 timer for the primary path is stopped and cwnd is set to MTU. All the other 9 in-flight packets will not be retransmitted (unless more new packets are sent on the primary path which depend on cwnd allowing it, and even in this case the 9 packets will be retransmitted only after a new packet timeouts which even in the best case would be more then RTO). This commit reverts d0ce92910bc04e107b2f3f2048f07e94f570035d and also removes the now unused transport->last_rto, introduced in b6157d8e03e1e780660a328f7183bcbfa4a93a19. p.s The problem is not only when multiple paths are there. It can happen in a single homed environment. If the application stops sending data, it possible to have a hung association. Signed-off-by: Andrei Pelinescu-Onciul Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/outqueue.c | 10 ---------- net/sctp/sm_sideeffect.c | 1 - net/sctp/transport.c | 5 ++--- 3 files changed, 2 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index c9f20e28521b..23e5e97aa617 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -423,16 +423,6 @@ void sctp_retransmit_mark(struct sctp_outq *q, if ((reason == SCTP_RTXR_FAST_RTX && (chunk->fast_retransmit == SCTP_NEED_FRTX)) || (reason != SCTP_RTXR_FAST_RTX && !chunk->tsn_gap_acked)) { - /* If this chunk was sent less then 1 rto ago, do not - * retransmit this chunk, but give the peer time - * to acknowlege it. Do this only when - * retransmitting due to T3 timeout. - */ - if (reason == SCTP_RTXR_T3_RTX && - time_before(jiffies, chunk->sent_at + - transport->last_rto)) - continue; - /* RFC 2960 6.2.1 Processing a Received SACK * * C) Any time a DATA chunk is marked for diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 8674d4919556..efa516b47e81 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -480,7 +480,6 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc, * that indicates that we have an outstanding HB. */ if (!is_hb || transport->hb_sent) { - transport->last_rto = transport->rto; transport->rto = min((transport->rto * 2), transport->asoc->rto_max); } } diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 3b141bb32faf..37a1184d789f 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -74,7 +74,7 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, * given destination transport address, set RTO to the protocol * parameter 'RTO.Initial'. */ - peer->last_rto = peer->rto = msecs_to_jiffies(sctp_rto_initial); + peer->rto = msecs_to_jiffies(sctp_rto_initial); peer->rtt = 0; peer->rttvar = 0; peer->srtt = 0; @@ -386,7 +386,6 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) tp->rto = tp->asoc->rto_max; tp->rtt = rtt; - tp->last_rto = tp->rto; /* Reset rto_pending so that a new RTT measurement is started when a * new data chunk is sent. @@ -602,7 +601,7 @@ void sctp_transport_reset(struct sctp_transport *t) */ t->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380)); t->ssthresh = asoc->peer.i.a_rwnd; - t->last_rto = t->rto = asoc->rto_initial; + t->rto = asoc->rto_initial; t->rtt = 0; t->srtt = 0; t->rttvar = 0; -- cgit v1.2.3 From bbf31bf18d34caa87dd01f08bf713635593697f2 Mon Sep 17 00:00:00 2001 From: David Ford Date: Sun, 29 Nov 2009 23:02:22 -0800 Subject: ipv4: additional update of dev_net(dev) to struct *net in ip_fragment.c, NULL ptr OOPS ipv4 ip_frag_reasm(), fully replace 'dev_net(dev)' with 'net', defined previously patched into 2.6.29. Between 2.6.28.10 and 2.6.29, net/ipv4/ip_fragment.c was patched, changing from dev_net(dev) to container_of(...). Unfortunately the goto section (out_fail) on oversized packets inside ip_frag_reasm() didn't get touched up as well. Oversized IP packets cause a NULL pointer dereference and immediate hang. I discovered this running openvasd and my previous email on this is titled: NULL pointer dereference at 2.6.32-rc8:net/ipv4/ip_fragment.c:566 Signed-off-by: David Ford Signed-off-by: David S. Miller --- net/ipv4/ip_fragment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 575f9bd51ccd..d3fe10be7219 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -563,7 +563,7 @@ out_oversize: printk(KERN_INFO "Oversized IP packet from %pI4.\n", &qp->saddr); out_fail: - IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_REASMFAILS); + IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS); return err; } -- cgit v1.2.3 From 4253119acf412fd686ef4bd8749b5a4d70ea3a51 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 20 Nov 2009 09:15:51 +0100 Subject: mac80211: fix two remote exploits Lennert Buytenhek noticed a remotely triggerable problem in mac80211, which is due to some code shuffling I did that ended up changing the order in which things were done -- this was in commit d75636ef9c1af224f1097941879d5a8db7cd04e5 Author: Johannes Berg Date: Tue Feb 10 21:25:53 2009 +0100 mac80211: RX aggregation: clean up stop session The problem is that the BUG_ON moved before the various checks, and as such can be triggered. As the comment indicates, the BUG_ON can be removed since the ampdu_action callback must already exist when the state is OPERATIONAL. A similar code path leads to a WARN_ON in ieee80211_stop_tx_ba_session, which can also be removed. Cc: stable@kernel.org [2.6.29+] Cc: Lennert Buytenhek Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-rx.c | 4 ---- net/mac80211/agg-tx.c | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'net') diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index bc064d7933ff..ce8e0e772bab 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -85,10 +85,6 @@ void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *r struct ieee80211_local *local = sdata->local; struct sta_info *sta; - /* stop HW Rx aggregation. ampdu_action existence - * already verified in session init so we add the BUG_ON */ - BUG_ON(!local->ops->ampdu_action); - rcu_read_lock(); sta = sta_info_get(local, ra); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 206fd82f0c76..63224d1ee8dd 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -545,7 +545,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, struct sta_info *sta; int ret = 0; - if (WARN_ON(!local->ops->ampdu_action)) + if (!local->ops->ampdu_action) return -EINVAL; if (tid >= STA_TID_NUM) -- cgit v1.2.3 From 827d42c9ac91ddd728e4f4a31fefb906ef2ceff7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 22 Nov 2009 12:28:41 +0100 Subject: mac80211: fix spurious delBA handling Lennert Buytenhek noticed that delBA handling in mac80211 was broken and has remotely triggerable problems, some of which are due to some code shuffling I did that ended up changing the order in which things were done -- this was commit d75636ef9c1af224f1097941879d5a8db7cd04e5 Author: Johannes Berg Date: Tue Feb 10 21:25:53 2009 +0100 mac80211: RX aggregation: clean up stop session and other parts were already present in the original commit d92684e66091c0f0101819619b315b4bb8b5bcc5 Author: Ron Rindjunsky Date: Mon Jan 28 14:07:22 2008 +0200 mac80211: A-MPDU Tx add delBA from recipient support The first problem is that I moved a BUG_ON before various checks -- thereby making it possible to hit. As the comment indicates, the BUG_ON can be removed since the ampdu_action callback must already exist when the state is != IDLE. The second problem isn't easily exploitable but there's a race condition due to unconditionally setting the state to OPERATIONAL when a delBA frame is received, even when no aggregation session was ever initiated. All the drivers accept stopping the session even then, but that opens a race window where crashes could happen before the driver accepts it. Right now, a WARN_ON may happen with non-HT drivers, while the race opens only for HT drivers. For this case, there are two things necessary to fix it: 1) don't process spurious delBA frames, and be more careful about the session state; don't drop the lock 2) HT drivers need to be prepared to handle a session stop even before the session was really started -- this is true for all drivers (that support aggregation) but iwlwifi which can be fixed easily. The other HT drivers (ath9k and ar9170) are behaving properly already. Reported-by: Lennert Buytenhek Cc: stable@kernel.org Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 15 +++++++-------- net/mac80211/ht.c | 8 +++----- net/mac80211/ieee80211_i.h | 2 ++ 3 files changed, 12 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 63224d1ee8dd..89e238b001de 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -123,13 +123,18 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1 ieee80211_tx_skb(sdata, skb, 0); } -static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, - enum ieee80211_back_parties initiator) +int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, + enum ieee80211_back_parties initiator) { struct ieee80211_local *local = sta->local; int ret; u8 *state; +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", + sta->sta.addr, tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + state = &sta->ampdu_mlme.tid_state_tx[tid]; if (*state == HT_AGG_STATE_OPERATIONAL) @@ -143,7 +148,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, /* HW shall not deny going back to legacy */ if (WARN_ON(ret)) { - *state = HT_AGG_STATE_OPERATIONAL; /* * We may have pending packets get stuck in this case... * Not bothering with a workaround for now. @@ -525,11 +529,6 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, goto unlock; } -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", - sta->sta.addr, tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - ret = ___ieee80211_stop_tx_ba_session(sta, tid, initiator); unlock: diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 48ef1a282b91..cdc58e61d921 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -141,7 +141,6 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee80211_mgmt *mgmt, size_t len) { - struct ieee80211_local *local = sdata->local; u16 tid, params; u16 initiator; @@ -161,10 +160,9 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, WLAN_BACK_INITIATOR, 0); else { /* WLAN_BACK_RECIPIENT */ spin_lock_bh(&sta->lock); - sta->ampdu_mlme.tid_state_tx[tid] = - HT_AGG_STATE_OPERATIONAL; + if (sta->ampdu_mlme.tid_state_tx[tid] & HT_ADDBA_REQUESTED_MSK) + ___ieee80211_stop_tx_ba_session(sta, tid, + WLAN_BACK_RECIPIENT); spin_unlock_bh(&sta->lock); - ieee80211_stop_tx_ba_session(&local->hw, sta->sta.addr, tid, - WLAN_BACK_RECIPIENT); } } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a910bf1f092f..10d316e455de 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1091,6 +1091,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, enum ieee80211_back_parties initiator); +int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, + enum ieee80211_back_parties initiator); /* Spectrum management */ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, -- cgit v1.2.3