diff options
Diffstat (limited to 'net')
52 files changed, 1495 insertions, 1126 deletions
diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c index 80caad1a31a5..6ef0e761e5de 100644 --- a/net/appletalk/atalk_proc.c +++ b/net/appletalk/atalk_proc.c | |||
@@ -144,40 +144,16 @@ out: | |||
144 | return 0; | 144 | return 0; |
145 | } | 145 | } |
146 | 146 | ||
147 | static __inline__ struct sock *atalk_get_socket_idx(loff_t pos) | ||
148 | { | ||
149 | struct sock *s; | ||
150 | struct hlist_node *node; | ||
151 | |||
152 | sk_for_each(s, node, &atalk_sockets) | ||
153 | if (!pos--) | ||
154 | goto found; | ||
155 | s = NULL; | ||
156 | found: | ||
157 | return s; | ||
158 | } | ||
159 | |||
160 | static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos) | 147 | static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos) |
161 | __acquires(atalk_sockets_lock) | 148 | __acquires(atalk_sockets_lock) |
162 | { | 149 | { |
163 | loff_t l = *pos; | ||
164 | |||
165 | read_lock_bh(&atalk_sockets_lock); | 150 | read_lock_bh(&atalk_sockets_lock); |
166 | return l ? atalk_get_socket_idx(--l) : SEQ_START_TOKEN; | 151 | return seq_hlist_start_head(&atalk_sockets, *pos); |
167 | } | 152 | } |
168 | 153 | ||
169 | static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) | 154 | static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) |
170 | { | 155 | { |
171 | struct sock *i; | 156 | return seq_hlist_next(v, &atalk_sockets, pos); |
172 | |||
173 | ++*pos; | ||
174 | if (v == SEQ_START_TOKEN) { | ||
175 | i = sk_head(&atalk_sockets); | ||
176 | goto out; | ||
177 | } | ||
178 | i = sk_next(v); | ||
179 | out: | ||
180 | return i; | ||
181 | } | 157 | } |
182 | 158 | ||
183 | static void atalk_seq_socket_stop(struct seq_file *seq, void *v) | 159 | static void atalk_seq_socket_stop(struct seq_file *seq, void *v) |
@@ -197,7 +173,7 @@ static int atalk_seq_socket_show(struct seq_file *seq, void *v) | |||
197 | goto out; | 173 | goto out; |
198 | } | 174 | } |
199 | 175 | ||
200 | s = v; | 176 | s = sk_entry(v); |
201 | at = at_sk(s); | 177 | at = at_sk(s); |
202 | 178 | ||
203 | seq_printf(seq, "%02X %04X:%02X:%02X %04X:%02X:%02X %08X:%08X " | 179 | seq_printf(seq, "%02X %04X:%02X:%02X %04X:%02X:%02X %08X:%08X " |
diff --git a/net/atm/proc.c b/net/atm/proc.c index 476779d845eb..7a96b2376bd7 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c | |||
@@ -238,7 +238,7 @@ static int atm_dev_seq_show(struct seq_file *seq, void *v) | |||
238 | "Itf Type ESI/\"MAC\"addr " | 238 | "Itf Type ESI/\"MAC\"addr " |
239 | "AAL(TX,err,RX,err,drop) ... [refcnt]\n"; | 239 | "AAL(TX,err,RX,err,drop) ... [refcnt]\n"; |
240 | 240 | ||
241 | if (v == SEQ_START_TOKEN) | 241 | if (v == &atm_devs) |
242 | seq_puts(seq, atm_dev_banner); | 242 | seq_puts(seq, atm_dev_banner); |
243 | else { | 243 | else { |
244 | struct atm_dev *dev = list_entry(v, struct atm_dev, dev_list); | 244 | struct atm_dev *dev = list_entry(v, struct atm_dev, dev_list); |
diff --git a/net/atm/resources.c b/net/atm/resources.c index 447ed89205d8..90082904f20d 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c | |||
@@ -444,21 +444,10 @@ done: | |||
444 | return error; | 444 | return error; |
445 | } | 445 | } |
446 | 446 | ||
447 | static inline void *dev_get_idx(loff_t left) | ||
448 | { | ||
449 | struct list_head *p; | ||
450 | |||
451 | list_for_each(p, &atm_devs) { | ||
452 | if (!--left) | ||
453 | break; | ||
454 | } | ||
455 | return (p != &atm_devs) ? p : NULL; | ||
456 | } | ||
457 | |||
458 | void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) | 447 | void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) |
459 | { | 448 | { |
460 | mutex_lock(&atm_dev_mutex); | 449 | mutex_lock(&atm_dev_mutex); |
461 | return *pos ? dev_get_idx(*pos) : SEQ_START_TOKEN; | 450 | return seq_list_start_head(&atm_devs, *pos); |
462 | } | 451 | } |
463 | 452 | ||
464 | void atm_dev_seq_stop(struct seq_file *seq, void *v) | 453 | void atm_dev_seq_stop(struct seq_file *seq, void *v) |
@@ -468,8 +457,5 @@ void atm_dev_seq_stop(struct seq_file *seq, void *v) | |||
468 | 457 | ||
469 | void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 458 | void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
470 | { | 459 | { |
471 | ++*pos; | 460 | return seq_list_next(v, &atm_devs, pos); |
472 | v = (v == SEQ_START_TOKEN) | ||
473 | ? atm_devs.next : ((struct list_head *)v)->next; | ||
474 | return (v == &atm_devs) ? NULL : v; | ||
475 | } | 461 | } |
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 5588ba69c468..a5beedf43e2d 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c | |||
@@ -1863,25 +1863,13 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1863 | static void *ax25_info_start(struct seq_file *seq, loff_t *pos) | 1863 | static void *ax25_info_start(struct seq_file *seq, loff_t *pos) |
1864 | __acquires(ax25_list_lock) | 1864 | __acquires(ax25_list_lock) |
1865 | { | 1865 | { |
1866 | struct ax25_cb *ax25; | ||
1867 | struct hlist_node *node; | ||
1868 | int i = 0; | ||
1869 | |||
1870 | spin_lock_bh(&ax25_list_lock); | 1866 | spin_lock_bh(&ax25_list_lock); |
1871 | ax25_for_each(ax25, node, &ax25_list) { | 1867 | return seq_hlist_start(&ax25_list, *pos); |
1872 | if (i == *pos) | ||
1873 | return ax25; | ||
1874 | ++i; | ||
1875 | } | ||
1876 | return NULL; | ||
1877 | } | 1868 | } |
1878 | 1869 | ||
1879 | static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos) | 1870 | static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos) |
1880 | { | 1871 | { |
1881 | ++*pos; | 1872 | return seq_hlist_next(v, &ax25_list, pos); |
1882 | |||
1883 | return hlist_entry( ((struct ax25_cb *)v)->ax25_node.next, | ||
1884 | struct ax25_cb, ax25_node); | ||
1885 | } | 1873 | } |
1886 | 1874 | ||
1887 | static void ax25_info_stop(struct seq_file *seq, void *v) | 1875 | static void ax25_info_stop(struct seq_file *seq, void *v) |
@@ -1892,7 +1880,7 @@ static void ax25_info_stop(struct seq_file *seq, void *v) | |||
1892 | 1880 | ||
1893 | static int ax25_info_show(struct seq_file *seq, void *v) | 1881 | static int ax25_info_show(struct seq_file *seq, void *v) |
1894 | { | 1882 | { |
1895 | ax25_cb *ax25 = v; | 1883 | ax25_cb *ax25 = hlist_entry(v, struct ax25_cb, ax25_node); |
1896 | char buf[11]; | 1884 | char buf[11]; |
1897 | int k; | 1885 | int k; |
1898 | 1886 | ||
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c index 832bcf092a01..9f13f6eefcba 100644 --- a/net/ax25/ax25_uid.c +++ b/net/ax25/ax25_uid.c | |||
@@ -146,31 +146,13 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) | |||
146 | static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) | 146 | static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) |
147 | __acquires(ax25_uid_lock) | 147 | __acquires(ax25_uid_lock) |
148 | { | 148 | { |
149 | struct ax25_uid_assoc *pt; | ||
150 | struct hlist_node *node; | ||
151 | int i = 1; | ||
152 | |||
153 | read_lock(&ax25_uid_lock); | 149 | read_lock(&ax25_uid_lock); |
154 | 150 | return seq_hlist_start_head(&ax25_uid_list, *pos); | |
155 | if (*pos == 0) | ||
156 | return SEQ_START_TOKEN; | ||
157 | |||
158 | ax25_uid_for_each(pt, node, &ax25_uid_list) { | ||
159 | if (i == *pos) | ||
160 | return pt; | ||
161 | ++i; | ||
162 | } | ||
163 | return NULL; | ||
164 | } | 151 | } |
165 | 152 | ||
166 | static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 153 | static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
167 | { | 154 | { |
168 | ++*pos; | 155 | return seq_hlist_next(v, &ax25_uid_list, pos); |
169 | if (v == SEQ_START_TOKEN) | ||
170 | return ax25_uid_list.first; | ||
171 | else | ||
172 | return hlist_entry(((ax25_uid_assoc *)v)->uid_node.next, | ||
173 | ax25_uid_assoc, uid_node); | ||
174 | } | 156 | } |
175 | 157 | ||
176 | static void ax25_uid_seq_stop(struct seq_file *seq, void *v) | 158 | static void ax25_uid_seq_stop(struct seq_file *seq, void *v) |
@@ -186,8 +168,9 @@ static int ax25_uid_seq_show(struct seq_file *seq, void *v) | |||
186 | if (v == SEQ_START_TOKEN) | 168 | if (v == SEQ_START_TOKEN) |
187 | seq_printf(seq, "Policy: %d\n", ax25_uid_policy); | 169 | seq_printf(seq, "Policy: %d\n", ax25_uid_policy); |
188 | else { | 170 | else { |
189 | struct ax25_uid_assoc *pt = v; | 171 | struct ax25_uid_assoc *pt; |
190 | 172 | ||
173 | pt = hlist_entry(v, struct ax25_uid_assoc, uid_node); | ||
191 | seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(buf, &pt->call)); | 174 | seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(buf, &pt->call)); |
192 | } | 175 | } |
193 | return 0; | 176 | return 0; |
diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index 26fb831ef7e0..b6234b73c4cf 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c | |||
@@ -64,7 +64,7 @@ static void bnep_net_set_mc_list(struct net_device *dev) | |||
64 | struct sk_buff *skb; | 64 | struct sk_buff *skb; |
65 | int size; | 65 | int size; |
66 | 66 | ||
67 | BT_DBG("%s mc_count %d", dev->name, dev->mc_count); | 67 | BT_DBG("%s mc_count %d", dev->name, netdev_mc_count(dev)); |
68 | 68 | ||
69 | size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2; | 69 | size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2; |
70 | skb = alloc_skb(size, GFP_ATOMIC); | 70 | skb = alloc_skb(size, GFP_ATOMIC); |
@@ -97,7 +97,9 @@ static void bnep_net_set_mc_list(struct net_device *dev) | |||
97 | 97 | ||
98 | /* FIXME: We should group addresses here. */ | 98 | /* FIXME: We should group addresses here. */ |
99 | 99 | ||
100 | for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) { | 100 | for (i = 0; |
101 | i < netdev_mc_count(dev) && i < BNEP_MAX_MULTICAST_FILTERS; | ||
102 | i++) { | ||
101 | memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); | 103 | memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); |
102 | memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); | 104 | memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN); |
103 | dmi = dmi->next; | 105 | dmi = dmi->next; |
diff --git a/net/core/dev.c b/net/core/dev.c index 94c1eeed25e5..d1cf53d0d597 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -4263,7 +4263,7 @@ static void dev_addr_discard(struct net_device *dev) | |||
4263 | netif_addr_lock_bh(dev); | 4263 | netif_addr_lock_bh(dev); |
4264 | 4264 | ||
4265 | __dev_addr_discard(&dev->mc_list); | 4265 | __dev_addr_discard(&dev->mc_list); |
4266 | dev->mc_count = 0; | 4266 | netdev_mc_count(dev) = 0; |
4267 | 4267 | ||
4268 | netif_addr_unlock_bh(dev); | 4268 | netif_addr_unlock_bh(dev); |
4269 | } | 4269 | } |
@@ -5419,6 +5419,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, | |||
5419 | 5419 | ||
5420 | netdev_init_queues(dev); | 5420 | netdev_init_queues(dev); |
5421 | 5421 | ||
5422 | INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list); | ||
5423 | dev->ethtool_ntuple_list.count = 0; | ||
5422 | INIT_LIST_HEAD(&dev->napi_list); | 5424 | INIT_LIST_HEAD(&dev->napi_list); |
5423 | INIT_LIST_HEAD(&dev->unreg_list); | 5425 | INIT_LIST_HEAD(&dev->unreg_list); |
5424 | INIT_LIST_HEAD(&dev->link_watch_list); | 5426 | INIT_LIST_HEAD(&dev->link_watch_list); |
@@ -5455,6 +5457,9 @@ void free_netdev(struct net_device *dev) | |||
5455 | /* Flush device addresses */ | 5457 | /* Flush device addresses */ |
5456 | dev_addr_flush(dev); | 5458 | dev_addr_flush(dev); |
5457 | 5459 | ||
5460 | /* Clear ethtool n-tuple list */ | ||
5461 | ethtool_ntuple_flush(dev); | ||
5462 | |||
5458 | list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) | 5463 | list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) |
5459 | netif_napi_del(p); | 5464 | netif_napi_del(p); |
5460 | 5465 | ||
diff --git a/net/core/ethtool.c b/net/core/ethtool.c index d8aee584e8d1..82cae3bca78d 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -120,7 +120,7 @@ int ethtool_op_set_ufo(struct net_device *dev, u32 data) | |||
120 | * NETIF_F_xxx values in include/linux/netdevice.h | 120 | * NETIF_F_xxx values in include/linux/netdevice.h |
121 | */ | 121 | */ |
122 | static const u32 flags_dup_features = | 122 | static const u32 flags_dup_features = |
123 | ETH_FLAG_LRO; | 123 | (ETH_FLAG_LRO | ETH_FLAG_NTUPLE); |
124 | 124 | ||
125 | u32 ethtool_op_get_flags(struct net_device *dev) | 125 | u32 ethtool_op_get_flags(struct net_device *dev) |
126 | { | 126 | { |
@@ -134,19 +134,42 @@ u32 ethtool_op_get_flags(struct net_device *dev) | |||
134 | 134 | ||
135 | int ethtool_op_set_flags(struct net_device *dev, u32 data) | 135 | int ethtool_op_set_flags(struct net_device *dev, u32 data) |
136 | { | 136 | { |
137 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
138 | |||
137 | if (data & ETH_FLAG_LRO) | 139 | if (data & ETH_FLAG_LRO) |
138 | dev->features |= NETIF_F_LRO; | 140 | dev->features |= NETIF_F_LRO; |
139 | else | 141 | else |
140 | dev->features &= ~NETIF_F_LRO; | 142 | dev->features &= ~NETIF_F_LRO; |
141 | 143 | ||
144 | if (data & ETH_FLAG_NTUPLE) { | ||
145 | if (!ops->set_rx_ntuple) | ||
146 | return -EOPNOTSUPP; | ||
147 | dev->features |= NETIF_F_NTUPLE; | ||
148 | } else { | ||
149 | /* safe to clear regardless */ | ||
150 | dev->features &= ~NETIF_F_NTUPLE; | ||
151 | } | ||
152 | |||
142 | return 0; | 153 | return 0; |
143 | } | 154 | } |
144 | 155 | ||
156 | void ethtool_ntuple_flush(struct net_device *dev) | ||
157 | { | ||
158 | struct ethtool_rx_ntuple_flow_spec_container *fsc, *f; | ||
159 | |||
160 | list_for_each_entry_safe(fsc, f, &dev->ethtool_ntuple_list.list, list) { | ||
161 | list_del(&fsc->list); | ||
162 | kfree(fsc); | ||
163 | } | ||
164 | dev->ethtool_ntuple_list.count = 0; | ||
165 | } | ||
166 | EXPORT_SYMBOL(ethtool_ntuple_flush); | ||
167 | |||
145 | /* Handlers for each ethtool command */ | 168 | /* Handlers for each ethtool command */ |
146 | 169 | ||
147 | static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) | 170 | static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) |
148 | { | 171 | { |
149 | struct ethtool_cmd cmd = { ETHTOOL_GSET }; | 172 | struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET }; |
150 | int err; | 173 | int err; |
151 | 174 | ||
152 | if (!dev->ethtool_ops->get_settings) | 175 | if (!dev->ethtool_ops->get_settings) |
@@ -174,7 +197,10 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr) | |||
174 | return dev->ethtool_ops->set_settings(dev, &cmd); | 197 | return dev->ethtool_ops->set_settings(dev, &cmd); |
175 | } | 198 | } |
176 | 199 | ||
177 | static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr) | 200 | /* |
201 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
202 | */ | ||
203 | static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr) | ||
178 | { | 204 | { |
179 | struct ethtool_drvinfo info; | 205 | struct ethtool_drvinfo info; |
180 | const struct ethtool_ops *ops = dev->ethtool_ops; | 206 | const struct ethtool_ops *ops = dev->ethtool_ops; |
@@ -209,7 +235,10 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr) | |||
209 | return 0; | 235 | return 0; |
210 | } | 236 | } |
211 | 237 | ||
212 | static int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr) | 238 | /* |
239 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
240 | */ | ||
241 | static noinline int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr) | ||
213 | { | 242 | { |
214 | struct ethtool_rxnfc cmd; | 243 | struct ethtool_rxnfc cmd; |
215 | 244 | ||
@@ -222,7 +251,10 @@ static int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr) | |||
222 | return dev->ethtool_ops->set_rxnfc(dev, &cmd); | 251 | return dev->ethtool_ops->set_rxnfc(dev, &cmd); |
223 | } | 252 | } |
224 | 253 | ||
225 | static int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr) | 254 | /* |
255 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
256 | */ | ||
257 | static noinline int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr) | ||
226 | { | 258 | { |
227 | struct ethtool_rxnfc info; | 259 | struct ethtool_rxnfc info; |
228 | const struct ethtool_ops *ops = dev->ethtool_ops; | 260 | const struct ethtool_ops *ops = dev->ethtool_ops; |
@@ -266,6 +298,315 @@ err_out: | |||
266 | return ret; | 298 | return ret; |
267 | } | 299 | } |
268 | 300 | ||
301 | static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list, | ||
302 | struct ethtool_rx_ntuple_flow_spec *spec, | ||
303 | struct ethtool_rx_ntuple_flow_spec_container *fsc) | ||
304 | { | ||
305 | |||
306 | /* don't add filters forever */ | ||
307 | if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) { | ||
308 | /* free the container */ | ||
309 | kfree(fsc); | ||
310 | return; | ||
311 | } | ||
312 | |||
313 | /* Copy the whole filter over */ | ||
314 | fsc->fs.flow_type = spec->flow_type; | ||
315 | memcpy(&fsc->fs.h_u, &spec->h_u, sizeof(spec->h_u)); | ||
316 | memcpy(&fsc->fs.m_u, &spec->m_u, sizeof(spec->m_u)); | ||
317 | |||
318 | fsc->fs.vlan_tag = spec->vlan_tag; | ||
319 | fsc->fs.vlan_tag_mask = spec->vlan_tag_mask; | ||
320 | fsc->fs.data = spec->data; | ||
321 | fsc->fs.data_mask = spec->data_mask; | ||
322 | fsc->fs.action = spec->action; | ||
323 | |||
324 | /* add to the list */ | ||
325 | list_add_tail_rcu(&fsc->list, &list->list); | ||
326 | list->count++; | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
331 | */ | ||
332 | static noinline int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr) | ||
333 | { | ||
334 | struct ethtool_rx_ntuple cmd; | ||
335 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
336 | struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL; | ||
337 | int ret; | ||
338 | |||
339 | if (!(dev->features & NETIF_F_NTUPLE)) | ||
340 | return -EINVAL; | ||
341 | |||
342 | if (copy_from_user(&cmd, useraddr, sizeof(cmd))) | ||
343 | return -EFAULT; | ||
344 | |||
345 | /* | ||
346 | * Cache filter in dev struct for GET operation only if | ||
347 | * the underlying driver doesn't have its own GET operation, and | ||
348 | * only if the filter was added successfully. First make sure we | ||
349 | * can allocate the filter, then continue if successful. | ||
350 | */ | ||
351 | if (!ops->get_rx_ntuple) { | ||
352 | fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC); | ||
353 | if (!fsc) | ||
354 | return -ENOMEM; | ||
355 | } | ||
356 | |||
357 | ret = ops->set_rx_ntuple(dev, &cmd); | ||
358 | if (ret) { | ||
359 | kfree(fsc); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | if (!ops->get_rx_ntuple) | ||
364 | __rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs, fsc); | ||
365 | |||
366 | return ret; | ||
367 | } | ||
368 | |||
369 | static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr) | ||
370 | { | ||
371 | struct ethtool_gstrings gstrings; | ||
372 | const struct ethtool_ops *ops = dev->ethtool_ops; | ||
373 | struct ethtool_rx_ntuple_flow_spec_container *fsc; | ||
374 | u8 *data; | ||
375 | char *p; | ||
376 | int ret, i, num_strings = 0; | ||
377 | |||
378 | if (!ops->get_sset_count) | ||
379 | return -EOPNOTSUPP; | ||
380 | |||
381 | if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) | ||
382 | return -EFAULT; | ||
383 | |||
384 | ret = ops->get_sset_count(dev, gstrings.string_set); | ||
385 | if (ret < 0) | ||
386 | return ret; | ||
387 | |||
388 | gstrings.len = ret; | ||
389 | |||
390 | data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER); | ||
391 | if (!data) | ||
392 | return -ENOMEM; | ||
393 | |||
394 | if (ops->get_rx_ntuple) { | ||
395 | /* driver-specific filter grab */ | ||
396 | ret = ops->get_rx_ntuple(dev, gstrings.string_set, data); | ||
397 | goto copy; | ||
398 | } | ||
399 | |||
400 | /* default ethtool filter grab */ | ||
401 | i = 0; | ||
402 | p = (char *)data; | ||
403 | list_for_each_entry(fsc, &dev->ethtool_ntuple_list.list, list) { | ||
404 | sprintf(p, "Filter %d:\n", i); | ||
405 | p += ETH_GSTRING_LEN; | ||
406 | num_strings++; | ||
407 | |||
408 | switch (fsc->fs.flow_type) { | ||
409 | case TCP_V4_FLOW: | ||
410 | sprintf(p, "\tFlow Type: TCP\n"); | ||
411 | p += ETH_GSTRING_LEN; | ||
412 | num_strings++; | ||
413 | break; | ||
414 | case UDP_V4_FLOW: | ||
415 | sprintf(p, "\tFlow Type: UDP\n"); | ||
416 | p += ETH_GSTRING_LEN; | ||
417 | num_strings++; | ||
418 | break; | ||
419 | case SCTP_V4_FLOW: | ||
420 | sprintf(p, "\tFlow Type: SCTP\n"); | ||
421 | p += ETH_GSTRING_LEN; | ||
422 | num_strings++; | ||
423 | break; | ||
424 | case AH_ESP_V4_FLOW: | ||
425 | sprintf(p, "\tFlow Type: AH ESP\n"); | ||
426 | p += ETH_GSTRING_LEN; | ||
427 | num_strings++; | ||
428 | break; | ||
429 | case ESP_V4_FLOW: | ||
430 | sprintf(p, "\tFlow Type: ESP\n"); | ||
431 | p += ETH_GSTRING_LEN; | ||
432 | num_strings++; | ||
433 | break; | ||
434 | case IP_USER_FLOW: | ||
435 | sprintf(p, "\tFlow Type: Raw IP\n"); | ||
436 | p += ETH_GSTRING_LEN; | ||
437 | num_strings++; | ||
438 | break; | ||
439 | case IPV4_FLOW: | ||
440 | sprintf(p, "\tFlow Type: IPv4\n"); | ||
441 | p += ETH_GSTRING_LEN; | ||
442 | num_strings++; | ||
443 | break; | ||
444 | default: | ||
445 | sprintf(p, "\tFlow Type: Unknown\n"); | ||
446 | p += ETH_GSTRING_LEN; | ||
447 | num_strings++; | ||
448 | goto unknown_filter; | ||
449 | }; | ||
450 | |||
451 | /* now the rest of the filters */ | ||
452 | switch (fsc->fs.flow_type) { | ||
453 | case TCP_V4_FLOW: | ||
454 | case UDP_V4_FLOW: | ||
455 | case SCTP_V4_FLOW: | ||
456 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
457 | fsc->fs.h_u.tcp_ip4_spec.ip4src); | ||
458 | p += ETH_GSTRING_LEN; | ||
459 | num_strings++; | ||
460 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
461 | fsc->fs.m_u.tcp_ip4_spec.ip4src); | ||
462 | p += ETH_GSTRING_LEN; | ||
463 | num_strings++; | ||
464 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
465 | fsc->fs.h_u.tcp_ip4_spec.ip4dst); | ||
466 | p += ETH_GSTRING_LEN; | ||
467 | num_strings++; | ||
468 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
469 | fsc->fs.m_u.tcp_ip4_spec.ip4dst); | ||
470 | p += ETH_GSTRING_LEN; | ||
471 | num_strings++; | ||
472 | sprintf(p, "\tSrc Port: %d, mask: 0x%x\n", | ||
473 | fsc->fs.h_u.tcp_ip4_spec.psrc, | ||
474 | fsc->fs.m_u.tcp_ip4_spec.psrc); | ||
475 | p += ETH_GSTRING_LEN; | ||
476 | num_strings++; | ||
477 | sprintf(p, "\tDest Port: %d, mask: 0x%x\n", | ||
478 | fsc->fs.h_u.tcp_ip4_spec.pdst, | ||
479 | fsc->fs.m_u.tcp_ip4_spec.pdst); | ||
480 | p += ETH_GSTRING_LEN; | ||
481 | num_strings++; | ||
482 | sprintf(p, "\tTOS: %d, mask: 0x%x\n", | ||
483 | fsc->fs.h_u.tcp_ip4_spec.tos, | ||
484 | fsc->fs.m_u.tcp_ip4_spec.tos); | ||
485 | p += ETH_GSTRING_LEN; | ||
486 | num_strings++; | ||
487 | break; | ||
488 | case AH_ESP_V4_FLOW: | ||
489 | case ESP_V4_FLOW: | ||
490 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
491 | fsc->fs.h_u.ah_ip4_spec.ip4src); | ||
492 | p += ETH_GSTRING_LEN; | ||
493 | num_strings++; | ||
494 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
495 | fsc->fs.m_u.ah_ip4_spec.ip4src); | ||
496 | p += ETH_GSTRING_LEN; | ||
497 | num_strings++; | ||
498 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
499 | fsc->fs.h_u.ah_ip4_spec.ip4dst); | ||
500 | p += ETH_GSTRING_LEN; | ||
501 | num_strings++; | ||
502 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
503 | fsc->fs.m_u.ah_ip4_spec.ip4dst); | ||
504 | p += ETH_GSTRING_LEN; | ||
505 | num_strings++; | ||
506 | sprintf(p, "\tSPI: %d, mask: 0x%x\n", | ||
507 | fsc->fs.h_u.ah_ip4_spec.spi, | ||
508 | fsc->fs.m_u.ah_ip4_spec.spi); | ||
509 | p += ETH_GSTRING_LEN; | ||
510 | num_strings++; | ||
511 | sprintf(p, "\tTOS: %d, mask: 0x%x\n", | ||
512 | fsc->fs.h_u.ah_ip4_spec.tos, | ||
513 | fsc->fs.m_u.ah_ip4_spec.tos); | ||
514 | p += ETH_GSTRING_LEN; | ||
515 | num_strings++; | ||
516 | break; | ||
517 | case IP_USER_FLOW: | ||
518 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
519 | fsc->fs.h_u.raw_ip4_spec.ip4src); | ||
520 | p += ETH_GSTRING_LEN; | ||
521 | num_strings++; | ||
522 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
523 | fsc->fs.m_u.raw_ip4_spec.ip4src); | ||
524 | p += ETH_GSTRING_LEN; | ||
525 | num_strings++; | ||
526 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
527 | fsc->fs.h_u.raw_ip4_spec.ip4dst); | ||
528 | p += ETH_GSTRING_LEN; | ||
529 | num_strings++; | ||
530 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
531 | fsc->fs.m_u.raw_ip4_spec.ip4dst); | ||
532 | p += ETH_GSTRING_LEN; | ||
533 | num_strings++; | ||
534 | break; | ||
535 | case IPV4_FLOW: | ||
536 | sprintf(p, "\tSrc IP addr: 0x%x\n", | ||
537 | fsc->fs.h_u.usr_ip4_spec.ip4src); | ||
538 | p += ETH_GSTRING_LEN; | ||
539 | num_strings++; | ||
540 | sprintf(p, "\tSrc IP mask: 0x%x\n", | ||
541 | fsc->fs.m_u.usr_ip4_spec.ip4src); | ||
542 | p += ETH_GSTRING_LEN; | ||
543 | num_strings++; | ||
544 | sprintf(p, "\tDest IP addr: 0x%x\n", | ||
545 | fsc->fs.h_u.usr_ip4_spec.ip4dst); | ||
546 | p += ETH_GSTRING_LEN; | ||
547 | num_strings++; | ||
548 | sprintf(p, "\tDest IP mask: 0x%x\n", | ||
549 | fsc->fs.m_u.usr_ip4_spec.ip4dst); | ||
550 | p += ETH_GSTRING_LEN; | ||
551 | num_strings++; | ||
552 | sprintf(p, "\tL4 bytes: 0x%x, mask: 0x%x\n", | ||
553 | fsc->fs.h_u.usr_ip4_spec.l4_4_bytes, | ||
554 | fsc->fs.m_u.usr_ip4_spec.l4_4_bytes); | ||
555 | p += ETH_GSTRING_LEN; | ||
556 | num_strings++; | ||
557 | sprintf(p, "\tTOS: %d, mask: 0x%x\n", | ||
558 | fsc->fs.h_u.usr_ip4_spec.tos, | ||
559 | fsc->fs.m_u.usr_ip4_spec.tos); | ||
560 | p += ETH_GSTRING_LEN; | ||
561 | num_strings++; | ||
562 | sprintf(p, "\tIP Version: %d, mask: 0x%x\n", | ||
563 | fsc->fs.h_u.usr_ip4_spec.ip_ver, | ||
564 | fsc->fs.m_u.usr_ip4_spec.ip_ver); | ||
565 | p += ETH_GSTRING_LEN; | ||
566 | num_strings++; | ||
567 | sprintf(p, "\tProtocol: %d, mask: 0x%x\n", | ||
568 | fsc->fs.h_u.usr_ip4_spec.proto, | ||
569 | fsc->fs.m_u.usr_ip4_spec.proto); | ||
570 | p += ETH_GSTRING_LEN; | ||
571 | num_strings++; | ||
572 | break; | ||
573 | }; | ||
574 | sprintf(p, "\tVLAN: %d, mask: 0x%x\n", | ||
575 | fsc->fs.vlan_tag, fsc->fs.vlan_tag_mask); | ||
576 | p += ETH_GSTRING_LEN; | ||
577 | num_strings++; | ||
578 | sprintf(p, "\tUser-defined: 0x%Lx\n", fsc->fs.data); | ||
579 | p += ETH_GSTRING_LEN; | ||
580 | num_strings++; | ||
581 | sprintf(p, "\tUser-defined mask: 0x%Lx\n", fsc->fs.data_mask); | ||
582 | p += ETH_GSTRING_LEN; | ||
583 | num_strings++; | ||
584 | if (fsc->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP) | ||
585 | sprintf(p, "\tAction: Drop\n"); | ||
586 | else | ||
587 | sprintf(p, "\tAction: Direct to queue %d\n", | ||
588 | fsc->fs.action); | ||
589 | p += ETH_GSTRING_LEN; | ||
590 | num_strings++; | ||
591 | unknown_filter: | ||
592 | i++; | ||
593 | } | ||
594 | copy: | ||
595 | /* indicate to userspace how many strings we actually have */ | ||
596 | gstrings.len = num_strings; | ||
597 | ret = -EFAULT; | ||
598 | if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) | ||
599 | goto out; | ||
600 | useraddr += sizeof(gstrings); | ||
601 | if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN)) | ||
602 | goto out; | ||
603 | ret = 0; | ||
604 | |||
605 | out: | ||
606 | kfree(data); | ||
607 | return ret; | ||
608 | } | ||
609 | |||
269 | static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) | 610 | static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) |
270 | { | 611 | { |
271 | struct ethtool_regs regs; | 612 | struct ethtool_regs regs; |
@@ -313,6 +654,9 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr) | |||
313 | if (copy_from_user(&reset, useraddr, sizeof(reset))) | 654 | if (copy_from_user(&reset, useraddr, sizeof(reset))) |
314 | return -EFAULT; | 655 | return -EFAULT; |
315 | 656 | ||
657 | /* Clear ethtool n-tuple list */ | ||
658 | ethtool_ntuple_flush(dev); | ||
659 | |||
316 | ret = dev->ethtool_ops->reset(dev, &reset.data); | 660 | ret = dev->ethtool_ops->reset(dev, &reset.data); |
317 | if (ret) | 661 | if (ret) |
318 | return ret; | 662 | return ret; |
@@ -324,7 +668,7 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr) | |||
324 | 668 | ||
325 | static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) | 669 | static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) |
326 | { | 670 | { |
327 | struct ethtool_wolinfo wol = { ETHTOOL_GWOL }; | 671 | struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; |
328 | 672 | ||
329 | if (!dev->ethtool_ops->get_wol) | 673 | if (!dev->ethtool_ops->get_wol) |
330 | return -EOPNOTSUPP; | 674 | return -EOPNOTSUPP; |
@@ -456,9 +800,12 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr) | |||
456 | return ret; | 800 | return ret; |
457 | } | 801 | } |
458 | 802 | ||
459 | static int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr) | 803 | /* |
804 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
805 | */ | ||
806 | static noinline int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr) | ||
460 | { | 807 | { |
461 | struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE }; | 808 | struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE }; |
462 | 809 | ||
463 | if (!dev->ethtool_ops->get_coalesce) | 810 | if (!dev->ethtool_ops->get_coalesce) |
464 | return -EOPNOTSUPP; | 811 | return -EOPNOTSUPP; |
@@ -470,7 +817,10 @@ static int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr) | |||
470 | return 0; | 817 | return 0; |
471 | } | 818 | } |
472 | 819 | ||
473 | static int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr) | 820 | /* |
821 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
822 | */ | ||
823 | static noinline int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr) | ||
474 | { | 824 | { |
475 | struct ethtool_coalesce coalesce; | 825 | struct ethtool_coalesce coalesce; |
476 | 826 | ||
@@ -485,7 +835,7 @@ static int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr) | |||
485 | 835 | ||
486 | static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr) | 836 | static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr) |
487 | { | 837 | { |
488 | struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM }; | 838 | struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM }; |
489 | 839 | ||
490 | if (!dev->ethtool_ops->get_ringparam) | 840 | if (!dev->ethtool_ops->get_ringparam) |
491 | return -EOPNOTSUPP; | 841 | return -EOPNOTSUPP; |
@@ -839,7 +1189,7 @@ static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr) | |||
839 | static int ethtool_get_value(struct net_device *dev, char __user *useraddr, | 1189 | static int ethtool_get_value(struct net_device *dev, char __user *useraddr, |
840 | u32 cmd, u32 (*actor)(struct net_device *)) | 1190 | u32 cmd, u32 (*actor)(struct net_device *)) |
841 | { | 1191 | { |
842 | struct ethtool_value edata = { cmd }; | 1192 | struct ethtool_value edata = { .cmd = cmd }; |
843 | 1193 | ||
844 | if (!actor) | 1194 | if (!actor) |
845 | return -EOPNOTSUPP; | 1195 | return -EOPNOTSUPP; |
@@ -880,7 +1230,10 @@ static int ethtool_set_value(struct net_device *dev, char __user *useraddr, | |||
880 | return actor(dev, edata.data); | 1230 | return actor(dev, edata.data); |
881 | } | 1231 | } |
882 | 1232 | ||
883 | static int ethtool_flash_device(struct net_device *dev, char __user *useraddr) | 1233 | /* |
1234 | * noinline attribute so that gcc doesnt use too much stack in dev_ethtool() | ||
1235 | */ | ||
1236 | static noinline int ethtool_flash_device(struct net_device *dev, char __user *useraddr) | ||
884 | { | 1237 | { |
885 | struct ethtool_flash efl; | 1238 | struct ethtool_flash efl; |
886 | 1239 | ||
@@ -1112,6 +1465,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) | |||
1112 | case ETHTOOL_RESET: | 1465 | case ETHTOOL_RESET: |
1113 | rc = ethtool_reset(dev, useraddr); | 1466 | rc = ethtool_reset(dev, useraddr); |
1114 | break; | 1467 | break; |
1468 | case ETHTOOL_SRXNTUPLE: | ||
1469 | rc = ethtool_set_rx_ntuple(dev, useraddr); | ||
1470 | break; | ||
1471 | case ETHTOOL_GRXNTUPLE: | ||
1472 | rc = ethtool_get_rx_ntuple(dev, useraddr); | ||
1473 | break; | ||
1115 | default: | 1474 | default: |
1116 | rc = -EOPNOTSUPP; | 1475 | rc = -EOPNOTSUPP; |
1117 | } | 1476 | } |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 62f3878a6010..42da96a4eeee 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/security.h> | 35 | #include <linux/security.h> |
36 | #include <linux/mutex.h> | 36 | #include <linux/mutex.h> |
37 | #include <linux/if_addr.h> | 37 | #include <linux/if_addr.h> |
38 | #include <linux/pci.h> | ||
38 | 39 | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | #include <asm/system.h> | 41 | #include <asm/system.h> |
@@ -580,6 +581,15 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a, | |||
580 | a->tx_compressed = b->tx_compressed; | 581 | a->tx_compressed = b->tx_compressed; |
581 | }; | 582 | }; |
582 | 583 | ||
584 | static inline int rtnl_vfinfo_size(const struct net_device *dev) | ||
585 | { | ||
586 | if (dev->dev.parent && dev_is_pci(dev->dev.parent)) | ||
587 | return dev_num_vf(dev->dev.parent) * | ||
588 | sizeof(struct ifla_vf_info); | ||
589 | else | ||
590 | return 0; | ||
591 | } | ||
592 | |||
583 | static inline size_t if_nlmsg_size(const struct net_device *dev) | 593 | static inline size_t if_nlmsg_size(const struct net_device *dev) |
584 | { | 594 | { |
585 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) | 595 | return NLMSG_ALIGN(sizeof(struct ifinfomsg)) |
@@ -597,6 +607,8 @@ static inline size_t if_nlmsg_size(const struct net_device *dev) | |||
597 | + nla_total_size(4) /* IFLA_MASTER */ | 607 | + nla_total_size(4) /* IFLA_MASTER */ |
598 | + nla_total_size(1) /* IFLA_OPERSTATE */ | 608 | + nla_total_size(1) /* IFLA_OPERSTATE */ |
599 | + nla_total_size(1) /* IFLA_LINKMODE */ | 609 | + nla_total_size(1) /* IFLA_LINKMODE */ |
610 | + nla_total_size(4) /* IFLA_NUM_VF */ | ||
611 | + nla_total_size(rtnl_vfinfo_size(dev)) /* IFLA_VFINFO */ | ||
600 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ | 612 | + rtnl_link_get_size(dev); /* IFLA_LINKINFO */ |
601 | } | 613 | } |
602 | 614 | ||
@@ -665,6 +677,17 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, | |||
665 | stats = dev_get_stats(dev); | 677 | stats = dev_get_stats(dev); |
666 | copy_rtnl_link_stats(nla_data(attr), stats); | 678 | copy_rtnl_link_stats(nla_data(attr), stats); |
667 | 679 | ||
680 | if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) { | ||
681 | int i; | ||
682 | struct ifla_vf_info ivi; | ||
683 | |||
684 | NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent)); | ||
685 | for (i = 0; i < dev_num_vf(dev->dev.parent); i++) { | ||
686 | if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi)) | ||
687 | break; | ||
688 | NLA_PUT(skb, IFLA_VFINFO, sizeof(ivi), &ivi); | ||
689 | } | ||
690 | } | ||
668 | if (dev->rtnl_link_ops) { | 691 | if (dev->rtnl_link_ops) { |
669 | if (rtnl_link_fill(skb, dev) < 0) | 692 | if (rtnl_link_fill(skb, dev) < 0) |
670 | goto nla_put_failure; | 693 | goto nla_put_failure; |
@@ -725,6 +748,12 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = { | |||
725 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, | 748 | [IFLA_LINKINFO] = { .type = NLA_NESTED }, |
726 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, | 749 | [IFLA_NET_NS_PID] = { .type = NLA_U32 }, |
727 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, | 750 | [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, |
751 | [IFLA_VF_MAC] = { .type = NLA_BINARY, | ||
752 | .len = sizeof(struct ifla_vf_mac) }, | ||
753 | [IFLA_VF_VLAN] = { .type = NLA_BINARY, | ||
754 | .len = sizeof(struct ifla_vf_vlan) }, | ||
755 | [IFLA_VF_TX_RATE] = { .type = NLA_BINARY, | ||
756 | .len = sizeof(struct ifla_vf_tx_rate) }, | ||
728 | }; | 757 | }; |
729 | EXPORT_SYMBOL(ifla_policy); | 758 | EXPORT_SYMBOL(ifla_policy); |
730 | 759 | ||
@@ -898,6 +927,44 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, | |||
898 | write_unlock_bh(&dev_base_lock); | 927 | write_unlock_bh(&dev_base_lock); |
899 | } | 928 | } |
900 | 929 | ||
930 | if (tb[IFLA_VF_MAC]) { | ||
931 | struct ifla_vf_mac *ivm; | ||
932 | ivm = nla_data(tb[IFLA_VF_MAC]); | ||
933 | write_lock_bh(&dev_base_lock); | ||
934 | if (ops->ndo_set_vf_mac) | ||
935 | err = ops->ndo_set_vf_mac(dev, ivm->vf, ivm->mac); | ||
936 | write_unlock_bh(&dev_base_lock); | ||
937 | if (err < 0) | ||
938 | goto errout; | ||
939 | modified = 1; | ||
940 | } | ||
941 | |||
942 | if (tb[IFLA_VF_VLAN]) { | ||
943 | struct ifla_vf_vlan *ivv; | ||
944 | ivv = nla_data(tb[IFLA_VF_VLAN]); | ||
945 | write_lock_bh(&dev_base_lock); | ||
946 | if (ops->ndo_set_vf_vlan) | ||
947 | err = ops->ndo_set_vf_vlan(dev, ivv->vf, | ||
948 | (u16)ivv->vlan, | ||
949 | (u8)ivv->qos); | ||
950 | write_unlock_bh(&dev_base_lock); | ||
951 | if (err < 0) | ||
952 | goto errout; | ||
953 | modified = 1; | ||
954 | } | ||
955 | err = 0; | ||
956 | |||
957 | if (tb[IFLA_VF_TX_RATE]) { | ||
958 | struct ifla_vf_tx_rate *ivt; | ||
959 | ivt = nla_data(tb[IFLA_VF_TX_RATE]); | ||
960 | write_lock_bh(&dev_base_lock); | ||
961 | if (ops->ndo_set_vf_tx_rate) | ||
962 | err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, ivt->rate); | ||
963 | write_unlock_bh(&dev_base_lock); | ||
964 | if (err < 0) | ||
965 | goto errout; | ||
966 | modified = 1; | ||
967 | } | ||
901 | err = 0; | 968 | err = 0; |
902 | 969 | ||
903 | errout: | 970 | errout: |
diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c index ff16e9df1969..49d27c556bec 100644 --- a/net/dccp/ccid.c +++ b/net/dccp/ccid.c | |||
@@ -63,14 +63,13 @@ int ccid_getsockopt_builtin_ccids(struct sock *sk, int len, | |||
63 | u8 *ccid_array, array_len; | 63 | u8 *ccid_array, array_len; |
64 | int err = 0; | 64 | int err = 0; |
65 | 65 | ||
66 | if (len < ARRAY_SIZE(ccids)) | ||
67 | return -EINVAL; | ||
68 | |||
69 | if (ccid_get_builtin_ccids(&ccid_array, &array_len)) | 66 | if (ccid_get_builtin_ccids(&ccid_array, &array_len)) |
70 | return -ENOBUFS; | 67 | return -ENOBUFS; |
71 | 68 | ||
72 | if (put_user(array_len, optlen) || | 69 | if (put_user(array_len, optlen)) |
73 | copy_to_user(optval, ccid_array, array_len)) | 70 | err = -EFAULT; |
71 | else if (len > 0 && copy_to_user(optval, ccid_array, | ||
72 | len > array_len ? array_len : len)) | ||
74 | err = -EFAULT; | 73 | err = -EFAULT; |
75 | 74 | ||
76 | kfree(ccid_array); | 75 | kfree(ccid_array); |
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 671cd1413d59..85ec1cb7fd41 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -835,6 +835,8 @@ verify_sock_status: | |||
835 | len = -EFAULT; | 835 | len = -EFAULT; |
836 | break; | 836 | break; |
837 | } | 837 | } |
838 | if (flags & MSG_TRUNC) | ||
839 | len = skb->len; | ||
838 | found_fin_ok: | 840 | found_fin_ok: |
839 | if (!(flags & MSG_PEEK)) | 841 | if (!(flags & MSG_PEEK)) |
840 | sk_eat_skb(sk, skb, 0); | 842 | sk_eat_skb(sk, skb, 0); |
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d28363998743..63bf298ca109 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c | |||
@@ -946,7 +946,6 @@ int igmp_rcv(struct sk_buff *skb) | |||
946 | break; | 946 | break; |
947 | case IGMP_HOST_MEMBERSHIP_REPORT: | 947 | case IGMP_HOST_MEMBERSHIP_REPORT: |
948 | case IGMPV2_HOST_MEMBERSHIP_REPORT: | 948 | case IGMPV2_HOST_MEMBERSHIP_REPORT: |
949 | case IGMPV3_HOST_MEMBERSHIP_REPORT: | ||
950 | /* Is it our report looped back? */ | 949 | /* Is it our report looped back? */ |
951 | if (skb_rtable(skb)->fl.iif == 0) | 950 | if (skb_rtable(skb)->fl.iif == 0) |
952 | break; | 951 | break; |
@@ -960,6 +959,7 @@ int igmp_rcv(struct sk_buff *skb) | |||
960 | in_dev_put(in_dev); | 959 | in_dev_put(in_dev); |
961 | return pim_rcv_v1(skb); | 960 | return pim_rcv_v1(skb); |
962 | #endif | 961 | #endif |
962 | case IGMPV3_HOST_MEMBERSHIP_REPORT: | ||
963 | case IGMP_DVMRP: | 963 | case IGMP_DVMRP: |
964 | case IGMP_TRACE: | 964 | case IGMP_TRACE: |
965 | case IGMP_HOST_LEAVE_MESSAGE: | 965 | case IGMP_HOST_LEAVE_MESSAGE: |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 28e029632493..3fddc69ccccc 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -5783,11 +5783,9 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
5783 | 5783 | ||
5784 | /* tcp_ack considers this ACK as duplicate | 5784 | /* tcp_ack considers this ACK as duplicate |
5785 | * and does not calculate rtt. | 5785 | * and does not calculate rtt. |
5786 | * Fix it at least with timestamps. | 5786 | * Force it here. |
5787 | */ | 5787 | */ |
5788 | if (tp->rx_opt.saw_tstamp && | 5788 | tcp_ack_update_rtt(sk, 0, 0); |
5789 | tp->rx_opt.rcv_tsecr && !tp->srtt) | ||
5790 | tcp_ack_saw_tstamp(sk, 0); | ||
5791 | 5789 | ||
5792 | if (tp->rx_opt.tstamp_ok) | 5790 | if (tp->rx_opt.tstamp_ok) |
5793 | tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; | 5791 | tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; |
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 4f7d2122d818..608a5446d05b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -1117,7 +1117,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
1117 | struct inet_sock *inet = inet_sk(sk); | 1117 | struct inet_sock *inet = inet_sk(sk); |
1118 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; | 1118 | struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; |
1119 | struct sk_buff *skb; | 1119 | struct sk_buff *skb; |
1120 | unsigned int ulen, copied; | 1120 | unsigned int ulen; |
1121 | int peeked; | 1121 | int peeked; |
1122 | int err; | 1122 | int err; |
1123 | int is_udplite = IS_UDPLITE(sk); | 1123 | int is_udplite = IS_UDPLITE(sk); |
@@ -1138,10 +1138,9 @@ try_again: | |||
1138 | goto out; | 1138 | goto out; |
1139 | 1139 | ||
1140 | ulen = skb->len - sizeof(struct udphdr); | 1140 | ulen = skb->len - sizeof(struct udphdr); |
1141 | copied = len; | 1141 | if (len > ulen) |
1142 | if (copied > ulen) | 1142 | len = ulen; |
1143 | copied = ulen; | 1143 | else if (len < ulen) |
1144 | else if (copied < ulen) | ||
1145 | msg->msg_flags |= MSG_TRUNC; | 1144 | msg->msg_flags |= MSG_TRUNC; |
1146 | 1145 | ||
1147 | /* | 1146 | /* |
@@ -1150,14 +1149,14 @@ try_again: | |||
1150 | * coverage checksum (UDP-Lite), do it before the copy. | 1149 | * coverage checksum (UDP-Lite), do it before the copy. |
1151 | */ | 1150 | */ |
1152 | 1151 | ||
1153 | if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { | 1152 | if (len < ulen || UDP_SKB_CB(skb)->partial_cov) { |
1154 | if (udp_lib_checksum_complete(skb)) | 1153 | if (udp_lib_checksum_complete(skb)) |
1155 | goto csum_copy_err; | 1154 | goto csum_copy_err; |
1156 | } | 1155 | } |
1157 | 1156 | ||
1158 | if (skb_csum_unnecessary(skb)) | 1157 | if (skb_csum_unnecessary(skb)) |
1159 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | 1158 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), |
1160 | msg->msg_iov, copied); | 1159 | msg->msg_iov, len); |
1161 | else { | 1160 | else { |
1162 | err = skb_copy_and_csum_datagram_iovec(skb, | 1161 | err = skb_copy_and_csum_datagram_iovec(skb, |
1163 | sizeof(struct udphdr), | 1162 | sizeof(struct udphdr), |
@@ -1186,7 +1185,7 @@ try_again: | |||
1186 | if (inet->cmsg_flags) | 1185 | if (inet->cmsg_flags) |
1187 | ip_cmsg_recv(msg, skb); | 1186 | ip_cmsg_recv(msg, skb); |
1188 | 1187 | ||
1189 | err = copied; | 1188 | err = len; |
1190 | if (flags & MSG_TRUNC) | 1189 | if (flags & MSG_TRUNC) |
1191 | err = ulen; | 1190 | err = ulen; |
1192 | 1191 | ||
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1593289155ff..764ad37ca070 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -2646,7 +2646,8 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2646 | 2646 | ||
2647 | write_lock_bh(&addrconf_hash_lock); | 2647 | write_lock_bh(&addrconf_hash_lock); |
2648 | while ((ifa = *bifa) != NULL) { | 2648 | while ((ifa = *bifa) != NULL) { |
2649 | if (ifa->idev == idev) { | 2649 | if (ifa->idev == idev && |
2650 | (how || !(ifa->flags&IFA_F_PERMANENT))) { | ||
2650 | *bifa = ifa->lst_next; | 2651 | *bifa = ifa->lst_next; |
2651 | ifa->lst_next = NULL; | 2652 | ifa->lst_next = NULL; |
2652 | addrconf_del_timer(ifa); | 2653 | addrconf_del_timer(ifa); |
@@ -2686,18 +2687,30 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2686 | write_lock_bh(&idev->lock); | 2687 | write_lock_bh(&idev->lock); |
2687 | } | 2688 | } |
2688 | #endif | 2689 | #endif |
2689 | while ((ifa = idev->addr_list) != NULL) { | 2690 | bifa = &idev->addr_list; |
2690 | idev->addr_list = ifa->if_next; | 2691 | while ((ifa = *bifa) != NULL) { |
2691 | ifa->if_next = NULL; | 2692 | if (how == 0 && (ifa->flags&IFA_F_PERMANENT)) { |
2692 | ifa->dead = 1; | 2693 | /* Retain permanent address on admin down */ |
2693 | addrconf_del_timer(ifa); | 2694 | bifa = &ifa->if_next; |
2694 | write_unlock_bh(&idev->lock); | 2695 | |
2696 | /* Restart DAD if needed when link comes back up */ | ||
2697 | if ( !((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) || | ||
2698 | idev->cnf.accept_dad <= 0 || | ||
2699 | (ifa->flags & IFA_F_NODAD))) | ||
2700 | ifa->flags |= IFA_F_TENTATIVE; | ||
2701 | } else { | ||
2702 | *bifa = ifa->if_next; | ||
2703 | ifa->if_next = NULL; | ||
2695 | 2704 | ||
2696 | __ipv6_ifa_notify(RTM_DELADDR, ifa); | 2705 | ifa->dead = 1; |
2697 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); | 2706 | write_unlock_bh(&idev->lock); |
2698 | in6_ifa_put(ifa); | ||
2699 | 2707 | ||
2700 | write_lock_bh(&idev->lock); | 2708 | __ipv6_ifa_notify(RTM_DELADDR, ifa); |
2709 | atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); | ||
2710 | in6_ifa_put(ifa); | ||
2711 | |||
2712 | write_lock_bh(&idev->lock); | ||
2713 | } | ||
2701 | } | 2714 | } |
2702 | write_unlock_bh(&idev->lock); | 2715 | write_unlock_bh(&idev->lock); |
2703 | 2716 | ||
@@ -2789,14 +2802,14 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2789 | read_lock_bh(&idev->lock); | 2802 | read_lock_bh(&idev->lock); |
2790 | if (ifp->dead) | 2803 | if (ifp->dead) |
2791 | goto out; | 2804 | goto out; |
2792 | spin_lock_bh(&ifp->lock); | ||
2793 | 2805 | ||
2806 | spin_lock(&ifp->lock); | ||
2794 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || | 2807 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || |
2795 | idev->cnf.accept_dad < 1 || | 2808 | idev->cnf.accept_dad < 1 || |
2796 | !(ifp->flags&IFA_F_TENTATIVE) || | 2809 | !(ifp->flags&IFA_F_TENTATIVE) || |
2797 | ifp->flags & IFA_F_NODAD) { | 2810 | ifp->flags & IFA_F_NODAD) { |
2798 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); | 2811 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); |
2799 | spin_unlock_bh(&ifp->lock); | 2812 | spin_unlock(&ifp->lock); |
2800 | read_unlock_bh(&idev->lock); | 2813 | read_unlock_bh(&idev->lock); |
2801 | 2814 | ||
2802 | addrconf_dad_completed(ifp); | 2815 | addrconf_dad_completed(ifp); |
@@ -2804,7 +2817,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2804 | } | 2817 | } |
2805 | 2818 | ||
2806 | if (!(idev->if_flags & IF_READY)) { | 2819 | if (!(idev->if_flags & IF_READY)) { |
2807 | spin_unlock_bh(&ifp->lock); | 2820 | spin_unlock(&ifp->lock); |
2808 | read_unlock_bh(&idev->lock); | 2821 | read_unlock_bh(&idev->lock); |
2809 | /* | 2822 | /* |
2810 | * If the device is not ready: | 2823 | * If the device is not ready: |
@@ -2824,7 +2837,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2824 | ip6_ins_rt(ifp->rt); | 2837 | ip6_ins_rt(ifp->rt); |
2825 | 2838 | ||
2826 | addrconf_dad_kick(ifp); | 2839 | addrconf_dad_kick(ifp); |
2827 | spin_unlock_bh(&ifp->lock); | 2840 | spin_unlock(&ifp->lock); |
2828 | out: | 2841 | out: |
2829 | read_unlock_bh(&idev->lock); | 2842 | read_unlock_bh(&idev->lock); |
2830 | } | 2843 | } |
@@ -2840,14 +2853,15 @@ static void addrconf_dad_timer(unsigned long data) | |||
2840 | read_unlock_bh(&idev->lock); | 2853 | read_unlock_bh(&idev->lock); |
2841 | goto out; | 2854 | goto out; |
2842 | } | 2855 | } |
2843 | spin_lock_bh(&ifp->lock); | 2856 | |
2857 | spin_lock(&ifp->lock); | ||
2844 | if (ifp->probes == 0) { | 2858 | if (ifp->probes == 0) { |
2845 | /* | 2859 | /* |
2846 | * DAD was successful | 2860 | * DAD was successful |
2847 | */ | 2861 | */ |
2848 | 2862 | ||
2849 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); | 2863 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); |
2850 | spin_unlock_bh(&ifp->lock); | 2864 | spin_unlock(&ifp->lock); |
2851 | read_unlock_bh(&idev->lock); | 2865 | read_unlock_bh(&idev->lock); |
2852 | 2866 | ||
2853 | addrconf_dad_completed(ifp); | 2867 | addrconf_dad_completed(ifp); |
@@ -2857,7 +2871,7 @@ static void addrconf_dad_timer(unsigned long data) | |||
2857 | 2871 | ||
2858 | ifp->probes--; | 2872 | ifp->probes--; |
2859 | addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); | 2873 | addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); |
2860 | spin_unlock_bh(&ifp->lock); | 2874 | spin_unlock(&ifp->lock); |
2861 | read_unlock_bh(&idev->lock); | 2875 | read_unlock_bh(&idev->lock); |
2862 | 2876 | ||
2863 | /* send a neighbour solicitation for our addr */ | 2877 | /* send a neighbour solicitation for our addr */ |
@@ -2905,12 +2919,12 @@ static void addrconf_dad_run(struct inet6_dev *idev) { | |||
2905 | 2919 | ||
2906 | read_lock_bh(&idev->lock); | 2920 | read_lock_bh(&idev->lock); |
2907 | for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { | 2921 | for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { |
2908 | spin_lock_bh(&ifp->lock); | 2922 | spin_lock(&ifp->lock); |
2909 | if (!(ifp->flags & IFA_F_TENTATIVE)) { | 2923 | if (!(ifp->flags & IFA_F_TENTATIVE)) { |
2910 | spin_unlock_bh(&ifp->lock); | 2924 | spin_unlock(&ifp->lock); |
2911 | continue; | 2925 | continue; |
2912 | } | 2926 | } |
2913 | spin_unlock_bh(&ifp->lock); | 2927 | spin_unlock(&ifp->lock); |
2914 | addrconf_dad_kick(ifp); | 2928 | addrconf_dad_kick(ifp); |
2915 | } | 2929 | } |
2916 | read_unlock_bh(&idev->lock); | 2930 | read_unlock_bh(&idev->lock); |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index f626ea2b304f..77e122f53ea6 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -319,12 +319,26 @@ static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, | |||
319 | w->root = &table->tb6_root; | 319 | w->root = &table->tb6_root; |
320 | 320 | ||
321 | if (cb->args[4] == 0) { | 321 | if (cb->args[4] == 0) { |
322 | w->count = 0; | ||
323 | w->skip = 0; | ||
324 | |||
322 | read_lock_bh(&table->tb6_lock); | 325 | read_lock_bh(&table->tb6_lock); |
323 | res = fib6_walk(w); | 326 | res = fib6_walk(w); |
324 | read_unlock_bh(&table->tb6_lock); | 327 | read_unlock_bh(&table->tb6_lock); |
325 | if (res > 0) | 328 | if (res > 0) { |
326 | cb->args[4] = 1; | 329 | cb->args[4] = 1; |
330 | cb->args[5] = w->root->fn_sernum; | ||
331 | } | ||
327 | } else { | 332 | } else { |
333 | if (cb->args[5] != w->root->fn_sernum) { | ||
334 | /* Begin at the root if the tree changed */ | ||
335 | cb->args[5] = w->root->fn_sernum; | ||
336 | w->state = FWS_INIT; | ||
337 | w->node = w->root; | ||
338 | w->skip = w->count; | ||
339 | } else | ||
340 | w->skip = 0; | ||
341 | |||
328 | read_lock_bh(&table->tb6_lock); | 342 | read_lock_bh(&table->tb6_lock); |
329 | res = fib6_walk_continue(w); | 343 | res = fib6_walk_continue(w); |
330 | read_unlock_bh(&table->tb6_lock); | 344 | read_unlock_bh(&table->tb6_lock); |
@@ -1250,9 +1264,18 @@ static int fib6_walk_continue(struct fib6_walker_t *w) | |||
1250 | w->leaf = fn->leaf; | 1264 | w->leaf = fn->leaf; |
1251 | case FWS_C: | 1265 | case FWS_C: |
1252 | if (w->leaf && fn->fn_flags&RTN_RTINFO) { | 1266 | if (w->leaf && fn->fn_flags&RTN_RTINFO) { |
1253 | int err = w->func(w); | 1267 | int err; |
1268 | |||
1269 | if (w->count < w->skip) { | ||
1270 | w->count++; | ||
1271 | continue; | ||
1272 | } | ||
1273 | |||
1274 | err = w->func(w); | ||
1254 | if (err) | 1275 | if (err) |
1255 | return err; | 1276 | return err; |
1277 | |||
1278 | w->count++; | ||
1256 | continue; | 1279 | continue; |
1257 | } | 1280 | } |
1258 | w->state = FWS_U; | 1281 | w->state = FWS_U; |
@@ -1346,6 +1369,8 @@ static void fib6_clean_tree(struct net *net, struct fib6_node *root, | |||
1346 | c.w.root = root; | 1369 | c.w.root = root; |
1347 | c.w.func = fib6_clean_node; | 1370 | c.w.func = fib6_clean_node; |
1348 | c.w.prune = prune; | 1371 | c.w.prune = prune; |
1372 | c.w.count = 0; | ||
1373 | c.w.skip = 0; | ||
1349 | c.func = func; | 1374 | c.func = func; |
1350 | c.arg = arg; | 1375 | c.arg = arg; |
1351 | c.net = net; | 1376 | c.net = net; |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index d93812d09c13..b2847ed6a7d9 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -237,8 +237,7 @@ out: | |||
237 | } | 237 | } |
238 | 238 | ||
239 | static __inline__ struct frag_queue * | 239 | static __inline__ struct frag_queue * |
240 | fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, | 240 | fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst) |
241 | struct inet6_dev *idev) | ||
242 | { | 241 | { |
243 | struct inet_frag_queue *q; | 242 | struct inet_frag_queue *q; |
244 | struct ip6_create_arg arg; | 243 | struct ip6_create_arg arg; |
@@ -254,13 +253,9 @@ fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst, | |||
254 | 253 | ||
255 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); | 254 | q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); |
256 | if (q == NULL) | 255 | if (q == NULL) |
257 | goto oom; | 256 | return NULL; |
258 | 257 | ||
259 | return container_of(q, struct frag_queue, q); | 258 | return container_of(q, struct frag_queue, q); |
260 | |||
261 | oom: | ||
262 | IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS); | ||
263 | return NULL; | ||
264 | } | 259 | } |
265 | 260 | ||
266 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | 261 | static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, |
@@ -606,8 +601,8 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
606 | if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) | 601 | if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) |
607 | ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); | 602 | ip6_evictor(net, ip6_dst_idev(skb_dst(skb))); |
608 | 603 | ||
609 | if ((fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, | 604 | fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr); |
610 | ip6_dst_idev(skb_dst(skb)))) != NULL) { | 605 | if (fq != NULL) { |
611 | int ret; | 606 | int ret; |
612 | 607 | ||
613 | spin_lock(&fq->q.lock); | 608 | spin_lock(&fq->q.lock); |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 34efb3589ffa..a7af9d68cd6c 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -322,7 +322,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
322 | struct ipv6_pinfo *np = inet6_sk(sk); | 322 | struct ipv6_pinfo *np = inet6_sk(sk); |
323 | struct inet_sock *inet = inet_sk(sk); | 323 | struct inet_sock *inet = inet_sk(sk); |
324 | struct sk_buff *skb; | 324 | struct sk_buff *skb; |
325 | unsigned int ulen, copied; | 325 | unsigned int ulen; |
326 | int peeked; | 326 | int peeked; |
327 | int err; | 327 | int err; |
328 | int is_udplite = IS_UDPLITE(sk); | 328 | int is_udplite = IS_UDPLITE(sk); |
@@ -341,10 +341,9 @@ try_again: | |||
341 | goto out; | 341 | goto out; |
342 | 342 | ||
343 | ulen = skb->len - sizeof(struct udphdr); | 343 | ulen = skb->len - sizeof(struct udphdr); |
344 | copied = len; | 344 | if (len > ulen) |
345 | if (copied > ulen) | 345 | len = ulen; |
346 | copied = ulen; | 346 | else if (len < ulen) |
347 | else if (copied < ulen) | ||
348 | msg->msg_flags |= MSG_TRUNC; | 347 | msg->msg_flags |= MSG_TRUNC; |
349 | 348 | ||
350 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); | 349 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); |
@@ -355,14 +354,14 @@ try_again: | |||
355 | * coverage checksum (UDP-Lite), do it before the copy. | 354 | * coverage checksum (UDP-Lite), do it before the copy. |
356 | */ | 355 | */ |
357 | 356 | ||
358 | if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { | 357 | if (len < ulen || UDP_SKB_CB(skb)->partial_cov) { |
359 | if (udp_lib_checksum_complete(skb)) | 358 | if (udp_lib_checksum_complete(skb)) |
360 | goto csum_copy_err; | 359 | goto csum_copy_err; |
361 | } | 360 | } |
362 | 361 | ||
363 | if (skb_csum_unnecessary(skb)) | 362 | if (skb_csum_unnecessary(skb)) |
364 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | 363 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), |
365 | msg->msg_iov, copied ); | 364 | msg->msg_iov,len); |
366 | else { | 365 | else { |
367 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); | 366 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); |
368 | if (err == -EINVAL) | 367 | if (err == -EINVAL) |
@@ -411,7 +410,7 @@ try_again: | |||
411 | datagram_recv_ctl(sk, msg, skb); | 410 | datagram_recv_ctl(sk, msg, skb); |
412 | } | 411 | } |
413 | 412 | ||
414 | err = copied; | 413 | err = len; |
415 | if (flags & MSG_TRUNC) | 414 | if (flags & MSG_TRUNC) |
416 | err = ulen; | 415 | err = ulen; |
417 | 416 | ||
diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c index 576178482f89..26b5bfcf1d03 100644 --- a/net/ipx/ipx_proc.c +++ b/net/ipx/ipx_proc.c | |||
@@ -13,45 +13,15 @@ | |||
13 | #include <net/tcp_states.h> | 13 | #include <net/tcp_states.h> |
14 | #include <net/ipx.h> | 14 | #include <net/ipx.h> |
15 | 15 | ||
16 | static __inline__ struct ipx_interface *ipx_get_interface_idx(loff_t pos) | ||
17 | { | ||
18 | struct ipx_interface *i; | ||
19 | |||
20 | list_for_each_entry(i, &ipx_interfaces, node) | ||
21 | if (!pos--) | ||
22 | goto out; | ||
23 | i = NULL; | ||
24 | out: | ||
25 | return i; | ||
26 | } | ||
27 | |||
28 | static struct ipx_interface *ipx_interfaces_next(struct ipx_interface *i) | ||
29 | { | ||
30 | struct ipx_interface *rc = NULL; | ||
31 | |||
32 | if (i->node.next != &ipx_interfaces) | ||
33 | rc = list_entry(i->node.next, struct ipx_interface, node); | ||
34 | return rc; | ||
35 | } | ||
36 | |||
37 | static void *ipx_seq_interface_start(struct seq_file *seq, loff_t *pos) | 16 | static void *ipx_seq_interface_start(struct seq_file *seq, loff_t *pos) |
38 | { | 17 | { |
39 | loff_t l = *pos; | ||
40 | |||
41 | spin_lock_bh(&ipx_interfaces_lock); | 18 | spin_lock_bh(&ipx_interfaces_lock); |
42 | return l ? ipx_get_interface_idx(--l) : SEQ_START_TOKEN; | 19 | return seq_list_start_head(&ipx_interfaces, *pos); |
43 | } | 20 | } |
44 | 21 | ||
45 | static void *ipx_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos) | 22 | static void *ipx_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos) |
46 | { | 23 | { |
47 | struct ipx_interface *i; | 24 | return seq_list_next(v, &ipx_interfaces, pos); |
48 | |||
49 | ++*pos; | ||
50 | if (v == SEQ_START_TOKEN) | ||
51 | i = ipx_interfaces_head(); | ||
52 | else | ||
53 | i = ipx_interfaces_next(v); | ||
54 | return i; | ||
55 | } | 25 | } |
56 | 26 | ||
57 | static void ipx_seq_interface_stop(struct seq_file *seq, void *v) | 27 | static void ipx_seq_interface_stop(struct seq_file *seq, void *v) |
@@ -63,7 +33,7 @@ static int ipx_seq_interface_show(struct seq_file *seq, void *v) | |||
63 | { | 33 | { |
64 | struct ipx_interface *i; | 34 | struct ipx_interface *i; |
65 | 35 | ||
66 | if (v == SEQ_START_TOKEN) { | 36 | if (v == &ipx_interfaces) { |
67 | seq_puts(seq, "Network Node_Address Primary Device " | 37 | seq_puts(seq, "Network Node_Address Primary Device " |
68 | "Frame_Type"); | 38 | "Frame_Type"); |
69 | #ifdef IPX_REFCNT_DEBUG | 39 | #ifdef IPX_REFCNT_DEBUG |
@@ -73,7 +43,7 @@ static int ipx_seq_interface_show(struct seq_file *seq, void *v) | |||
73 | goto out; | 43 | goto out; |
74 | } | 44 | } |
75 | 45 | ||
76 | i = v; | 46 | i = list_entry(v, struct ipx_interface, node); |
77 | seq_printf(seq, "%08lX ", (unsigned long int)ntohl(i->if_netnum)); | 47 | seq_printf(seq, "%08lX ", (unsigned long int)ntohl(i->if_netnum)); |
78 | seq_printf(seq, "%02X%02X%02X%02X%02X%02X ", | 48 | seq_printf(seq, "%02X%02X%02X%02X%02X%02X ", |
79 | i->if_node[0], i->if_node[1], i->if_node[2], | 49 | i->if_node[0], i->if_node[1], i->if_node[2], |
@@ -89,53 +59,15 @@ out: | |||
89 | return 0; | 59 | return 0; |
90 | } | 60 | } |
91 | 61 | ||
92 | static struct ipx_route *ipx_routes_head(void) | ||
93 | { | ||
94 | struct ipx_route *rc = NULL; | ||
95 | |||
96 | if (!list_empty(&ipx_routes)) | ||
97 | rc = list_entry(ipx_routes.next, struct ipx_route, node); | ||
98 | return rc; | ||
99 | } | ||
100 | |||
101 | static struct ipx_route *ipx_routes_next(struct ipx_route *r) | ||
102 | { | ||
103 | struct ipx_route *rc = NULL; | ||
104 | |||
105 | if (r->node.next != &ipx_routes) | ||
106 | rc = list_entry(r->node.next, struct ipx_route, node); | ||
107 | return rc; | ||
108 | } | ||
109 | |||
110 | static __inline__ struct ipx_route *ipx_get_route_idx(loff_t pos) | ||
111 | { | ||
112 | struct ipx_route *r; | ||
113 | |||
114 | list_for_each_entry(r, &ipx_routes, node) | ||
115 | if (!pos--) | ||
116 | goto out; | ||
117 | r = NULL; | ||
118 | out: | ||
119 | return r; | ||
120 | } | ||
121 | |||
122 | static void *ipx_seq_route_start(struct seq_file *seq, loff_t *pos) | 62 | static void *ipx_seq_route_start(struct seq_file *seq, loff_t *pos) |
123 | { | 63 | { |
124 | loff_t l = *pos; | ||
125 | read_lock_bh(&ipx_routes_lock); | 64 | read_lock_bh(&ipx_routes_lock); |
126 | return l ? ipx_get_route_idx(--l) : SEQ_START_TOKEN; | 65 | return seq_list_start_head(&ipx_routes, *pos); |
127 | } | 66 | } |
128 | 67 | ||
129 | static void *ipx_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) | 68 | static void *ipx_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) |
130 | { | 69 | { |
131 | struct ipx_route *r; | 70 | return seq_list_next(v, &ipx_routes, pos); |
132 | |||
133 | ++*pos; | ||
134 | if (v == SEQ_START_TOKEN) | ||
135 | r = ipx_routes_head(); | ||
136 | else | ||
137 | r = ipx_routes_next(v); | ||
138 | return r; | ||
139 | } | 71 | } |
140 | 72 | ||
141 | static void ipx_seq_route_stop(struct seq_file *seq, void *v) | 73 | static void ipx_seq_route_stop(struct seq_file *seq, void *v) |
@@ -147,11 +79,13 @@ static int ipx_seq_route_show(struct seq_file *seq, void *v) | |||
147 | { | 79 | { |
148 | struct ipx_route *rt; | 80 | struct ipx_route *rt; |
149 | 81 | ||
150 | if (v == SEQ_START_TOKEN) { | 82 | if (v == &ipx_routes) { |
151 | seq_puts(seq, "Network Router_Net Router_Node\n"); | 83 | seq_puts(seq, "Network Router_Net Router_Node\n"); |
152 | goto out; | 84 | goto out; |
153 | } | 85 | } |
154 | rt = v; | 86 | |
87 | rt = list_entry(v, struct ipx_route, node); | ||
88 | |||
155 | seq_printf(seq, "%08lX ", (unsigned long int)ntohl(rt->ir_net)); | 89 | seq_printf(seq, "%08lX ", (unsigned long int)ntohl(rt->ir_net)); |
156 | if (rt->ir_routed) | 90 | if (rt->ir_routed) |
157 | seq_printf(seq, "%08lX %02X%02X%02X%02X%02X%02X\n", | 91 | seq_printf(seq, "%08lX %02X%02X%02X%02X%02X%02X\n", |
@@ -226,9 +160,9 @@ static void *ipx_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) | |||
226 | spin_unlock_bh(&i->if_sklist_lock); | 160 | spin_unlock_bh(&i->if_sklist_lock); |
227 | sk = NULL; | 161 | sk = NULL; |
228 | for (;;) { | 162 | for (;;) { |
229 | i = ipx_interfaces_next(i); | 163 | if (i->node.next == &ipx_interfaces) |
230 | if (!i) | ||
231 | break; | 164 | break; |
165 | i = list_entry(i->node.next, struct ipx_interface, node); | ||
232 | spin_lock_bh(&i->if_sklist_lock); | 166 | spin_lock_bh(&i->if_sklist_lock); |
233 | if (!hlist_empty(&i->if_sklist)) { | 167 | if (!hlist_empty(&i->if_sklist)) { |
234 | sk = sk_head(&i->if_sklist); | 168 | sk = sk_head(&i->if_sklist); |
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 315ead3cb926..e486dc89ea59 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c | |||
@@ -1128,34 +1128,14 @@ int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len) | |||
1128 | */ | 1128 | */ |
1129 | static void *irlan_seq_start(struct seq_file *seq, loff_t *pos) | 1129 | static void *irlan_seq_start(struct seq_file *seq, loff_t *pos) |
1130 | { | 1130 | { |
1131 | int i = 1; | ||
1132 | struct irlan_cb *self; | ||
1133 | |||
1134 | rcu_read_lock(); | 1131 | rcu_read_lock(); |
1135 | if (*pos == 0) | 1132 | return seq_list_start_head(&irlans, *pos); |
1136 | return SEQ_START_TOKEN; | ||
1137 | |||
1138 | list_for_each_entry(self, &irlans, dev_list) { | ||
1139 | if (*pos == i) | ||
1140 | return self; | ||
1141 | ++i; | ||
1142 | } | ||
1143 | return NULL; | ||
1144 | } | 1133 | } |
1145 | 1134 | ||
1146 | /* Return entry after v, and increment pos */ | 1135 | /* Return entry after v, and increment pos */ |
1147 | static void *irlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 1136 | static void *irlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
1148 | { | 1137 | { |
1149 | struct list_head *nxt; | 1138 | return seq_list_next(v, &irlans, pos); |
1150 | |||
1151 | ++*pos; | ||
1152 | if (v == SEQ_START_TOKEN) | ||
1153 | nxt = irlans.next; | ||
1154 | else | ||
1155 | nxt = ((struct irlan_cb *)v)->dev_list.next; | ||
1156 | |||
1157 | return (nxt == &irlans) ? NULL | ||
1158 | : list_entry(nxt, struct irlan_cb, dev_list); | ||
1159 | } | 1139 | } |
1160 | 1140 | ||
1161 | /* End of reading /proc file */ | 1141 | /* End of reading /proc file */ |
@@ -1170,10 +1150,10 @@ static void irlan_seq_stop(struct seq_file *seq, void *v) | |||
1170 | */ | 1150 | */ |
1171 | static int irlan_seq_show(struct seq_file *seq, void *v) | 1151 | static int irlan_seq_show(struct seq_file *seq, void *v) |
1172 | { | 1152 | { |
1173 | if (v == SEQ_START_TOKEN) | 1153 | if (v == &irlans) |
1174 | seq_puts(seq, "IrLAN instances:\n"); | 1154 | seq_puts(seq, "IrLAN instances:\n"); |
1175 | else { | 1155 | else { |
1176 | struct irlan_cb *self = v; | 1156 | struct irlan_cb *self = list_entry(v, struct irlan_cb, dev_list); |
1177 | 1157 | ||
1178 | IRDA_ASSERT(self != NULL, return -1;); | 1158 | IRDA_ASSERT(self != NULL, return -1;); |
1179 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); | 1159 | IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); |
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index d340110f5c0c..9616c32d1076 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c | |||
@@ -321,14 +321,15 @@ static void irlan_eth_set_multicast_list(struct net_device *dev) | |||
321 | /* Enable promiscuous mode */ | 321 | /* Enable promiscuous mode */ |
322 | IRDA_WARNING("Promiscuous mode not implemented by IrLAN!\n"); | 322 | IRDA_WARNING("Promiscuous mode not implemented by IrLAN!\n"); |
323 | } | 323 | } |
324 | else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) { | 324 | else if ((dev->flags & IFF_ALLMULTI) || |
325 | netdev_mc_count(dev) > HW_MAX_ADDRS) { | ||
325 | /* Disable promiscuous mode, use normal mode. */ | 326 | /* Disable promiscuous mode, use normal mode. */ |
326 | IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ ); | 327 | IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ ); |
327 | /* hardware_set_filter(NULL); */ | 328 | /* hardware_set_filter(NULL); */ |
328 | 329 | ||
329 | irlan_set_multicast_filter(self, TRUE); | 330 | irlan_set_multicast_filter(self, TRUE); |
330 | } | 331 | } |
331 | else if (dev->mc_count) { | 332 | else if (!netdev_mc_empty(dev)) { |
332 | IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ ); | 333 | IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ ); |
333 | /* Walk the address list, and load the filter */ | 334 | /* Walk the address list, and load the filter */ |
334 | /* hardware_set_filter(dev->mc_list); */ | 335 | /* hardware_set_filter(dev->mc_list); */ |
diff --git a/net/key/af_key.c b/net/key/af_key.c index 41dd2cb07ef3..8b8e26a9e401 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c | |||
@@ -1751,7 +1751,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd | |||
1751 | audit_info.secid = 0; | 1751 | audit_info.secid = 0; |
1752 | err = xfrm_state_flush(net, proto, &audit_info); | 1752 | err = xfrm_state_flush(net, proto, &audit_info); |
1753 | if (err) | 1753 | if (err) |
1754 | return err; | 1754 | return 0; |
1755 | c.data.proto = proto; | 1755 | c.data.proto = proto; |
1756 | c.seq = hdr->sadb_msg_seq; | 1756 | c.seq = hdr->sadb_msg_seq; |
1757 | c.pid = hdr->sadb_msg_pid; | 1757 | c.pid = hdr->sadb_msg_pid; |
@@ -2713,7 +2713,7 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg | |||
2713 | audit_info.secid = 0; | 2713 | audit_info.secid = 0; |
2714 | err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); | 2714 | err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); |
2715 | if (err) | 2715 | if (err) |
2716 | return err; | 2716 | return 0; |
2717 | c.data.type = XFRM_POLICY_TYPE_MAIN; | 2717 | c.data.type = XFRM_POLICY_TYPE_MAIN; |
2718 | c.event = XFRM_MSG_FLUSHPOLICY; | 2718 | c.event = XFRM_MSG_FLUSHPOLICY; |
2719 | c.pid = hdr->sadb_msg_pid; | 2719 | c.pid = hdr->sadb_msg_pid; |
@@ -3654,9 +3654,8 @@ static const struct net_proto_family pfkey_family_ops = { | |||
3654 | #ifdef CONFIG_PROC_FS | 3654 | #ifdef CONFIG_PROC_FS |
3655 | static int pfkey_seq_show(struct seq_file *f, void *v) | 3655 | static int pfkey_seq_show(struct seq_file *f, void *v) |
3656 | { | 3656 | { |
3657 | struct sock *s; | 3657 | struct sock *s = sk_entry(v); |
3658 | 3658 | ||
3659 | s = (struct sock *)v; | ||
3660 | if (v == SEQ_START_TOKEN) | 3659 | if (v == SEQ_START_TOKEN) |
3661 | seq_printf(f ,"sk RefCnt Rmem Wmem User Inode\n"); | 3660 | seq_printf(f ,"sk RefCnt Rmem Wmem User Inode\n"); |
3662 | else | 3661 | else |
@@ -3675,19 +3674,9 @@ static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos) | |||
3675 | { | 3674 | { |
3676 | struct net *net = seq_file_net(f); | 3675 | struct net *net = seq_file_net(f); |
3677 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | 3676 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); |
3678 | struct sock *s; | ||
3679 | struct hlist_node *node; | ||
3680 | loff_t pos = *ppos; | ||
3681 | 3677 | ||
3682 | read_lock(&pfkey_table_lock); | 3678 | read_lock(&pfkey_table_lock); |
3683 | if (pos == 0) | 3679 | return seq_hlist_start_head(&net_pfkey->table, *ppos); |
3684 | return SEQ_START_TOKEN; | ||
3685 | |||
3686 | sk_for_each(s, node, &net_pfkey->table) | ||
3687 | if (pos-- == 1) | ||
3688 | return s; | ||
3689 | |||
3690 | return NULL; | ||
3691 | } | 3680 | } |
3692 | 3681 | ||
3693 | static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos) | 3682 | static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos) |
@@ -3695,10 +3684,7 @@ static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos) | |||
3695 | struct net *net = seq_file_net(f); | 3684 | struct net *net = seq_file_net(f); |
3696 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); | 3685 | struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); |
3697 | 3686 | ||
3698 | ++*ppos; | 3687 | return seq_hlist_next(v, &net_pfkey->table, ppos); |
3699 | return (v == SEQ_START_TOKEN) ? | ||
3700 | sk_head(&net_pfkey->table) : | ||
3701 | sk_next((struct sock *)v); | ||
3702 | } | 3688 | } |
3703 | 3689 | ||
3704 | static void pfkey_seq_stop(struct seq_file *f, void *v) | 3690 | static void pfkey_seq_stop(struct seq_file *f, void *v) |
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 718fbcff84d2..5538e1b4a697 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c | |||
@@ -237,6 +237,14 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) | |||
237 | sdata->vif.type != NL80211_IFTYPE_AP) | 237 | sdata->vif.type != NL80211_IFTYPE_AP) |
238 | return -EINVAL; | 238 | return -EINVAL; |
239 | 239 | ||
240 | if (test_sta_flags(sta, WLAN_STA_DISASSOC)) { | ||
241 | #ifdef CONFIG_MAC80211_HT_DEBUG | ||
242 | printk(KERN_DEBUG "Disassociation is in progress. " | ||
243 | "Denying BA session request\n"); | ||
244 | #endif | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | |||
240 | if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { | 248 | if (test_sta_flags(sta, WLAN_STA_SUSPEND)) { |
241 | #ifdef CONFIG_MAC80211_HT_DEBUG | 249 | #ifdef CONFIG_MAC80211_HT_DEBUG |
242 | printk(KERN_DEBUG "Suspend in progress. " | 250 | printk(KERN_DEBUG "Suspend in progress. " |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index facf233843e0..e1731b7c2523 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -515,6 +515,8 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, | |||
515 | if (old) | 515 | if (old) |
516 | memcpy(new->tail, old->tail, new_tail_len); | 516 | memcpy(new->tail, old->tail, new_tail_len); |
517 | 517 | ||
518 | sdata->vif.bss_conf.dtim_period = new->dtim_period; | ||
519 | |||
518 | rcu_assign_pointer(sdata->u.ap.beacon, new); | 520 | rcu_assign_pointer(sdata->u.ap.beacon, new); |
519 | 521 | ||
520 | synchronize_rcu(); | 522 | synchronize_rcu(); |
@@ -747,9 +749,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, | |||
747 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || | 749 | layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || |
748 | sdata->vif.type == NL80211_IFTYPE_AP; | 750 | sdata->vif.type == NL80211_IFTYPE_AP; |
749 | 751 | ||
750 | rcu_read_lock(); | 752 | err = sta_info_insert_rcu(sta); |
751 | |||
752 | err = sta_info_insert(sta); | ||
753 | if (err) { | 753 | if (err) { |
754 | rcu_read_unlock(); | 754 | rcu_read_unlock(); |
755 | return err; | 755 | return err; |
@@ -768,26 +768,13 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, | |||
768 | { | 768 | { |
769 | struct ieee80211_local *local = wiphy_priv(wiphy); | 769 | struct ieee80211_local *local = wiphy_priv(wiphy); |
770 | struct ieee80211_sub_if_data *sdata; | 770 | struct ieee80211_sub_if_data *sdata; |
771 | struct sta_info *sta; | ||
772 | 771 | ||
773 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 772 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
774 | 773 | ||
775 | if (mac) { | 774 | if (mac) |
776 | rcu_read_lock(); | 775 | return sta_info_destroy_addr_bss(sdata, mac); |
777 | |||
778 | sta = sta_info_get_bss(sdata, mac); | ||
779 | if (!sta) { | ||
780 | rcu_read_unlock(); | ||
781 | return -ENOENT; | ||
782 | } | ||
783 | |||
784 | sta_info_unlink(&sta); | ||
785 | rcu_read_unlock(); | ||
786 | |||
787 | sta_info_destroy(sta); | ||
788 | } else | ||
789 | sta_info_flush(local, sdata); | ||
790 | 776 | ||
777 | sta_info_flush(local, sdata); | ||
791 | return 0; | 778 | return 0; |
792 | } | 779 | } |
793 | 780 | ||
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index b3bc32b62a5a..637929b65ccc 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c | |||
@@ -250,6 +250,38 @@ static const struct file_operations uapsd_max_sp_len_ops = { | |||
250 | .open = mac80211_open_file_generic | 250 | .open = mac80211_open_file_generic |
251 | }; | 251 | }; |
252 | 252 | ||
253 | static ssize_t channel_type_read(struct file *file, char __user *user_buf, | ||
254 | size_t count, loff_t *ppos) | ||
255 | { | ||
256 | struct ieee80211_local *local = file->private_data; | ||
257 | const char *buf; | ||
258 | |||
259 | switch (local->hw.conf.channel_type) { | ||
260 | case NL80211_CHAN_NO_HT: | ||
261 | buf = "no ht\n"; | ||
262 | break; | ||
263 | case NL80211_CHAN_HT20: | ||
264 | buf = "ht20\n"; | ||
265 | break; | ||
266 | case NL80211_CHAN_HT40MINUS: | ||
267 | buf = "ht40-\n"; | ||
268 | break; | ||
269 | case NL80211_CHAN_HT40PLUS: | ||
270 | buf = "ht40+\n"; | ||
271 | break; | ||
272 | default: | ||
273 | buf = "???"; | ||
274 | break; | ||
275 | } | ||
276 | |||
277 | return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); | ||
278 | } | ||
279 | |||
280 | static const struct file_operations channel_type_ops = { | ||
281 | .read = channel_type_read, | ||
282 | .open = mac80211_open_file_generic | ||
283 | }; | ||
284 | |||
253 | static ssize_t queues_read(struct file *file, char __user *user_buf, | 285 | static ssize_t queues_read(struct file *file, char __user *user_buf, |
254 | size_t count, loff_t *ppos) | 286 | size_t count, loff_t *ppos) |
255 | { | 287 | { |
@@ -408,6 +440,7 @@ void debugfs_hw_add(struct ieee80211_local *local) | |||
408 | DEBUGFS_ADD(noack); | 440 | DEBUGFS_ADD(noack); |
409 | DEBUGFS_ADD(uapsd_queues); | 441 | DEBUGFS_ADD(uapsd_queues); |
410 | DEBUGFS_ADD(uapsd_max_sp_len); | 442 | DEBUGFS_ADD(uapsd_max_sp_len); |
443 | DEBUGFS_ADD(channel_type); | ||
411 | 444 | ||
412 | statsd = debugfs_create_dir("statistics", phyd); | 445 | statsd = debugfs_create_dir("statistics", phyd); |
413 | 446 | ||
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 6c31f38ac7f5..c3d844093a2f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -243,6 +243,40 @@ static inline void drv_sta_notify(struct ieee80211_local *local, | |||
243 | trace_drv_sta_notify(local, sdata, cmd, sta); | 243 | trace_drv_sta_notify(local, sdata, cmd, sta); |
244 | } | 244 | } |
245 | 245 | ||
246 | static inline int drv_sta_add(struct ieee80211_local *local, | ||
247 | struct ieee80211_sub_if_data *sdata, | ||
248 | struct ieee80211_sta *sta) | ||
249 | { | ||
250 | int ret = 0; | ||
251 | |||
252 | might_sleep(); | ||
253 | |||
254 | if (local->ops->sta_add) | ||
255 | ret = local->ops->sta_add(&local->hw, &sdata->vif, sta); | ||
256 | else if (local->ops->sta_notify) | ||
257 | local->ops->sta_notify(&local->hw, &sdata->vif, | ||
258 | STA_NOTIFY_ADD, sta); | ||
259 | |||
260 | trace_drv_sta_add(local, sdata, sta, ret); | ||
261 | |||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | static inline void drv_sta_remove(struct ieee80211_local *local, | ||
266 | struct ieee80211_sub_if_data *sdata, | ||
267 | struct ieee80211_sta *sta) | ||
268 | { | ||
269 | might_sleep(); | ||
270 | |||
271 | if (local->ops->sta_remove) | ||
272 | local->ops->sta_remove(&local->hw, &sdata->vif, sta); | ||
273 | else if (local->ops->sta_notify) | ||
274 | local->ops->sta_notify(&local->hw, &sdata->vif, | ||
275 | STA_NOTIFY_REMOVE, sta); | ||
276 | |||
277 | trace_drv_sta_remove(local, sdata, sta); | ||
278 | } | ||
279 | |||
246 | static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, | 280 | static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, |
247 | const struct ieee80211_tx_queue_params *params) | 281 | const struct ieee80211_tx_queue_params *params) |
248 | { | 282 | { |
@@ -256,14 +290,6 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, | |||
256 | return ret; | 290 | return ret; |
257 | } | 291 | } |
258 | 292 | ||
259 | static inline int drv_get_tx_stats(struct ieee80211_local *local, | ||
260 | struct ieee80211_tx_queue_stats *stats) | ||
261 | { | ||
262 | int ret = local->ops->get_tx_stats(&local->hw, stats); | ||
263 | trace_drv_get_tx_stats(local, stats, ret); | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | static inline u64 drv_get_tsf(struct ieee80211_local *local) | 293 | static inline u64 drv_get_tsf(struct ieee80211_local *local) |
268 | { | 294 | { |
269 | u64 ret = -1ULL; | 295 | u64 ret = -1ULL; |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index 502424b2538a..41baf730a5c7 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -545,59 +545,88 @@ TRACE_EVENT(drv_sta_notify, | |||
545 | ) | 545 | ) |
546 | ); | 546 | ); |
547 | 547 | ||
548 | TRACE_EVENT(drv_conf_tx, | 548 | TRACE_EVENT(drv_sta_add, |
549 | TP_PROTO(struct ieee80211_local *local, u16 queue, | 549 | TP_PROTO(struct ieee80211_local *local, |
550 | const struct ieee80211_tx_queue_params *params, | 550 | struct ieee80211_sub_if_data *sdata, |
551 | int ret), | 551 | struct ieee80211_sta *sta, int ret), |
552 | 552 | ||
553 | TP_ARGS(local, queue, params, ret), | 553 | TP_ARGS(local, sdata, sta, ret), |
554 | 554 | ||
555 | TP_STRUCT__entry( | 555 | TP_STRUCT__entry( |
556 | LOCAL_ENTRY | 556 | LOCAL_ENTRY |
557 | __field(u16, queue) | 557 | VIF_ENTRY |
558 | __field(u16, txop) | 558 | STA_ENTRY |
559 | __field(u16, cw_min) | ||
560 | __field(u16, cw_max) | ||
561 | __field(u8, aifs) | ||
562 | __field(int, ret) | 559 | __field(int, ret) |
563 | ), | 560 | ), |
564 | 561 | ||
565 | TP_fast_assign( | 562 | TP_fast_assign( |
566 | LOCAL_ASSIGN; | 563 | LOCAL_ASSIGN; |
567 | __entry->queue = queue; | 564 | VIF_ASSIGN; |
565 | STA_ASSIGN; | ||
568 | __entry->ret = ret; | 566 | __entry->ret = ret; |
569 | __entry->txop = params->txop; | ||
570 | __entry->cw_max = params->cw_max; | ||
571 | __entry->cw_min = params->cw_min; | ||
572 | __entry->aifs = params->aifs; | ||
573 | ), | 567 | ), |
574 | 568 | ||
575 | TP_printk( | 569 | TP_printk( |
576 | LOCAL_PR_FMT " queue:%d ret:%d", | 570 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " ret:%d", |
577 | LOCAL_PR_ARG, __entry->queue, __entry->ret | 571 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->ret |
578 | ) | 572 | ) |
579 | ); | 573 | ); |
580 | 574 | ||
581 | TRACE_EVENT(drv_get_tx_stats, | 575 | TRACE_EVENT(drv_sta_remove, |
582 | TP_PROTO(struct ieee80211_local *local, | 576 | TP_PROTO(struct ieee80211_local *local, |
583 | struct ieee80211_tx_queue_stats *stats, | 577 | struct ieee80211_sub_if_data *sdata, |
578 | struct ieee80211_sta *sta), | ||
579 | |||
580 | TP_ARGS(local, sdata, sta), | ||
581 | |||
582 | TP_STRUCT__entry( | ||
583 | LOCAL_ENTRY | ||
584 | VIF_ENTRY | ||
585 | STA_ENTRY | ||
586 | ), | ||
587 | |||
588 | TP_fast_assign( | ||
589 | LOCAL_ASSIGN; | ||
590 | VIF_ASSIGN; | ||
591 | STA_ASSIGN; | ||
592 | ), | ||
593 | |||
594 | TP_printk( | ||
595 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT, | ||
596 | LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG | ||
597 | ) | ||
598 | ); | ||
599 | |||
600 | TRACE_EVENT(drv_conf_tx, | ||
601 | TP_PROTO(struct ieee80211_local *local, u16 queue, | ||
602 | const struct ieee80211_tx_queue_params *params, | ||
584 | int ret), | 603 | int ret), |
585 | 604 | ||
586 | TP_ARGS(local, stats, ret), | 605 | TP_ARGS(local, queue, params, ret), |
587 | 606 | ||
588 | TP_STRUCT__entry( | 607 | TP_STRUCT__entry( |
589 | LOCAL_ENTRY | 608 | LOCAL_ENTRY |
609 | __field(u16, queue) | ||
610 | __field(u16, txop) | ||
611 | __field(u16, cw_min) | ||
612 | __field(u16, cw_max) | ||
613 | __field(u8, aifs) | ||
590 | __field(int, ret) | 614 | __field(int, ret) |
591 | ), | 615 | ), |
592 | 616 | ||
593 | TP_fast_assign( | 617 | TP_fast_assign( |
594 | LOCAL_ASSIGN; | 618 | LOCAL_ASSIGN; |
619 | __entry->queue = queue; | ||
595 | __entry->ret = ret; | 620 | __entry->ret = ret; |
621 | __entry->txop = params->txop; | ||
622 | __entry->cw_max = params->cw_max; | ||
623 | __entry->cw_min = params->cw_min; | ||
624 | __entry->aifs = params->aifs; | ||
596 | ), | 625 | ), |
597 | 626 | ||
598 | TP_printk( | 627 | TP_printk( |
599 | LOCAL_PR_FMT " ret:%d", | 628 | LOCAL_PR_FMT " queue:%d ret:%d", |
600 | LOCAL_PR_ARG, __entry->ret | 629 | LOCAL_PR_ARG, __entry->queue, __entry->ret |
601 | ) | 630 | ) |
602 | ); | 631 | ); |
603 | 632 | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index f95750b423e3..f3e942486749 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -275,10 +275,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
275 | (unsigned long long) supp_rates, | 275 | (unsigned long long) supp_rates, |
276 | (unsigned long long) sta->sta.supp_rates[band]); | 276 | (unsigned long long) sta->sta.supp_rates[band]); |
277 | #endif | 277 | #endif |
278 | } else | 278 | rcu_read_unlock(); |
279 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 279 | } else { |
280 | 280 | rcu_read_unlock(); | |
281 | rcu_read_unlock(); | 281 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
282 | supp_rates, GFP_KERNEL); | ||
283 | } | ||
282 | } | 284 | } |
283 | 285 | ||
284 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, | 286 | bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems, |
@@ -368,7 +370,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
368 | sdata->name, mgmt->bssid); | 370 | sdata->name, mgmt->bssid); |
369 | #endif | 371 | #endif |
370 | ieee80211_sta_join_ibss(sdata, bss); | 372 | ieee80211_sta_join_ibss(sdata, bss); |
371 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); | 373 | ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, |
374 | supp_rates, GFP_KERNEL); | ||
372 | } | 375 | } |
373 | 376 | ||
374 | put_bss: | 377 | put_bss: |
@@ -381,7 +384,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
381 | * must be callable in atomic context. | 384 | * must be callable in atomic context. |
382 | */ | 385 | */ |
383 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 386 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
384 | u8 *bssid,u8 *addr, u32 supp_rates) | 387 | u8 *bssid,u8 *addr, u32 supp_rates, |
388 | gfp_t gfp) | ||
385 | { | 389 | { |
386 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 390 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
387 | struct ieee80211_local *local = sdata->local; | 391 | struct ieee80211_local *local = sdata->local; |
@@ -410,7 +414,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
410 | wiphy_name(local->hw.wiphy), addr, sdata->name); | 414 | wiphy_name(local->hw.wiphy), addr, sdata->name); |
411 | #endif | 415 | #endif |
412 | 416 | ||
413 | sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | 417 | sta = sta_info_alloc(sdata, addr, gfp); |
414 | if (!sta) | 418 | if (!sta) |
415 | return NULL; | 419 | return NULL; |
416 | 420 | ||
@@ -422,9 +426,9 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | |||
422 | 426 | ||
423 | rate_control_rate_init(sta); | 427 | rate_control_rate_init(sta); |
424 | 428 | ||
429 | /* If it fails, maybe we raced another insertion? */ | ||
425 | if (sta_info_insert(sta)) | 430 | if (sta_info_insert(sta)) |
426 | return NULL; | 431 | return sta_info_get(sdata, addr); |
427 | |||
428 | return sta; | 432 | return sta; |
429 | } | 433 | } |
430 | 434 | ||
@@ -652,7 +656,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, | |||
652 | } | 656 | } |
653 | if (pos[1] != 0 && | 657 | if (pos[1] != 0 && |
654 | (pos[1] != ifibss->ssid_len || | 658 | (pos[1] != ifibss->ssid_len || |
655 | !memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) { | 659 | memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len))) { |
656 | /* Ignore ProbeReq for foreign SSID */ | 660 | /* Ignore ProbeReq for foreign SSID */ |
657 | return; | 661 | return; |
658 | } | 662 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 3067fbd69d63..9dd98b674cbc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -316,6 +316,7 @@ enum ieee80211_sta_flags { | |||
316 | IEEE80211_STA_CSA_RECEIVED = BIT(5), | 316 | IEEE80211_STA_CSA_RECEIVED = BIT(5), |
317 | IEEE80211_STA_MFP_ENABLED = BIT(6), | 317 | IEEE80211_STA_MFP_ENABLED = BIT(6), |
318 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), | 318 | IEEE80211_STA_UAPSD_ENABLED = BIT(7), |
319 | IEEE80211_STA_NULLFUNC_ACKED = BIT(8), | ||
319 | }; | 320 | }; |
320 | 321 | ||
321 | struct ieee80211_if_managed { | 322 | struct ieee80211_if_managed { |
@@ -688,15 +689,18 @@ struct ieee80211_local { | |||
688 | 689 | ||
689 | /* Station data */ | 690 | /* Station data */ |
690 | /* | 691 | /* |
691 | * The lock only protects the list, hash, timer and counter | 692 | * The mutex only protects the list and counter, |
692 | * against manipulation, reads are done in RCU. Additionally, | 693 | * reads are done in RCU. |
693 | * the lock protects each BSS's TIM bitmap. | 694 | * Additionally, the lock protects the hash table, |
695 | * the pending list and each BSS's TIM bitmap. | ||
694 | */ | 696 | */ |
697 | struct mutex sta_mtx; | ||
695 | spinlock_t sta_lock; | 698 | spinlock_t sta_lock; |
696 | unsigned long num_sta; | 699 | unsigned long num_sta; |
697 | struct list_head sta_list; | 700 | struct list_head sta_list, sta_pending_list; |
698 | struct sta_info *sta_hash[STA_HASH_SIZE]; | 701 | struct sta_info *sta_hash[STA_HASH_SIZE]; |
699 | struct timer_list sta_cleanup; | 702 | struct timer_list sta_cleanup; |
703 | struct work_struct sta_finish_work; | ||
700 | int sta_generation; | 704 | int sta_generation; |
701 | 705 | ||
702 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; | 706 | struct sk_buff_head pending[IEEE80211_MAX_QUEUES]; |
@@ -770,10 +774,6 @@ struct ieee80211_local { | |||
770 | assoc_led_name[32], radio_led_name[32]; | 774 | assoc_led_name[32], radio_led_name[32]; |
771 | #endif | 775 | #endif |
772 | 776 | ||
773 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
774 | struct work_struct sta_debugfs_add; | ||
775 | #endif | ||
776 | |||
777 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS | 777 | #ifdef CONFIG_MAC80211_DEBUG_COUNTERS |
778 | /* TX/RX handler statistics */ | 778 | /* TX/RX handler statistics */ |
779 | unsigned int tx_handlers_drop; | 779 | unsigned int tx_handlers_drop; |
@@ -985,7 +985,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata); | |||
985 | ieee80211_rx_result | 985 | ieee80211_rx_result |
986 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); | 986 | ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); |
987 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | 987 | struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, |
988 | u8 *bssid, u8 *addr, u32 supp_rates); | 988 | u8 *bssid, u8 *addr, u32 supp_rates, |
989 | gfp_t gfp); | ||
989 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, | 990 | int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata, |
990 | struct cfg80211_ibss_params *params); | 991 | struct cfg80211_ibss_params *params); |
991 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); | 992 | int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 7985e5150898..bc4e20e57ff5 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -102,7 +102,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
102 | if (local->num_sta >= MESH_MAX_PLINKS) | 102 | if (local->num_sta >= MESH_MAX_PLINKS) |
103 | return NULL; | 103 | return NULL; |
104 | 104 | ||
105 | sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC); | 105 | sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); |
106 | if (!sta) | 106 | if (!sta) |
107 | return NULL; | 107 | return NULL; |
108 | 108 | ||
@@ -236,12 +236,12 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data | |||
236 | 236 | ||
237 | sta = sta_info_get(sdata, hw_addr); | 237 | sta = sta_info_get(sdata, hw_addr); |
238 | if (!sta) { | 238 | if (!sta) { |
239 | rcu_read_unlock(); | ||
240 | |||
239 | sta = mesh_plink_alloc(sdata, hw_addr, rates); | 241 | sta = mesh_plink_alloc(sdata, hw_addr, rates); |
240 | if (!sta) { | 242 | if (!sta) |
241 | rcu_read_unlock(); | ||
242 | return; | 243 | return; |
243 | } | 244 | if (sta_info_insert_rcu(sta)) { |
244 | if (sta_info_insert(sta)) { | ||
245 | rcu_read_unlock(); | 245 | rcu_read_unlock(); |
246 | return; | 246 | return; |
247 | } | 247 | } |
@@ -485,9 +485,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
485 | } else if (!sta) { | 485 | } else if (!sta) { |
486 | /* ftype == PLINK_OPEN */ | 486 | /* ftype == PLINK_OPEN */ |
487 | u32 rates; | 487 | u32 rates; |
488 | |||
489 | rcu_read_unlock(); | ||
490 | |||
488 | if (!mesh_plink_free_count(sdata)) { | 491 | if (!mesh_plink_free_count(sdata)) { |
489 | mpl_dbg("Mesh plink error: no more free plinks\n"); | 492 | mpl_dbg("Mesh plink error: no more free plinks\n"); |
490 | rcu_read_unlock(); | ||
491 | return; | 493 | return; |
492 | } | 494 | } |
493 | 495 | ||
@@ -495,10 +497,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
495 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); | 497 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); |
496 | if (!sta) { | 498 | if (!sta) { |
497 | mpl_dbg("Mesh plink error: plink table full\n"); | 499 | mpl_dbg("Mesh plink error: plink table full\n"); |
498 | rcu_read_unlock(); | ||
499 | return; | 500 | return; |
500 | } | 501 | } |
501 | if (sta_info_insert(sta)) { | 502 | if (sta_info_insert_rcu(sta)) { |
502 | rcu_read_unlock(); | 503 | rcu_read_unlock(); |
503 | return; | 504 | return; |
504 | } | 505 | } |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 86c6ad1b058d..bfc4a5070013 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -27,10 +27,6 @@ | |||
27 | #include "rate.h" | 27 | #include "rate.h" |
28 | #include "led.h" | 28 | #include "led.h" |
29 | 29 | ||
30 | #define IEEE80211_AUTH_TIMEOUT (HZ / 5) | ||
31 | #define IEEE80211_AUTH_MAX_TRIES 3 | ||
32 | #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) | ||
33 | #define IEEE80211_ASSOC_MAX_TRIES 3 | ||
34 | #define IEEE80211_MAX_PROBE_TRIES 5 | 30 | #define IEEE80211_MAX_PROBE_TRIES 5 |
35 | 31 | ||
36 | /* | 32 | /* |
@@ -438,8 +434,11 @@ static void ieee80211_enable_ps(struct ieee80211_local *local, | |||
438 | } else { | 434 | } else { |
439 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | 435 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) |
440 | ieee80211_send_nullfunc(local, sdata, 1); | 436 | ieee80211_send_nullfunc(local, sdata, 1); |
441 | conf->flags |= IEEE80211_CONF_PS; | 437 | |
442 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 438 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)) { |
439 | conf->flags |= IEEE80211_CONF_PS; | ||
440 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
441 | } | ||
443 | } | 442 | } |
444 | } | 443 | } |
445 | 444 | ||
@@ -545,6 +544,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
545 | container_of(work, struct ieee80211_local, | 544 | container_of(work, struct ieee80211_local, |
546 | dynamic_ps_enable_work); | 545 | dynamic_ps_enable_work); |
547 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; | 546 | struct ieee80211_sub_if_data *sdata = local->ps_sdata; |
547 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
548 | 548 | ||
549 | /* can only happen when PS was just disabled anyway */ | 549 | /* can only happen when PS was just disabled anyway */ |
550 | if (!sdata) | 550 | if (!sdata) |
@@ -553,11 +553,16 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
553 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 553 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
554 | return; | 554 | return; |
555 | 555 | ||
556 | if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) | 556 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
557 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) | ||
557 | ieee80211_send_nullfunc(local, sdata, 1); | 558 | ieee80211_send_nullfunc(local, sdata, 1); |
558 | 559 | ||
559 | local->hw.conf.flags |= IEEE80211_CONF_PS; | 560 | if (!(local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) || |
560 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 561 | (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { |
562 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | ||
563 | local->hw.conf.flags |= IEEE80211_CONF_PS; | ||
564 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||
565 | } | ||
561 | } | 566 | } |
562 | 567 | ||
563 | void ieee80211_dynamic_ps_timer(unsigned long data) | 568 | void ieee80211_dynamic_ps_timer(unsigned long data) |
@@ -792,8 +797,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | |||
792 | 797 | ||
793 | rcu_read_lock(); | 798 | rcu_read_lock(); |
794 | sta = sta_info_get(sdata, bssid); | 799 | sta = sta_info_get(sdata, bssid); |
795 | if (sta) | 800 | if (sta) { |
801 | set_sta_flags(sta, WLAN_STA_DISASSOC); | ||
796 | ieee80211_sta_tear_down_BA_sessions(sta); | 802 | ieee80211_sta_tear_down_BA_sessions(sta); |
803 | } | ||
797 | rcu_read_unlock(); | 804 | rcu_read_unlock(); |
798 | 805 | ||
799 | changed |= ieee80211_reset_erp_info(sdata); | 806 | changed |= ieee80211_reset_erp_info(sdata); |
@@ -826,19 +833,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata) | |||
826 | changed |= BSS_CHANGED_BSSID; | 833 | changed |= BSS_CHANGED_BSSID; |
827 | ieee80211_bss_info_change_notify(sdata, changed); | 834 | ieee80211_bss_info_change_notify(sdata, changed); |
828 | 835 | ||
829 | rcu_read_lock(); | 836 | sta_info_destroy_addr(sdata, bssid); |
830 | |||
831 | sta = sta_info_get(sdata, bssid); | ||
832 | if (!sta) { | ||
833 | rcu_read_unlock(); | ||
834 | return; | ||
835 | } | ||
836 | |||
837 | sta_info_unlink(&sta); | ||
838 | |||
839 | rcu_read_unlock(); | ||
840 | |||
841 | sta_info_destroy(sta); | ||
842 | } | 837 | } |
843 | 838 | ||
844 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | 839 | void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, |
@@ -1844,7 +1839,11 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
1844 | wk->probe_auth.algorithm = auth_alg; | 1839 | wk->probe_auth.algorithm = auth_alg; |
1845 | wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; | 1840 | wk->probe_auth.privacy = req->bss->capability & WLAN_CAPABILITY_PRIVACY; |
1846 | 1841 | ||
1847 | wk->type = IEEE80211_WORK_DIRECT_PROBE; | 1842 | /* if we already have a probe, don't probe again */ |
1843 | if (req->bss->proberesp_ies) | ||
1844 | wk->type = IEEE80211_WORK_AUTH; | ||
1845 | else | ||
1846 | wk->type = IEEE80211_WORK_DIRECT_PROBE; | ||
1848 | wk->chan = req->bss->channel; | 1847 | wk->chan = req->bss->channel; |
1849 | wk->sdata = sdata; | 1848 | wk->sdata = sdata; |
1850 | wk->done = ieee80211_probe_auth_done; | 1849 | wk->done = ieee80211_probe_auth_done; |
@@ -1904,6 +1903,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
1904 | return -ENOMEM; | 1903 | return -ENOMEM; |
1905 | 1904 | ||
1906 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; | 1905 | ifmgd->flags &= ~IEEE80211_STA_DISABLE_11N; |
1906 | ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED; | ||
1907 | 1907 | ||
1908 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) | 1908 | for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) |
1909 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || | 1909 | if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || |
@@ -2007,12 +2007,18 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, | |||
2007 | 2007 | ||
2008 | mutex_lock(&local->work_mtx); | 2008 | mutex_lock(&local->work_mtx); |
2009 | list_for_each_entry(wk, &local->work_list, list) { | 2009 | list_for_each_entry(wk, &local->work_list, list) { |
2010 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE) | 2010 | if (wk->sdata != sdata) |
2011 | continue; | ||
2012 | |||
2013 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE && | ||
2014 | wk->type != IEEE80211_WORK_AUTH) | ||
2011 | continue; | 2015 | continue; |
2016 | |||
2012 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) | 2017 | if (memcmp(req->bss->bssid, wk->filter_ta, ETH_ALEN)) |
2013 | continue; | 2018 | continue; |
2014 | not_auth_yet = true; | 2019 | |
2015 | list_del(&wk->list); | 2020 | not_auth_yet = wk->type == IEEE80211_WORK_DIRECT_PROBE; |
2021 | list_del_rcu(&wk->list); | ||
2016 | free_work(wk); | 2022 | free_work(wk); |
2017 | break; | 2023 | break; |
2018 | } | 2024 | } |
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 47f818959ad7..0e64484e861c 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c | |||
@@ -11,7 +11,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
11 | struct ieee80211_local *local = hw_to_local(hw); | 11 | struct ieee80211_local *local = hw_to_local(hw); |
12 | struct ieee80211_sub_if_data *sdata; | 12 | struct ieee80211_sub_if_data *sdata; |
13 | struct sta_info *sta; | 13 | struct sta_info *sta; |
14 | unsigned long flags; | ||
15 | 14 | ||
16 | ieee80211_scan_cancel(local); | 15 | ieee80211_scan_cancel(local); |
17 | 16 | ||
@@ -55,22 +54,21 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | |||
55 | rcu_read_unlock(); | 54 | rcu_read_unlock(); |
56 | 55 | ||
57 | /* remove STAs */ | 56 | /* remove STAs */ |
58 | spin_lock_irqsave(&local->sta_lock, flags); | 57 | mutex_lock(&local->sta_mtx); |
59 | list_for_each_entry(sta, &local->sta_list, list) { | 58 | list_for_each_entry(sta, &local->sta_list, list) { |
60 | if (local->ops->sta_notify) { | 59 | if (sta->uploaded) { |
61 | sdata = sta->sdata; | 60 | sdata = sta->sdata; |
62 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 61 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
63 | sdata = container_of(sdata->bss, | 62 | sdata = container_of(sdata->bss, |
64 | struct ieee80211_sub_if_data, | 63 | struct ieee80211_sub_if_data, |
65 | u.ap); | 64 | u.ap); |
66 | 65 | ||
67 | drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE, | 66 | drv_sta_remove(local, sdata, &sta->sta); |
68 | &sta->sta); | ||
69 | } | 67 | } |
70 | 68 | ||
71 | mesh_plink_quiesce(sta); | 69 | mesh_plink_quiesce(sta); |
72 | } | 70 | } |
73 | spin_unlock_irqrestore(&local->sta_lock, flags); | 71 | mutex_unlock(&local->sta_mtx); |
74 | 72 | ||
75 | /* remove all interfaces */ | 73 | /* remove all interfaces */ |
76 | list_for_each_entry(sdata, &local->interfaces, list) { | 74 | list_for_each_entry(sdata, &local->interfaces, list) { |
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index c74b7c85403c..0b299d236fa1 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c | |||
@@ -145,7 +145,7 @@ static const struct file_operations rcname_ops = { | |||
145 | }; | 145 | }; |
146 | #endif | 146 | #endif |
147 | 147 | ||
148 | struct rate_control_ref *rate_control_alloc(const char *name, | 148 | static struct rate_control_ref *rate_control_alloc(const char *name, |
149 | struct ieee80211_local *local) | 149 | struct ieee80211_local *local) |
150 | { | 150 | { |
151 | struct dentry *debugfsdir = NULL; | 151 | struct dentry *debugfsdir = NULL; |
@@ -303,6 +303,9 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | |||
303 | info->control.rates[i].count = 1; | 303 | info->control.rates[i].count = 1; |
304 | } | 304 | } |
305 | 305 | ||
306 | if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) | ||
307 | return; | ||
308 | |||
306 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); | 309 | ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); |
307 | 310 | ||
308 | /* | 311 | /* |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 998cf7a935b6..b6108bca96d4 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -26,10 +26,6 @@ struct rate_control_ref { | |||
26 | struct kref kref; | 26 | struct kref kref; |
27 | }; | 27 | }; |
28 | 28 | ||
29 | /* Get a reference to the rate control algorithm. If `name' is NULL, get the | ||
30 | * first available algorithm. */ | ||
31 | struct rate_control_ref *rate_control_alloc(const char *name, | ||
32 | struct ieee80211_local *local); | ||
33 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, | 29 | void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, |
34 | struct sta_info *sta, | 30 | struct sta_info *sta, |
35 | struct ieee80211_tx_rate_control *txrc); | 31 | struct ieee80211_tx_rate_control *txrc); |
@@ -116,7 +112,8 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) | |||
116 | #endif | 112 | #endif |
117 | } | 113 | } |
118 | 114 | ||
119 | /* functions for rate control related to a device */ | 115 | /* Get a reference to the rate control algorithm. If `name' is NULL, get the |
116 | * first available algorithm. */ | ||
120 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, | 117 | int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, |
121 | const char *name); | 118 | const char *name); |
122 | void rate_control_deinitialize(struct ieee80211_local *local); | 119 | void rate_control_deinitialize(struct ieee80211_local *local); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5709307fcb9b..c9755f3d986c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1719,6 +1719,7 @@ static ieee80211_rx_result debug_noinline | |||
1719 | ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | 1719 | ieee80211_rx_h_data(struct ieee80211_rx_data *rx) |
1720 | { | 1720 | { |
1721 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1721 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
1722 | struct ieee80211_local *local = rx->local; | ||
1722 | struct net_device *dev = sdata->dev; | 1723 | struct net_device *dev = sdata->dev; |
1723 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; | 1724 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; |
1724 | __le16 fc = hdr->frame_control; | 1725 | __le16 fc = hdr->frame_control; |
@@ -1750,6 +1751,13 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1750 | dev->stats.rx_packets++; | 1751 | dev->stats.rx_packets++; |
1751 | dev->stats.rx_bytes += rx->skb->len; | 1752 | dev->stats.rx_bytes += rx->skb->len; |
1752 | 1753 | ||
1754 | if (ieee80211_is_data(hdr->frame_control) && | ||
1755 | !is_multicast_ether_addr(hdr->addr1) && | ||
1756 | local->hw.conf.dynamic_ps_timeout > 0 && local->ps_sdata) { | ||
1757 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
1758 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||
1759 | } | ||
1760 | |||
1753 | ieee80211_deliver_skb(rx); | 1761 | ieee80211_deliver_skb(rx); |
1754 | 1762 | ||
1755 | return RX_QUEUED; | 1763 | return RX_QUEUED; |
@@ -2244,8 +2252,8 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, | |||
2244 | rate_idx = 0; /* TODO: HT rates */ | 2252 | rate_idx = 0; /* TODO: HT rates */ |
2245 | else | 2253 | else |
2246 | rate_idx = status->rate_idx; | 2254 | rate_idx = status->rate_idx; |
2247 | rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2, | 2255 | rx->sta = ieee80211_ibss_add_sta(sdata, bssid, |
2248 | BIT(rate_idx)); | 2256 | hdr->addr2, BIT(rate_idx), GFP_ATOMIC); |
2249 | } | 2257 | } |
2250 | break; | 2258 | break; |
2251 | case NL80211_IFTYPE_MESH_POINT: | 2259 | case NL80211_IFTYPE_MESH_POINT: |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index bc061f629674..b822dce97867 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -345,6 +345,13 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
345 | if (local->scan_req) | 345 | if (local->scan_req) |
346 | return -EBUSY; | 346 | return -EBUSY; |
347 | 347 | ||
348 | if (!list_empty(&local->work_list)) { | ||
349 | /* wait for the work to finish/time out */ | ||
350 | local->scan_req = req; | ||
351 | local->scan_sdata = sdata; | ||
352 | return 0; | ||
353 | } | ||
354 | |||
348 | if (local->ops->hw_scan) { | 355 | if (local->ops->hw_scan) { |
349 | u8 *ies; | 356 | u8 *ies; |
350 | 357 | ||
@@ -364,29 +371,33 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | |||
364 | local->hw_scan_req->ie = ies; | 371 | local->hw_scan_req->ie = ies; |
365 | 372 | ||
366 | local->hw_scan_band = 0; | 373 | local->hw_scan_band = 0; |
374 | |||
375 | /* | ||
376 | * After allocating local->hw_scan_req, we must | ||
377 | * go through until ieee80211_prep_hw_scan(), so | ||
378 | * anything that might be changed here and leave | ||
379 | * this function early must not go after this | ||
380 | * allocation. | ||
381 | */ | ||
367 | } | 382 | } |
368 | 383 | ||
369 | local->scan_req = req; | 384 | local->scan_req = req; |
370 | local->scan_sdata = sdata; | 385 | local->scan_sdata = sdata; |
371 | 386 | ||
372 | if (!list_empty(&local->work_list)) { | ||
373 | /* wait for the work to finish/time out */ | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | if (local->ops->hw_scan) | 387 | if (local->ops->hw_scan) |
378 | __set_bit(SCAN_HW_SCANNING, &local->scanning); | 388 | __set_bit(SCAN_HW_SCANNING, &local->scanning); |
379 | else | 389 | else |
380 | __set_bit(SCAN_SW_SCANNING, &local->scanning); | 390 | __set_bit(SCAN_SW_SCANNING, &local->scanning); |
391 | |||
381 | /* | 392 | /* |
382 | * Kicking off the scan need not be protected, | 393 | * Kicking off the scan need not be protected, |
383 | * only the scan variable stuff, since now | 394 | * only the scan variable stuff, since now |
384 | * local->scan_req is assigned and other callers | 395 | * local->scan_req is assigned and other callers |
385 | * will abort their scan attempts. | 396 | * will abort their scan attempts. |
386 | * | 397 | * |
387 | * This avoids getting a scan_mtx -> iflist_mtx | 398 | * This avoids too many locking dependencies |
388 | * dependency, so that the scan completed calls | 399 | * so that the scan completed calls have more |
389 | * have more locking freedom. | 400 | * locking freedom. |
390 | */ | 401 | */ |
391 | 402 | ||
392 | ieee80211_recalc_idle(local); | 403 | ieee80211_recalc_idle(local); |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f735826f055c..211c475f73c6 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -32,49 +32,33 @@ | |||
32 | * for faster lookup and a list for iteration. They are managed using | 32 | * for faster lookup and a list for iteration. They are managed using |
33 | * RCU, i.e. access to the list and hash table is protected by RCU. | 33 | * RCU, i.e. access to the list and hash table is protected by RCU. |
34 | * | 34 | * |
35 | * Upon allocating a STA info structure with sta_info_alloc(), the caller owns | 35 | * Upon allocating a STA info structure with sta_info_alloc(), the caller |
36 | * that structure. It must then either destroy it using sta_info_destroy() | 36 | * owns that structure. It must then insert it into the hash table using |
37 | * (which is pretty useless) or insert it into the hash table using | 37 | * either sta_info_insert() or sta_info_insert_rcu(); only in the latter |
38 | * sta_info_insert() which demotes the reference from ownership to a regular | 38 | * case (which acquires an rcu read section but must not be called from |
39 | * RCU-protected reference; if the function is called without protection by an | 39 | * within one) will the pointer still be valid after the call. Note that |
40 | * RCU critical section the reference is instantly invalidated. Note that the | 40 | * the caller may not do much with the STA info before inserting it, in |
41 | * caller may not do much with the STA info before inserting it, in particular, | 41 | * particular, it may not start any mesh peer link management or add |
42 | * it may not start any mesh peer link management or add encryption keys. | 42 | * encryption keys. |
43 | * | 43 | * |
44 | * When the insertion fails (sta_info_insert()) returns non-zero), the | 44 | * When the insertion fails (sta_info_insert()) returns non-zero), the |
45 | * structure will have been freed by sta_info_insert()! | 45 | * structure will have been freed by sta_info_insert()! |
46 | * | 46 | * |
47 | * sta entries are added by mac80211 when you establish a link with a | 47 | * Station entries are added by mac80211 when you establish a link with a |
48 | * peer. This means different things for the different type of interfaces | 48 | * peer. This means different things for the different type of interfaces |
49 | * we support. For a regular station this mean we add the AP sta when we | 49 | * we support. For a regular station this mean we add the AP sta when we |
50 | * receive an assocation response from the AP. For IBSS this occurs when | 50 | * receive an assocation response from the AP. For IBSS this occurs when |
51 | * we receive a probe response or a beacon from target IBSS network. For | 51 | * get to know about a peer on the same IBSS. For WDS we add the sta for |
52 | * WDS we add the sta for the peer imediately upon device open. When using | 52 | * the peer imediately upon device open. When using AP mode we add stations |
53 | * AP mode we add stations for each respective station upon request from | 53 | * for each respective station upon request from userspace through nl80211. |
54 | * userspace through nl80211. | ||
55 | * | 54 | * |
56 | * Because there are debugfs entries for each station, and adding those | 55 | * In order to remove a STA info structure, various sta_info_destroy_*() |
57 | * must be able to sleep, it is also possible to "pin" a station entry, | 56 | * calls are available. |
58 | * that means it can be removed from the hash table but not be freed. | ||
59 | * See the comment in __sta_info_unlink() for more information, this is | ||
60 | * an internal capability only. | ||
61 | * | 57 | * |
62 | * In order to remove a STA info structure, the caller needs to first | 58 | * There is no concept of ownership on a STA entry, each structure is |
63 | * unlink it (sta_info_unlink()) from the list and hash tables and | 59 | * owned by the global hash table/list until it is removed. All users of |
64 | * then destroy it; sta_info_destroy() will wait for an RCU grace period | 60 | * the structure need to be RCU protected so that the structure won't be |
65 | * to elapse before actually freeing it. Due to the pinning and the | 61 | * freed before they are done using it. |
66 | * possibility of multiple callers trying to remove the same STA info at | ||
67 | * the same time, sta_info_unlink() can clear the STA info pointer it is | ||
68 | * passed to indicate that the STA info is owned by somebody else now. | ||
69 | * | ||
70 | * If sta_info_unlink() did not clear the pointer then the caller owns | ||
71 | * the STA info structure now and is responsible of destroying it with | ||
72 | * a call to sta_info_destroy(). | ||
73 | * | ||
74 | * In all other cases, there is no concept of ownership on a STA entry, | ||
75 | * each structure is owned by the global hash table/list until it is | ||
76 | * removed. All users of the structure need to be RCU protected so that | ||
77 | * the structure won't be freed before they are done using it. | ||
78 | */ | 62 | */ |
79 | 63 | ||
80 | /* Caller must hold local->sta_lock */ | 64 | /* Caller must hold local->sta_lock */ |
@@ -185,101 +169,6 @@ static void __sta_info_free(struct ieee80211_local *local, | |||
185 | kfree(sta); | 169 | kfree(sta); |
186 | } | 170 | } |
187 | 171 | ||
188 | void sta_info_destroy(struct sta_info *sta) | ||
189 | { | ||
190 | struct ieee80211_local *local; | ||
191 | struct sk_buff *skb; | ||
192 | int i; | ||
193 | |||
194 | might_sleep(); | ||
195 | |||
196 | if (!sta) | ||
197 | return; | ||
198 | |||
199 | local = sta->local; | ||
200 | |||
201 | cancel_work_sync(&sta->drv_unblock_wk); | ||
202 | |||
203 | rate_control_remove_sta_debugfs(sta); | ||
204 | ieee80211_sta_debugfs_remove(sta); | ||
205 | |||
206 | #ifdef CONFIG_MAC80211_MESH | ||
207 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
208 | mesh_plink_deactivate(sta); | ||
209 | #endif | ||
210 | |||
211 | /* | ||
212 | * We have only unlinked the key, and actually destroying it | ||
213 | * may mean it is removed from hardware which requires that | ||
214 | * the key->sta pointer is still valid, so flush the key todo | ||
215 | * list here. | ||
216 | * | ||
217 | * ieee80211_key_todo() will synchronize_rcu() so after this | ||
218 | * nothing can reference this sta struct any more. | ||
219 | */ | ||
220 | ieee80211_key_todo(); | ||
221 | |||
222 | #ifdef CONFIG_MAC80211_MESH | ||
223 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | ||
224 | del_timer_sync(&sta->plink_timer); | ||
225 | #endif | ||
226 | |||
227 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | ||
228 | local->total_ps_buffered--; | ||
229 | dev_kfree_skb_any(skb); | ||
230 | } | ||
231 | |||
232 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
233 | dev_kfree_skb_any(skb); | ||
234 | |||
235 | for (i = 0; i < STA_TID_NUM; i++) { | ||
236 | struct tid_ampdu_rx *tid_rx; | ||
237 | struct tid_ampdu_tx *tid_tx; | ||
238 | |||
239 | spin_lock_bh(&sta->lock); | ||
240 | tid_rx = sta->ampdu_mlme.tid_rx[i]; | ||
241 | /* Make sure timer won't free the tid_rx struct, see below */ | ||
242 | if (tid_rx) | ||
243 | tid_rx->shutdown = true; | ||
244 | |||
245 | spin_unlock_bh(&sta->lock); | ||
246 | |||
247 | /* | ||
248 | * Outside spinlock - shutdown is true now so that the timer | ||
249 | * won't free tid_rx, we have to do that now. Can't let the | ||
250 | * timer do it because we have to sync the timer outside the | ||
251 | * lock that it takes itself. | ||
252 | */ | ||
253 | if (tid_rx) { | ||
254 | del_timer_sync(&tid_rx->session_timer); | ||
255 | kfree(tid_rx); | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * No need to do such complications for TX agg sessions, the | ||
260 | * path leading to freeing the tid_tx struct goes via a call | ||
261 | * from the driver, and thus needs to look up the sta struct | ||
262 | * again, which cannot be found when we get here. Hence, we | ||
263 | * just need to delete the timer and free the aggregation | ||
264 | * info; we won't be telling the peer about it then but that | ||
265 | * doesn't matter if we're not talking to it again anyway. | ||
266 | */ | ||
267 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
268 | if (tid_tx) { | ||
269 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
270 | /* | ||
271 | * STA removed while aggregation session being | ||
272 | * started? Bit odd, but purge frames anyway. | ||
273 | */ | ||
274 | skb_queue_purge(&tid_tx->pending); | ||
275 | kfree(tid_tx); | ||
276 | } | ||
277 | } | ||
278 | |||
279 | __sta_info_free(local, sta); | ||
280 | } | ||
281 | |||
282 | |||
283 | /* Caller must hold local->sta_lock */ | 172 | /* Caller must hold local->sta_lock */ |
284 | static void sta_info_hash_add(struct ieee80211_local *local, | 173 | static void sta_info_hash_add(struct ieee80211_local *local, |
285 | struct sta_info *sta) | 174 | struct sta_info *sta) |
@@ -376,7 +265,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
376 | return sta; | 265 | return sta; |
377 | } | 266 | } |
378 | 267 | ||
379 | int sta_info_insert(struct sta_info *sta) | 268 | static int sta_info_finish_insert(struct sta_info *sta, bool async) |
380 | { | 269 | { |
381 | struct ieee80211_local *local = sta->local; | 270 | struct ieee80211_local *local = sta->local; |
382 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 271 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
@@ -384,6 +273,91 @@ int sta_info_insert(struct sta_info *sta) | |||
384 | unsigned long flags; | 273 | unsigned long flags; |
385 | int err = 0; | 274 | int err = 0; |
386 | 275 | ||
276 | WARN_ON(!mutex_is_locked(&local->sta_mtx)); | ||
277 | |||
278 | /* notify driver */ | ||
279 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
280 | sdata = container_of(sdata->bss, | ||
281 | struct ieee80211_sub_if_data, | ||
282 | u.ap); | ||
283 | err = drv_sta_add(local, sdata, &sta->sta); | ||
284 | if (err) { | ||
285 | if (!async) | ||
286 | return err; | ||
287 | printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to driver (%d)" | ||
288 | " - keeping it anyway.\n", | ||
289 | sdata->name, sta->sta.addr, err); | ||
290 | } else { | ||
291 | sta->uploaded = true; | ||
292 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
293 | if (async) | ||
294 | printk(KERN_DEBUG "%s: Finished adding IBSS STA %pM\n", | ||
295 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
296 | #endif | ||
297 | } | ||
298 | |||
299 | sdata = sta->sdata; | ||
300 | |||
301 | if (!async) { | ||
302 | local->num_sta++; | ||
303 | local->sta_generation++; | ||
304 | smp_mb(); | ||
305 | |||
306 | /* make the station visible */ | ||
307 | spin_lock_irqsave(&local->sta_lock, flags); | ||
308 | sta_info_hash_add(local, sta); | ||
309 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
310 | } | ||
311 | |||
312 | list_add(&sta->list, &local->sta_list); | ||
313 | |||
314 | ieee80211_sta_debugfs_add(sta); | ||
315 | rate_control_add_sta_debugfs(sta); | ||
316 | |||
317 | sinfo.filled = 0; | ||
318 | sinfo.generation = local->sta_generation; | ||
319 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); | ||
320 | |||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static void sta_info_finish_pending(struct ieee80211_local *local) | ||
326 | { | ||
327 | struct sta_info *sta; | ||
328 | unsigned long flags; | ||
329 | |||
330 | spin_lock_irqsave(&local->sta_lock, flags); | ||
331 | while (!list_empty(&local->sta_pending_list)) { | ||
332 | sta = list_first_entry(&local->sta_pending_list, | ||
333 | struct sta_info, list); | ||
334 | list_del(&sta->list); | ||
335 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
336 | |||
337 | sta_info_finish_insert(sta, true); | ||
338 | |||
339 | spin_lock_irqsave(&local->sta_lock, flags); | ||
340 | } | ||
341 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
342 | } | ||
343 | |||
344 | static void sta_info_finish_work(struct work_struct *work) | ||
345 | { | ||
346 | struct ieee80211_local *local = | ||
347 | container_of(work, struct ieee80211_local, sta_finish_work); | ||
348 | |||
349 | mutex_lock(&local->sta_mtx); | ||
350 | sta_info_finish_pending(local); | ||
351 | mutex_unlock(&local->sta_mtx); | ||
352 | } | ||
353 | |||
354 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) | ||
355 | { | ||
356 | struct ieee80211_local *local = sta->local; | ||
357 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
358 | unsigned long flags; | ||
359 | int err = 0; | ||
360 | |||
387 | /* | 361 | /* |
388 | * Can't be a WARN_ON because it can be triggered through a race: | 362 | * Can't be a WARN_ON because it can be triggered through a race: |
389 | * something inserts a STA (on one CPU) without holding the RTNL | 363 | * something inserts a STA (on one CPU) without holding the RTNL |
@@ -391,36 +365,87 @@ int sta_info_insert(struct sta_info *sta) | |||
391 | */ | 365 | */ |
392 | if (unlikely(!ieee80211_sdata_running(sdata))) { | 366 | if (unlikely(!ieee80211_sdata_running(sdata))) { |
393 | err = -ENETDOWN; | 367 | err = -ENETDOWN; |
368 | rcu_read_lock(); | ||
394 | goto out_free; | 369 | goto out_free; |
395 | } | 370 | } |
396 | 371 | ||
397 | if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 || | 372 | if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 || |
398 | is_multicast_ether_addr(sta->sta.addr))) { | 373 | is_multicast_ether_addr(sta->sta.addr))) { |
399 | err = -EINVAL; | 374 | err = -EINVAL; |
375 | rcu_read_lock(); | ||
400 | goto out_free; | 376 | goto out_free; |
401 | } | 377 | } |
402 | 378 | ||
379 | /* | ||
380 | * In ad-hoc mode, we sometimes need to insert stations | ||
381 | * from tasklet context from the RX path. To avoid races, | ||
382 | * always do so in that case -- see the comment below. | ||
383 | */ | ||
384 | if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { | ||
385 | spin_lock_irqsave(&local->sta_lock, flags); | ||
386 | /* check if STA exists already */ | ||
387 | if (sta_info_get_bss(sdata, sta->sta.addr)) { | ||
388 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
389 | rcu_read_lock(); | ||
390 | err = -EEXIST; | ||
391 | goto out_free; | ||
392 | } | ||
393 | |||
394 | local->num_sta++; | ||
395 | local->sta_generation++; | ||
396 | smp_mb(); | ||
397 | sta_info_hash_add(local, sta); | ||
398 | |||
399 | list_add_tail(&sta->list, &local->sta_pending_list); | ||
400 | |||
401 | rcu_read_lock(); | ||
402 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
403 | |||
404 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
405 | printk(KERN_DEBUG "%s: Added IBSS STA %pM\n", | ||
406 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
407 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
408 | |||
409 | ieee80211_queue_work(&local->hw, &local->sta_finish_work); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * On first glance, this will look racy, because the code | ||
416 | * below this point, which inserts a station with sleeping, | ||
417 | * unlocks the sta_lock between checking existence in the | ||
418 | * hash table and inserting into it. | ||
419 | * | ||
420 | * However, it is not racy against itself because it keeps | ||
421 | * the mutex locked. It still seems to race against the | ||
422 | * above code that atomically inserts the station... That, | ||
423 | * however, is not true because the above code can only | ||
424 | * be invoked for IBSS interfaces, and the below code will | ||
425 | * not be -- and the two do not race against each other as | ||
426 | * the hash table also keys off the interface. | ||
427 | */ | ||
428 | |||
429 | might_sleep(); | ||
430 | |||
431 | mutex_lock(&local->sta_mtx); | ||
432 | |||
403 | spin_lock_irqsave(&local->sta_lock, flags); | 433 | spin_lock_irqsave(&local->sta_lock, flags); |
404 | /* check if STA exists already */ | 434 | /* check if STA exists already */ |
405 | if (sta_info_get(sdata, sta->sta.addr)) { | 435 | if (sta_info_get_bss(sdata, sta->sta.addr)) { |
406 | spin_unlock_irqrestore(&local->sta_lock, flags); | 436 | spin_unlock_irqrestore(&local->sta_lock, flags); |
437 | rcu_read_lock(); | ||
407 | err = -EEXIST; | 438 | err = -EEXIST; |
408 | goto out_free; | 439 | goto out_free; |
409 | } | 440 | } |
410 | list_add(&sta->list, &local->sta_list); | ||
411 | local->sta_generation++; | ||
412 | local->num_sta++; | ||
413 | sta_info_hash_add(local, sta); | ||
414 | 441 | ||
415 | /* notify driver */ | 442 | spin_unlock_irqrestore(&local->sta_lock, flags); |
416 | if (local->ops->sta_notify) { | ||
417 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
418 | sdata = container_of(sdata->bss, | ||
419 | struct ieee80211_sub_if_data, | ||
420 | u.ap); | ||
421 | 443 | ||
422 | drv_sta_notify(local, sdata, STA_NOTIFY_ADD, &sta->sta); | 444 | err = sta_info_finish_insert(sta, false); |
423 | sdata = sta->sdata; | 445 | if (err) { |
446 | mutex_unlock(&local->sta_mtx); | ||
447 | rcu_read_lock(); | ||
448 | goto out_free; | ||
424 | } | 449 | } |
425 | 450 | ||
426 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 451 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
@@ -428,22 +453,9 @@ int sta_info_insert(struct sta_info *sta) | |||
428 | wiphy_name(local->hw.wiphy), sta->sta.addr); | 453 | wiphy_name(local->hw.wiphy), sta->sta.addr); |
429 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | 454 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ |
430 | 455 | ||
431 | spin_unlock_irqrestore(&local->sta_lock, flags); | 456 | /* move reference to rcu-protected */ |
432 | 457 | rcu_read_lock(); | |
433 | sinfo.filled = 0; | 458 | mutex_unlock(&local->sta_mtx); |
434 | sinfo.generation = local->sta_generation; | ||
435 | cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_ATOMIC); | ||
436 | |||
437 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
438 | /* | ||
439 | * Debugfs entry adding might sleep, so schedule process | ||
440 | * context task for adding entry for STAs that do not yet | ||
441 | * have one. | ||
442 | * NOTE: due to auto-freeing semantics this may only be done | ||
443 | * if the insertion is successful! | ||
444 | */ | ||
445 | schedule_work(&local->sta_debugfs_add); | ||
446 | #endif | ||
447 | 459 | ||
448 | if (ieee80211_vif_is_mesh(&sdata->vif)) | 460 | if (ieee80211_vif_is_mesh(&sdata->vif)) |
449 | mesh_accept_plinks_update(sdata); | 461 | mesh_accept_plinks_update(sdata); |
@@ -455,6 +467,15 @@ int sta_info_insert(struct sta_info *sta) | |||
455 | return err; | 467 | return err; |
456 | } | 468 | } |
457 | 469 | ||
470 | int sta_info_insert(struct sta_info *sta) | ||
471 | { | ||
472 | int err = sta_info_insert_rcu(sta); | ||
473 | |||
474 | rcu_read_unlock(); | ||
475 | |||
476 | return err; | ||
477 | } | ||
478 | |||
458 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) | 479 | static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) |
459 | { | 480 | { |
460 | /* | 481 | /* |
@@ -523,108 +544,6 @@ void sta_info_clear_tim_bit(struct sta_info *sta) | |||
523 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | 544 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); |
524 | } | 545 | } |
525 | 546 | ||
526 | static void __sta_info_unlink(struct sta_info **sta) | ||
527 | { | ||
528 | struct ieee80211_local *local = (*sta)->local; | ||
529 | struct ieee80211_sub_if_data *sdata = (*sta)->sdata; | ||
530 | /* | ||
531 | * pull caller's reference if we're already gone. | ||
532 | */ | ||
533 | if (sta_info_hash_del(local, *sta)) { | ||
534 | *sta = NULL; | ||
535 | return; | ||
536 | } | ||
537 | |||
538 | if ((*sta)->key) { | ||
539 | ieee80211_key_free((*sta)->key); | ||
540 | WARN_ON((*sta)->key); | ||
541 | } | ||
542 | |||
543 | list_del(&(*sta)->list); | ||
544 | (*sta)->dead = true; | ||
545 | |||
546 | if (test_and_clear_sta_flags(*sta, | ||
547 | WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { | ||
548 | BUG_ON(!sdata->bss); | ||
549 | |||
550 | atomic_dec(&sdata->bss->num_sta_ps); | ||
551 | __sta_info_clear_tim_bit(sdata->bss, *sta); | ||
552 | } | ||
553 | |||
554 | local->num_sta--; | ||
555 | local->sta_generation++; | ||
556 | |||
557 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
558 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
559 | |||
560 | if (local->ops->sta_notify) { | ||
561 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
562 | sdata = container_of(sdata->bss, | ||
563 | struct ieee80211_sub_if_data, | ||
564 | u.ap); | ||
565 | |||
566 | drv_sta_notify(local, sdata, STA_NOTIFY_REMOVE, | ||
567 | &(*sta)->sta); | ||
568 | sdata = (*sta)->sdata; | ||
569 | } | ||
570 | |||
571 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
572 | mesh_accept_plinks_update(sdata); | ||
573 | #ifdef CONFIG_MAC80211_MESH | ||
574 | del_timer(&(*sta)->plink_timer); | ||
575 | #endif | ||
576 | } | ||
577 | |||
578 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
579 | printk(KERN_DEBUG "%s: Removed STA %pM\n", | ||
580 | wiphy_name(local->hw.wiphy), (*sta)->sta.addr); | ||
581 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
582 | |||
583 | /* | ||
584 | * Finally, pull caller's reference if the STA is pinned by the | ||
585 | * task that is adding the debugfs entries. In that case, we | ||
586 | * leave the STA "to be freed". | ||
587 | * | ||
588 | * The rules are not trivial, but not too complex either: | ||
589 | * (1) pin_status is only modified under the sta_lock | ||
590 | * (2) STAs may only be pinned under the RTNL so that | ||
591 | * sta_info_flush() is guaranteed to actually destroy | ||
592 | * all STAs that are active for a given interface, this | ||
593 | * is required for correctness because otherwise we | ||
594 | * could notify a driver that an interface is going | ||
595 | * away and only after that (!) notify it about a STA | ||
596 | * on that interface going away. | ||
597 | * (3) sta_info_debugfs_add_work() will set the status | ||
598 | * to PINNED when it found an item that needs a new | ||
599 | * debugfs directory created. In that case, that item | ||
600 | * must not be freed although all *RCU* users are done | ||
601 | * with it. Hence, we tell the caller of _unlink() | ||
602 | * that the item is already gone (as can happen when | ||
603 | * two tasks try to unlink/destroy at the same time) | ||
604 | * (4) We set the pin_status to DESTROY here when we | ||
605 | * find such an item. | ||
606 | * (5) sta_info_debugfs_add_work() will reset the pin_status | ||
607 | * from PINNED to NORMAL when it is done with the item, | ||
608 | * but will check for DESTROY before resetting it in | ||
609 | * which case it will free the item. | ||
610 | */ | ||
611 | if ((*sta)->pin_status == STA_INFO_PIN_STAT_PINNED) { | ||
612 | (*sta)->pin_status = STA_INFO_PIN_STAT_DESTROY; | ||
613 | *sta = NULL; | ||
614 | return; | ||
615 | } | ||
616 | } | ||
617 | |||
618 | void sta_info_unlink(struct sta_info **sta) | ||
619 | { | ||
620 | struct ieee80211_local *local = (*sta)->local; | ||
621 | unsigned long flags; | ||
622 | |||
623 | spin_lock_irqsave(&local->sta_lock, flags); | ||
624 | __sta_info_unlink(sta); | ||
625 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
626 | } | ||
627 | |||
628 | static int sta_info_buffer_expired(struct sta_info *sta, | 547 | static int sta_info_buffer_expired(struct sta_info *sta, |
629 | struct sk_buff *skb) | 548 | struct sk_buff *skb) |
630 | { | 549 | { |
@@ -681,109 +600,209 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, | |||
681 | } | 600 | } |
682 | } | 601 | } |
683 | 602 | ||
684 | 603 | static int __must_check __sta_info_destroy(struct sta_info *sta) | |
685 | static void sta_info_cleanup(unsigned long data) | ||
686 | { | 604 | { |
687 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 605 | struct ieee80211_local *local; |
688 | struct sta_info *sta; | 606 | struct ieee80211_sub_if_data *sdata; |
607 | struct sk_buff *skb; | ||
608 | unsigned long flags; | ||
609 | int ret, i; | ||
689 | 610 | ||
690 | rcu_read_lock(); | 611 | might_sleep(); |
691 | list_for_each_entry_rcu(sta, &local->sta_list, list) | ||
692 | sta_info_cleanup_expire_buffered(local, sta); | ||
693 | rcu_read_unlock(); | ||
694 | 612 | ||
695 | if (local->quiescing) | 613 | if (!sta) |
696 | return; | 614 | return -ENOENT; |
697 | 615 | ||
698 | local->sta_cleanup.expires = | 616 | local = sta->local; |
699 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 617 | sdata = sta->sdata; |
700 | add_timer(&local->sta_cleanup); | ||
701 | } | ||
702 | 618 | ||
703 | #ifdef CONFIG_MAC80211_DEBUGFS | 619 | spin_lock_irqsave(&local->sta_lock, flags); |
704 | /* | 620 | ret = sta_info_hash_del(local, sta); |
705 | * See comment in __sta_info_unlink, | 621 | /* this might still be the pending list ... which is fine */ |
706 | * caller must hold local->sta_lock. | 622 | if (!ret) |
707 | */ | 623 | list_del(&sta->list); |
708 | static void __sta_info_pin(struct sta_info *sta) | 624 | spin_unlock_irqrestore(&local->sta_lock, flags); |
709 | { | 625 | if (ret) |
710 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL); | 626 | return ret; |
711 | sta->pin_status = STA_INFO_PIN_STAT_PINNED; | 627 | |
628 | if (sta->key) { | ||
629 | ieee80211_key_free(sta->key); | ||
630 | /* | ||
631 | * We have only unlinked the key, and actually destroying it | ||
632 | * may mean it is removed from hardware which requires that | ||
633 | * the key->sta pointer is still valid, so flush the key todo | ||
634 | * list here. | ||
635 | * | ||
636 | * ieee80211_key_todo() will synchronize_rcu() so after this | ||
637 | * nothing can reference this sta struct any more. | ||
638 | */ | ||
639 | ieee80211_key_todo(); | ||
640 | |||
641 | WARN_ON(sta->key); | ||
642 | } | ||
643 | |||
644 | sta->dead = true; | ||
645 | |||
646 | if (test_and_clear_sta_flags(sta, | ||
647 | WLAN_STA_PS_STA | WLAN_STA_PS_DRIVER)) { | ||
648 | BUG_ON(!sdata->bss); | ||
649 | |||
650 | atomic_dec(&sdata->bss->num_sta_ps); | ||
651 | __sta_info_clear_tim_bit(sdata->bss, sta); | ||
652 | } | ||
653 | |||
654 | local->num_sta--; | ||
655 | local->sta_generation++; | ||
656 | |||
657 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
658 | rcu_assign_pointer(sdata->u.vlan.sta, NULL); | ||
659 | |||
660 | if (sta->uploaded) { | ||
661 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | ||
662 | sdata = container_of(sdata->bss, | ||
663 | struct ieee80211_sub_if_data, | ||
664 | u.ap); | ||
665 | drv_sta_remove(local, sdata, &sta->sta); | ||
666 | sdata = sta->sdata; | ||
667 | } | ||
668 | |||
669 | #ifdef CONFIG_MAC80211_MESH | ||
670 | if (ieee80211_vif_is_mesh(&sdata->vif)) { | ||
671 | mesh_accept_plinks_update(sdata); | ||
672 | del_timer(&sta->plink_timer); | ||
673 | } | ||
674 | #endif | ||
675 | |||
676 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
677 | printk(KERN_DEBUG "%s: Removed STA %pM\n", | ||
678 | wiphy_name(local->hw.wiphy), sta->sta.addr); | ||
679 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
680 | cancel_work_sync(&sta->drv_unblock_wk); | ||
681 | |||
682 | rate_control_remove_sta_debugfs(sta); | ||
683 | ieee80211_sta_debugfs_remove(sta); | ||
684 | |||
685 | #ifdef CONFIG_MAC80211_MESH | ||
686 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { | ||
687 | mesh_plink_deactivate(sta); | ||
688 | del_timer_sync(&sta->plink_timer); | ||
689 | } | ||
690 | #endif | ||
691 | |||
692 | while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { | ||
693 | local->total_ps_buffered--; | ||
694 | dev_kfree_skb_any(skb); | ||
695 | } | ||
696 | |||
697 | while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) | ||
698 | dev_kfree_skb_any(skb); | ||
699 | |||
700 | for (i = 0; i < STA_TID_NUM; i++) { | ||
701 | struct tid_ampdu_rx *tid_rx; | ||
702 | struct tid_ampdu_tx *tid_tx; | ||
703 | |||
704 | spin_lock_bh(&sta->lock); | ||
705 | tid_rx = sta->ampdu_mlme.tid_rx[i]; | ||
706 | /* Make sure timer won't free the tid_rx struct, see below */ | ||
707 | if (tid_rx) | ||
708 | tid_rx->shutdown = true; | ||
709 | |||
710 | spin_unlock_bh(&sta->lock); | ||
711 | |||
712 | /* | ||
713 | * Outside spinlock - shutdown is true now so that the timer | ||
714 | * won't free tid_rx, we have to do that now. Can't let the | ||
715 | * timer do it because we have to sync the timer outside the | ||
716 | * lock that it takes itself. | ||
717 | */ | ||
718 | if (tid_rx) { | ||
719 | del_timer_sync(&tid_rx->session_timer); | ||
720 | kfree(tid_rx); | ||
721 | } | ||
722 | |||
723 | /* | ||
724 | * No need to do such complications for TX agg sessions, the | ||
725 | * path leading to freeing the tid_tx struct goes via a call | ||
726 | * from the driver, and thus needs to look up the sta struct | ||
727 | * again, which cannot be found when we get here. Hence, we | ||
728 | * just need to delete the timer and free the aggregation | ||
729 | * info; we won't be telling the peer about it then but that | ||
730 | * doesn't matter if we're not talking to it again anyway. | ||
731 | */ | ||
732 | tid_tx = sta->ampdu_mlme.tid_tx[i]; | ||
733 | if (tid_tx) { | ||
734 | del_timer_sync(&tid_tx->addba_resp_timer); | ||
735 | /* | ||
736 | * STA removed while aggregation session being | ||
737 | * started? Bit odd, but purge frames anyway. | ||
738 | */ | ||
739 | skb_queue_purge(&tid_tx->pending); | ||
740 | kfree(tid_tx); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | __sta_info_free(local, sta); | ||
745 | |||
746 | return 0; | ||
712 | } | 747 | } |
713 | 748 | ||
714 | /* | 749 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr) |
715 | * See comment in __sta_info_unlink, returns sta if it | ||
716 | * needs to be destroyed. | ||
717 | */ | ||
718 | static struct sta_info *__sta_info_unpin(struct sta_info *sta) | ||
719 | { | 750 | { |
720 | struct sta_info *ret = NULL; | 751 | struct sta_info *sta; |
721 | unsigned long flags; | 752 | int ret; |
722 | 753 | ||
723 | spin_lock_irqsave(&sta->local->sta_lock, flags); | 754 | mutex_lock(&sdata->local->sta_mtx); |
724 | WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY && | 755 | sta = sta_info_get(sdata, addr); |
725 | sta->pin_status != STA_INFO_PIN_STAT_PINNED); | 756 | ret = __sta_info_destroy(sta); |
726 | if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY) | 757 | mutex_unlock(&sdata->local->sta_mtx); |
727 | ret = sta; | ||
728 | sta->pin_status = STA_INFO_PIN_STAT_NORMAL; | ||
729 | spin_unlock_irqrestore(&sta->local->sta_lock, flags); | ||
730 | 758 | ||
731 | return ret; | 759 | return ret; |
732 | } | 760 | } |
733 | 761 | ||
734 | static void sta_info_debugfs_add_work(struct work_struct *work) | 762 | int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, |
763 | const u8 *addr) | ||
735 | { | 764 | { |
736 | struct ieee80211_local *local = | 765 | struct sta_info *sta; |
737 | container_of(work, struct ieee80211_local, sta_debugfs_add); | 766 | int ret; |
738 | struct sta_info *sta, *tmp; | ||
739 | unsigned long flags; | ||
740 | 767 | ||
741 | /* We need to keep the RTNL across the whole pinned status. */ | 768 | mutex_lock(&sdata->local->sta_mtx); |
742 | rtnl_lock(); | 769 | sta = sta_info_get_bss(sdata, addr); |
743 | while (1) { | 770 | ret = __sta_info_destroy(sta); |
744 | sta = NULL; | 771 | mutex_unlock(&sdata->local->sta_mtx); |
745 | 772 | ||
746 | spin_lock_irqsave(&local->sta_lock, flags); | 773 | return ret; |
747 | list_for_each_entry(tmp, &local->sta_list, list) { | 774 | } |
748 | /* | ||
749 | * debugfs.add_has_run will be set by | ||
750 | * ieee80211_sta_debugfs_add regardless | ||
751 | * of what else it does. | ||
752 | */ | ||
753 | if (!tmp->debugfs.add_has_run) { | ||
754 | sta = tmp; | ||
755 | __sta_info_pin(sta); | ||
756 | break; | ||
757 | } | ||
758 | } | ||
759 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
760 | 775 | ||
761 | if (!sta) | 776 | static void sta_info_cleanup(unsigned long data) |
762 | break; | 777 | { |
778 | struct ieee80211_local *local = (struct ieee80211_local *) data; | ||
779 | struct sta_info *sta; | ||
780 | |||
781 | rcu_read_lock(); | ||
782 | list_for_each_entry_rcu(sta, &local->sta_list, list) | ||
783 | sta_info_cleanup_expire_buffered(local, sta); | ||
784 | rcu_read_unlock(); | ||
763 | 785 | ||
764 | ieee80211_sta_debugfs_add(sta); | 786 | if (local->quiescing) |
765 | rate_control_add_sta_debugfs(sta); | 787 | return; |
766 | 788 | ||
767 | sta = __sta_info_unpin(sta); | 789 | local->sta_cleanup.expires = |
768 | sta_info_destroy(sta); | 790 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
769 | } | 791 | add_timer(&local->sta_cleanup); |
770 | rtnl_unlock(); | ||
771 | } | 792 | } |
772 | #endif | ||
773 | 793 | ||
774 | void sta_info_init(struct ieee80211_local *local) | 794 | void sta_info_init(struct ieee80211_local *local) |
775 | { | 795 | { |
776 | spin_lock_init(&local->sta_lock); | 796 | spin_lock_init(&local->sta_lock); |
797 | mutex_init(&local->sta_mtx); | ||
777 | INIT_LIST_HEAD(&local->sta_list); | 798 | INIT_LIST_HEAD(&local->sta_list); |
799 | INIT_LIST_HEAD(&local->sta_pending_list); | ||
800 | INIT_WORK(&local->sta_finish_work, sta_info_finish_work); | ||
778 | 801 | ||
779 | setup_timer(&local->sta_cleanup, sta_info_cleanup, | 802 | setup_timer(&local->sta_cleanup, sta_info_cleanup, |
780 | (unsigned long)local); | 803 | (unsigned long)local); |
781 | local->sta_cleanup.expires = | 804 | local->sta_cleanup.expires = |
782 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); | 805 | round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); |
783 | |||
784 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
785 | INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_work); | ||
786 | #endif | ||
787 | } | 806 | } |
788 | 807 | ||
789 | int sta_info_start(struct ieee80211_local *local) | 808 | int sta_info_start(struct ieee80211_local *local) |
@@ -795,16 +814,6 @@ int sta_info_start(struct ieee80211_local *local) | |||
795 | void sta_info_stop(struct ieee80211_local *local) | 814 | void sta_info_stop(struct ieee80211_local *local) |
796 | { | 815 | { |
797 | del_timer(&local->sta_cleanup); | 816 | del_timer(&local->sta_cleanup); |
798 | #ifdef CONFIG_MAC80211_DEBUGFS | ||
799 | /* | ||
800 | * Make sure the debugfs adding work isn't pending after this | ||
801 | * because we're about to be destroyed. It doesn't matter | ||
802 | * whether it ran or not since we're going to flush all STAs | ||
803 | * anyway. | ||
804 | */ | ||
805 | cancel_work_sync(&local->sta_debugfs_add); | ||
806 | #endif | ||
807 | |||
808 | sta_info_flush(local, NULL); | 817 | sta_info_flush(local, NULL); |
809 | } | 818 | } |
810 | 819 | ||
@@ -820,26 +829,19 @@ int sta_info_flush(struct ieee80211_local *local, | |||
820 | struct ieee80211_sub_if_data *sdata) | 829 | struct ieee80211_sub_if_data *sdata) |
821 | { | 830 | { |
822 | struct sta_info *sta, *tmp; | 831 | struct sta_info *sta, *tmp; |
823 | LIST_HEAD(tmp_list); | ||
824 | int ret = 0; | 832 | int ret = 0; |
825 | unsigned long flags; | ||
826 | 833 | ||
827 | might_sleep(); | 834 | might_sleep(); |
828 | 835 | ||
829 | spin_lock_irqsave(&local->sta_lock, flags); | 836 | mutex_lock(&local->sta_mtx); |
837 | |||
838 | sta_info_finish_pending(local); | ||
839 | |||
830 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { | 840 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { |
831 | if (!sdata || sdata == sta->sdata) { | 841 | if (!sdata || sdata == sta->sdata) |
832 | __sta_info_unlink(&sta); | 842 | WARN_ON(__sta_info_destroy(sta)); |
833 | if (sta) { | ||
834 | list_add_tail(&sta->list, &tmp_list); | ||
835 | ret++; | ||
836 | } | ||
837 | } | ||
838 | } | 843 | } |
839 | spin_unlock_irqrestore(&local->sta_lock, flags); | 844 | mutex_unlock(&local->sta_mtx); |
840 | |||
841 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | ||
842 | sta_info_destroy(sta); | ||
843 | 845 | ||
844 | return ret; | 846 | return ret; |
845 | } | 847 | } |
@@ -849,24 +851,17 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, | |||
849 | { | 851 | { |
850 | struct ieee80211_local *local = sdata->local; | 852 | struct ieee80211_local *local = sdata->local; |
851 | struct sta_info *sta, *tmp; | 853 | struct sta_info *sta, *tmp; |
852 | LIST_HEAD(tmp_list); | ||
853 | unsigned long flags; | ||
854 | 854 | ||
855 | spin_lock_irqsave(&local->sta_lock, flags); | 855 | mutex_lock(&local->sta_mtx); |
856 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) | 856 | list_for_each_entry_safe(sta, tmp, &local->sta_list, list) |
857 | if (time_after(jiffies, sta->last_rx + exp_time)) { | 857 | if (time_after(jiffies, sta->last_rx + exp_time)) { |
858 | #ifdef CONFIG_MAC80211_IBSS_DEBUG | 858 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
859 | printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", | 859 | printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", |
860 | sdata->name, sta->sta.addr); | 860 | sdata->name, sta->sta.addr); |
861 | #endif | 861 | #endif |
862 | __sta_info_unlink(&sta); | 862 | WARN_ON(__sta_info_destroy(sta)); |
863 | if (sta) | ||
864 | list_add(&sta->list, &tmp_list); | ||
865 | } | 863 | } |
866 | spin_unlock_irqrestore(&local->sta_lock, flags); | 864 | mutex_unlock(&local->sta_mtx); |
867 | |||
868 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | ||
869 | sta_info_destroy(sta); | ||
870 | } | 865 | } |
871 | 866 | ||
872 | struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, | 867 | struct ieee80211_sta *ieee80211_find_sta_by_hw(struct ieee80211_hw *hw, |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 6f79bba5706e..822d84522937 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -42,6 +42,9 @@ | |||
42 | * be in the queues | 42 | * be in the queues |
43 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping | 43 | * @WLAN_STA_PSPOLL: Station sent PS-poll while driver was keeping |
44 | * station in power-save mode, reply when the driver unblocks. | 44 | * station in power-save mode, reply when the driver unblocks. |
45 | * @WLAN_STA_DISASSOC: Disassociation in progress. | ||
46 | * This is used to reject TX BA session requests when disassociation | ||
47 | * is in progress. | ||
45 | */ | 48 | */ |
46 | enum ieee80211_sta_info_flags { | 49 | enum ieee80211_sta_info_flags { |
47 | WLAN_STA_AUTH = 1<<0, | 50 | WLAN_STA_AUTH = 1<<0, |
@@ -57,6 +60,7 @@ enum ieee80211_sta_info_flags { | |||
57 | WLAN_STA_SUSPEND = 1<<11, | 60 | WLAN_STA_SUSPEND = 1<<11, |
58 | WLAN_STA_PS_DRIVER = 1<<12, | 61 | WLAN_STA_PS_DRIVER = 1<<12, |
59 | WLAN_STA_PSPOLL = 1<<13, | 62 | WLAN_STA_PSPOLL = 1<<13, |
63 | WLAN_STA_DISASSOC = 1<<14, | ||
60 | }; | 64 | }; |
61 | 65 | ||
62 | #define STA_TID_NUM 16 | 66 | #define STA_TID_NUM 16 |
@@ -162,11 +166,6 @@ struct sta_ampdu_mlme { | |||
162 | }; | 166 | }; |
163 | 167 | ||
164 | 168 | ||
165 | /* see __sta_info_unlink */ | ||
166 | #define STA_INFO_PIN_STAT_NORMAL 0 | ||
167 | #define STA_INFO_PIN_STAT_PINNED 1 | ||
168 | #define STA_INFO_PIN_STAT_DESTROY 2 | ||
169 | |||
170 | /** | 169 | /** |
171 | * struct sta_info - STA information | 170 | * struct sta_info - STA information |
172 | * | 171 | * |
@@ -187,7 +186,6 @@ struct sta_ampdu_mlme { | |||
187 | * @flaglock: spinlock for flags accesses | 186 | * @flaglock: spinlock for flags accesses |
188 | * @drv_unblock_wk: used for driver PS unblocking | 187 | * @drv_unblock_wk: used for driver PS unblocking |
189 | * @listen_interval: listen interval of this station, when we're acting as AP | 188 | * @listen_interval: listen interval of this station, when we're acting as AP |
190 | * @pin_status: used internally for pinning a STA struct into memory | ||
191 | * @flags: STA flags, see &enum ieee80211_sta_info_flags | 189 | * @flags: STA flags, see &enum ieee80211_sta_info_flags |
192 | * @ps_tx_buf: buffer of frames to transmit to this station | 190 | * @ps_tx_buf: buffer of frames to transmit to this station |
193 | * when it leaves power saving state | 191 | * when it leaves power saving state |
@@ -226,6 +224,7 @@ struct sta_ampdu_mlme { | |||
226 | * @debugfs: debug filesystem info | 224 | * @debugfs: debug filesystem info |
227 | * @sta: station information we share with the driver | 225 | * @sta: station information we share with the driver |
228 | * @dead: set to true when sta is unlinked | 226 | * @dead: set to true when sta is unlinked |
227 | * @uploaded: set to true when sta is uploaded to the driver | ||
229 | */ | 228 | */ |
230 | struct sta_info { | 229 | struct sta_info { |
231 | /* General information, mostly static */ | 230 | /* General information, mostly static */ |
@@ -245,11 +244,7 @@ struct sta_info { | |||
245 | 244 | ||
246 | bool dead; | 245 | bool dead; |
247 | 246 | ||
248 | /* | 247 | bool uploaded; |
249 | * for use by the internal lifetime management, | ||
250 | * see __sta_info_unlink | ||
251 | */ | ||
252 | u8 pin_status; | ||
253 | 248 | ||
254 | /* | 249 | /* |
255 | * frequently updated, locked with own spinlock (flaglock), | 250 | * frequently updated, locked with own spinlock (flaglock), |
@@ -449,18 +444,19 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, | |||
449 | * Insert STA info into hash table/list, returns zero or a | 444 | * Insert STA info into hash table/list, returns zero or a |
450 | * -EEXIST if (if the same MAC address is already present). | 445 | * -EEXIST if (if the same MAC address is already present). |
451 | * | 446 | * |
452 | * Calling this without RCU protection makes the caller | 447 | * Calling the non-rcu version makes the caller relinquish, |
453 | * relinquish its reference to @sta. | 448 | * the _rcu version calls read_lock_rcu() and must be called |
449 | * without it held. | ||
454 | */ | 450 | */ |
455 | int sta_info_insert(struct sta_info *sta); | 451 | int sta_info_insert(struct sta_info *sta); |
456 | /* | 452 | int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU); |
457 | * Unlink a STA info from the hash table/list. | 453 | int sta_info_insert_atomic(struct sta_info *sta); |
458 | * This can NULL the STA pointer if somebody else | 454 | |
459 | * has already unlinked it. | 455 | int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, |
460 | */ | 456 | const u8 *addr); |
461 | void sta_info_unlink(struct sta_info **sta); | 457 | int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata, |
458 | const u8 *addr); | ||
462 | 459 | ||
463 | void sta_info_destroy(struct sta_info *sta); | ||
464 | void sta_info_set_tim_bit(struct sta_info *sta); | 460 | void sta_info_set_tim_bit(struct sta_info *sta); |
465 | void sta_info_clear_tim_bit(struct sta_info *sta); | 461 | void sta_info_clear_tim_bit(struct sta_info *sta); |
466 | 462 | ||
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index e57ad6b1d7ea..ded98730c111 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -188,6 +188,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
188 | rcu_read_lock(); | 188 | rcu_read_lock(); |
189 | 189 | ||
190 | sband = local->hw.wiphy->bands[info->band]; | 190 | sband = local->hw.wiphy->bands[info->band]; |
191 | fc = hdr->frame_control; | ||
191 | 192 | ||
192 | for_each_sta_info(local, hdr->addr1, sta, tmp) { | 193 | for_each_sta_info(local, hdr->addr1, sta, tmp) { |
193 | /* skip wrong virtual interface */ | 194 | /* skip wrong virtual interface */ |
@@ -205,8 +206,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
205 | return; | 206 | return; |
206 | } | 207 | } |
207 | 208 | ||
208 | fc = hdr->frame_control; | ||
209 | |||
210 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && | 209 | if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) && |
211 | (ieee80211_is_data_qos(fc))) { | 210 | (ieee80211_is_data_qos(fc))) { |
212 | u16 tid, ssn; | 211 | u16 tid, ssn; |
@@ -275,6 +274,20 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
275 | local->dot11FailedCount++; | 274 | local->dot11FailedCount++; |
276 | } | 275 | } |
277 | 276 | ||
277 | if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc) && | ||
278 | (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && | ||
279 | !(info->flags & IEEE80211_TX_CTL_INJECTED) && | ||
280 | local->ps_sdata && !(local->scanning)) { | ||
281 | if (info->flags & IEEE80211_TX_STAT_ACK) { | ||
282 | local->ps_sdata->u.mgd.flags |= | ||
283 | IEEE80211_STA_NULLFUNC_ACKED; | ||
284 | ieee80211_queue_work(&local->hw, | ||
285 | &local->dynamic_ps_enable_work); | ||
286 | } else | ||
287 | mod_timer(&local->dynamic_ps_timer, jiffies + | ||
288 | msecs_to_jiffies(10)); | ||
289 | } | ||
290 | |||
278 | /* this was a transmitted frame, but now we want to reuse it */ | 291 | /* this was a transmitted frame, but now we want to reuse it */ |
279 | skb_orphan(skb); | 292 | skb_orphan(skb); |
280 | 293 | ||
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 85e382aa894e..cbe53ed4fb0b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -571,7 +571,7 @@ ieee80211_tx_h_sta(struct ieee80211_tx_data *tx) | |||
571 | { | 571 | { |
572 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 572 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
573 | 573 | ||
574 | if (tx->sta) | 574 | if (tx->sta && tx->sta->uploaded) |
575 | info->control.sta = &tx->sta->sta; | 575 | info->control.sta = &tx->sta->sta; |
576 | 576 | ||
577 | return TX_CONTINUE; | 577 | return TX_CONTINUE; |
@@ -1010,7 +1010,8 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1010 | (struct ieee80211_radiotap_header *) skb->data; | 1010 | (struct ieee80211_radiotap_header *) skb->data; |
1011 | struct ieee80211_supported_band *sband; | 1011 | struct ieee80211_supported_band *sband; |
1012 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1012 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1013 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); | 1013 | int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, |
1014 | NULL); | ||
1014 | 1015 | ||
1015 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; | 1016 | sband = tx->local->hw.wiphy->bands[tx->channel->band]; |
1016 | 1017 | ||
@@ -1046,7 +1047,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1046 | * because it will be recomputed and added | 1047 | * because it will be recomputed and added |
1047 | * on transmission | 1048 | * on transmission |
1048 | */ | 1049 | */ |
1049 | if (skb->len < (iterator.max_length + FCS_LEN)) | 1050 | if (skb->len < (iterator._max_length + FCS_LEN)) |
1050 | return false; | 1051 | return false; |
1051 | 1052 | ||
1052 | skb_trim(skb, skb->len - FCS_LEN); | 1053 | skb_trim(skb, skb->len - FCS_LEN); |
@@ -1073,10 +1074,10 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, | |||
1073 | 1074 | ||
1074 | /* | 1075 | /* |
1075 | * remove the radiotap header | 1076 | * remove the radiotap header |
1076 | * iterator->max_length was sanity-checked against | 1077 | * iterator->_max_length was sanity-checked against |
1077 | * skb->len by iterator init | 1078 | * skb->len by iterator init |
1078 | */ | 1079 | */ |
1079 | skb_pull(skb, iterator.max_length); | 1080 | skb_pull(skb, iterator._max_length); |
1080 | 1081 | ||
1081 | return true; | 1082 | return true; |
1082 | } | 1083 | } |
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index ca170b417da6..c453226f06b2 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -1082,7 +1082,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1082 | struct ieee80211_hw *hw = &local->hw; | 1082 | struct ieee80211_hw *hw = &local->hw; |
1083 | struct ieee80211_sub_if_data *sdata; | 1083 | struct ieee80211_sub_if_data *sdata; |
1084 | struct sta_info *sta; | 1084 | struct sta_info *sta; |
1085 | unsigned long flags; | ||
1086 | int res; | 1085 | int res; |
1087 | 1086 | ||
1088 | if (local->suspended) | 1087 | if (local->suspended) |
@@ -1116,20 +1115,19 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1116 | } | 1115 | } |
1117 | 1116 | ||
1118 | /* add STAs back */ | 1117 | /* add STAs back */ |
1119 | if (local->ops->sta_notify) { | 1118 | mutex_lock(&local->sta_mtx); |
1120 | spin_lock_irqsave(&local->sta_lock, flags); | 1119 | list_for_each_entry(sta, &local->sta_list, list) { |
1121 | list_for_each_entry(sta, &local->sta_list, list) { | 1120 | if (sta->uploaded) { |
1122 | sdata = sta->sdata; | 1121 | sdata = sta->sdata; |
1123 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 1122 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
1124 | sdata = container_of(sdata->bss, | 1123 | sdata = container_of(sdata->bss, |
1125 | struct ieee80211_sub_if_data, | 1124 | struct ieee80211_sub_if_data, |
1126 | u.ap); | 1125 | u.ap); |
1127 | 1126 | ||
1128 | drv_sta_notify(local, sdata, STA_NOTIFY_ADD, | 1127 | WARN_ON(drv_sta_add(local, sdata, &sta->sta)); |
1129 | &sta->sta); | ||
1130 | } | 1128 | } |
1131 | spin_unlock_irqrestore(&local->sta_lock, flags); | ||
1132 | } | 1129 | } |
1130 | mutex_unlock(&local->sta_mtx); | ||
1133 | 1131 | ||
1134 | /* Clear Suspend state so that ADDBA requests can be processed */ | 1132 | /* Clear Suspend state so that ADDBA requests can be processed */ |
1135 | 1133 | ||
@@ -1180,6 +1178,14 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1180 | } | 1178 | } |
1181 | } | 1179 | } |
1182 | 1180 | ||
1181 | rcu_read_lock(); | ||
1182 | if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { | ||
1183 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
1184 | ieee80211_sta_tear_down_BA_sessions(sta); | ||
1185 | } | ||
1186 | } | ||
1187 | rcu_read_unlock(); | ||
1188 | |||
1183 | /* add back keys */ | 1189 | /* add back keys */ |
1184 | list_for_each_entry(sdata, &local->interfaces, list) | 1190 | list_for_each_entry(sdata, &local->interfaces, list) |
1185 | if (ieee80211_sdata_running(sdata)) | 1191 | if (ieee80211_sdata_running(sdata)) |
@@ -1219,10 +1225,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) | |||
1219 | 1225 | ||
1220 | add_timer(&local->sta_cleanup); | 1226 | add_timer(&local->sta_cleanup); |
1221 | 1227 | ||
1222 | spin_lock_irqsave(&local->sta_lock, flags); | 1228 | mutex_lock(&local->sta_mtx); |
1223 | list_for_each_entry(sta, &local->sta_list, list) | 1229 | list_for_each_entry(sta, &local->sta_list, list) |
1224 | mesh_plink_restart(sta); | 1230 | mesh_plink_restart(sta); |
1225 | spin_unlock_irqrestore(&local->sta_lock, flags); | 1231 | mutex_unlock(&local->sta_mtx); |
1226 | #else | 1232 | #else |
1227 | WARN_ON(1); | 1233 | WARN_ON(1); |
1228 | #endif | 1234 | #endif |
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 71604c6613b5..a249127020a5 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c | |||
@@ -1267,28 +1267,13 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1267 | 1267 | ||
1268 | static void *nr_info_start(struct seq_file *seq, loff_t *pos) | 1268 | static void *nr_info_start(struct seq_file *seq, loff_t *pos) |
1269 | { | 1269 | { |
1270 | struct sock *s; | ||
1271 | struct hlist_node *node; | ||
1272 | int i = 1; | ||
1273 | |||
1274 | spin_lock_bh(&nr_list_lock); | 1270 | spin_lock_bh(&nr_list_lock); |
1275 | if (*pos == 0) | 1271 | return seq_hlist_start_head(&nr_list, *pos); |
1276 | return SEQ_START_TOKEN; | ||
1277 | |||
1278 | sk_for_each(s, node, &nr_list) { | ||
1279 | if (i == *pos) | ||
1280 | return s; | ||
1281 | ++i; | ||
1282 | } | ||
1283 | return NULL; | ||
1284 | } | 1272 | } |
1285 | 1273 | ||
1286 | static void *nr_info_next(struct seq_file *seq, void *v, loff_t *pos) | 1274 | static void *nr_info_next(struct seq_file *seq, void *v, loff_t *pos) |
1287 | { | 1275 | { |
1288 | ++*pos; | 1276 | return seq_hlist_next(v, &nr_list, pos); |
1289 | |||
1290 | return (v == SEQ_START_TOKEN) ? sk_head(&nr_list) | ||
1291 | : sk_next((struct sock *)v); | ||
1292 | } | 1277 | } |
1293 | 1278 | ||
1294 | static void nr_info_stop(struct seq_file *seq, void *v) | 1279 | static void nr_info_stop(struct seq_file *seq, void *v) |
@@ -1298,7 +1283,7 @@ static void nr_info_stop(struct seq_file *seq, void *v) | |||
1298 | 1283 | ||
1299 | static int nr_info_show(struct seq_file *seq, void *v) | 1284 | static int nr_info_show(struct seq_file *seq, void *v) |
1300 | { | 1285 | { |
1301 | struct sock *s = v; | 1286 | struct sock *s = sk_entry(v); |
1302 | struct net_device *dev; | 1287 | struct net_device *dev; |
1303 | struct nr_sock *nr; | 1288 | struct nr_sock *nr; |
1304 | const char *devname; | 1289 | const char *devname; |
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c index e2e2d33cafdf..5cc648012f50 100644 --- a/net/netrom/nr_route.c +++ b/net/netrom/nr_route.c | |||
@@ -863,33 +863,13 @@ int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25) | |||
863 | 863 | ||
864 | static void *nr_node_start(struct seq_file *seq, loff_t *pos) | 864 | static void *nr_node_start(struct seq_file *seq, loff_t *pos) |
865 | { | 865 | { |
866 | struct nr_node *nr_node; | ||
867 | struct hlist_node *node; | ||
868 | int i = 1; | ||
869 | |||
870 | spin_lock_bh(&nr_node_list_lock); | 866 | spin_lock_bh(&nr_node_list_lock); |
871 | if (*pos == 0) | 867 | return seq_hlist_start_head(&nr_node_list, *pos); |
872 | return SEQ_START_TOKEN; | ||
873 | |||
874 | nr_node_for_each(nr_node, node, &nr_node_list) { | ||
875 | if (i == *pos) | ||
876 | return nr_node; | ||
877 | ++i; | ||
878 | } | ||
879 | |||
880 | return NULL; | ||
881 | } | 868 | } |
882 | 869 | ||
883 | static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos) | 870 | static void *nr_node_next(struct seq_file *seq, void *v, loff_t *pos) |
884 | { | 871 | { |
885 | struct hlist_node *node; | 872 | return seq_hlist_next(v, &nr_node_list, pos); |
886 | ++*pos; | ||
887 | |||
888 | node = (v == SEQ_START_TOKEN) | ||
889 | ? nr_node_list.first | ||
890 | : ((struct nr_node *)v)->node_node.next; | ||
891 | |||
892 | return hlist_entry(node, struct nr_node, node_node); | ||
893 | } | 873 | } |
894 | 874 | ||
895 | static void nr_node_stop(struct seq_file *seq, void *v) | 875 | static void nr_node_stop(struct seq_file *seq, void *v) |
@@ -906,7 +886,9 @@ static int nr_node_show(struct seq_file *seq, void *v) | |||
906 | seq_puts(seq, | 886 | seq_puts(seq, |
907 | "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n"); | 887 | "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n"); |
908 | else { | 888 | else { |
909 | struct nr_node *nr_node = v; | 889 | struct nr_node *nr_node = hlist_entry(v, struct nr_node, |
890 | node_node); | ||
891 | |||
910 | nr_node_lock(nr_node); | 892 | nr_node_lock(nr_node); |
911 | seq_printf(seq, "%-9s %-7s %d %d", | 893 | seq_printf(seq, "%-9s %-7s %d %d", |
912 | ax2asc(buf, &nr_node->callsign), | 894 | ax2asc(buf, &nr_node->callsign), |
@@ -949,31 +931,13 @@ const struct file_operations nr_nodes_fops = { | |||
949 | 931 | ||
950 | static void *nr_neigh_start(struct seq_file *seq, loff_t *pos) | 932 | static void *nr_neigh_start(struct seq_file *seq, loff_t *pos) |
951 | { | 933 | { |
952 | struct nr_neigh *nr_neigh; | ||
953 | struct hlist_node *node; | ||
954 | int i = 1; | ||
955 | |||
956 | spin_lock_bh(&nr_neigh_list_lock); | 934 | spin_lock_bh(&nr_neigh_list_lock); |
957 | if (*pos == 0) | 935 | return seq_hlist_start_head(&nr_neigh_list, *pos); |
958 | return SEQ_START_TOKEN; | ||
959 | |||
960 | nr_neigh_for_each(nr_neigh, node, &nr_neigh_list) { | ||
961 | if (i == *pos) | ||
962 | return nr_neigh; | ||
963 | } | ||
964 | return NULL; | ||
965 | } | 936 | } |
966 | 937 | ||
967 | static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos) | 938 | static void *nr_neigh_next(struct seq_file *seq, void *v, loff_t *pos) |
968 | { | 939 | { |
969 | struct hlist_node *node; | 940 | return seq_hlist_next(v, &nr_neigh_list, pos); |
970 | ++*pos; | ||
971 | |||
972 | node = (v == SEQ_START_TOKEN) | ||
973 | ? nr_neigh_list.first | ||
974 | : ((struct nr_neigh *)v)->neigh_node.next; | ||
975 | |||
976 | return hlist_entry(node, struct nr_neigh, neigh_node); | ||
977 | } | 941 | } |
978 | 942 | ||
979 | static void nr_neigh_stop(struct seq_file *seq, void *v) | 943 | static void nr_neigh_stop(struct seq_file *seq, void *v) |
@@ -989,8 +953,9 @@ static int nr_neigh_show(struct seq_file *seq, void *v) | |||
989 | if (v == SEQ_START_TOKEN) | 953 | if (v == SEQ_START_TOKEN) |
990 | seq_puts(seq, "addr callsign dev qual lock count failed digipeaters\n"); | 954 | seq_puts(seq, "addr callsign dev qual lock count failed digipeaters\n"); |
991 | else { | 955 | else { |
992 | struct nr_neigh *nr_neigh = v; | 956 | struct nr_neigh *nr_neigh; |
993 | 957 | ||
958 | nr_neigh = hlist_entry(v, struct nr_neigh, neigh_node); | ||
994 | seq_printf(seq, "%05d %-9s %-4s %3d %d %3d %3d", | 959 | seq_printf(seq, "%05d %-9s %-4s %3d %d %3d %3d", |
995 | nr_neigh->number, | 960 | nr_neigh->number, |
996 | ax2asc(buf, &nr_neigh->callsign), | 961 | ax2asc(buf, &nr_neigh->callsign), |
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6ecb426bc0cf..10f7295bcefb 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -2510,33 +2510,19 @@ static struct notifier_block packet_netdev_notifier = { | |||
2510 | }; | 2510 | }; |
2511 | 2511 | ||
2512 | #ifdef CONFIG_PROC_FS | 2512 | #ifdef CONFIG_PROC_FS |
2513 | static inline struct sock *packet_seq_idx(struct net *net, loff_t off) | ||
2514 | { | ||
2515 | struct sock *s; | ||
2516 | struct hlist_node *node; | ||
2517 | |||
2518 | sk_for_each(s, node, &net->packet.sklist) { | ||
2519 | if (!off--) | ||
2520 | return s; | ||
2521 | } | ||
2522 | return NULL; | ||
2523 | } | ||
2524 | 2513 | ||
2525 | static void *packet_seq_start(struct seq_file *seq, loff_t *pos) | 2514 | static void *packet_seq_start(struct seq_file *seq, loff_t *pos) |
2526 | __acquires(seq_file_net(seq)->packet.sklist_lock) | 2515 | __acquires(seq_file_net(seq)->packet.sklist_lock) |
2527 | { | 2516 | { |
2528 | struct net *net = seq_file_net(seq); | 2517 | struct net *net = seq_file_net(seq); |
2529 | read_lock(&net->packet.sklist_lock); | 2518 | read_lock(&net->packet.sklist_lock); |
2530 | return *pos ? packet_seq_idx(net, *pos - 1) : SEQ_START_TOKEN; | 2519 | return seq_hlist_start_head(&net->packet.sklist, *pos); |
2531 | } | 2520 | } |
2532 | 2521 | ||
2533 | static void *packet_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 2522 | static void *packet_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
2534 | { | 2523 | { |
2535 | struct net *net = seq_file_net(seq); | 2524 | struct net *net = seq_file_net(seq); |
2536 | ++*pos; | 2525 | return seq_hlist_next(v, &net->packet.sklist, pos); |
2537 | return (v == SEQ_START_TOKEN) | ||
2538 | ? sk_head(&net->packet.sklist) | ||
2539 | : sk_next((struct sock *)v) ; | ||
2540 | } | 2526 | } |
2541 | 2527 | ||
2542 | static void packet_seq_stop(struct seq_file *seq, void *v) | 2528 | static void packet_seq_stop(struct seq_file *seq, void *v) |
@@ -2551,7 +2537,7 @@ static int packet_seq_show(struct seq_file *seq, void *v) | |||
2551 | if (v == SEQ_START_TOKEN) | 2537 | if (v == SEQ_START_TOKEN) |
2552 | seq_puts(seq, "sk RefCnt Type Proto Iface R Rmem User Inode\n"); | 2538 | seq_puts(seq, "sk RefCnt Type Proto Iface R Rmem User Inode\n"); |
2553 | else { | 2539 | else { |
2554 | struct sock *s = v; | 2540 | struct sock *s = sk_entry(v); |
2555 | const struct packet_sock *po = pkt_sk(s); | 2541 | const struct packet_sock *po = pkt_sk(s); |
2556 | 2542 | ||
2557 | seq_printf(seq, | 2543 | seq_printf(seq, |
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 8feb9e5d6623..e90b9b6c16ae 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c | |||
@@ -1404,29 +1404,13 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) | |||
1404 | static void *rose_info_start(struct seq_file *seq, loff_t *pos) | 1404 | static void *rose_info_start(struct seq_file *seq, loff_t *pos) |
1405 | __acquires(rose_list_lock) | 1405 | __acquires(rose_list_lock) |
1406 | { | 1406 | { |
1407 | int i; | ||
1408 | struct sock *s; | ||
1409 | struct hlist_node *node; | ||
1410 | |||
1411 | spin_lock_bh(&rose_list_lock); | 1407 | spin_lock_bh(&rose_list_lock); |
1412 | if (*pos == 0) | 1408 | return seq_hlist_start_head(&rose_list, *pos); |
1413 | return SEQ_START_TOKEN; | ||
1414 | |||
1415 | i = 1; | ||
1416 | sk_for_each(s, node, &rose_list) { | ||
1417 | if (i == *pos) | ||
1418 | return s; | ||
1419 | ++i; | ||
1420 | } | ||
1421 | return NULL; | ||
1422 | } | 1409 | } |
1423 | 1410 | ||
1424 | static void *rose_info_next(struct seq_file *seq, void *v, loff_t *pos) | 1411 | static void *rose_info_next(struct seq_file *seq, void *v, loff_t *pos) |
1425 | { | 1412 | { |
1426 | ++*pos; | 1413 | return seq_hlist_next(v, &rose_list, pos); |
1427 | |||
1428 | return (v == SEQ_START_TOKEN) ? sk_head(&rose_list) | ||
1429 | : sk_next((struct sock *)v); | ||
1430 | } | 1414 | } |
1431 | 1415 | ||
1432 | static void rose_info_stop(struct seq_file *seq, void *v) | 1416 | static void rose_info_stop(struct seq_file *seq, void *v) |
@@ -1444,7 +1428,7 @@ static int rose_info_show(struct seq_file *seq, void *v) | |||
1444 | "dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n"); | 1428 | "dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n"); |
1445 | 1429 | ||
1446 | else { | 1430 | else { |
1447 | struct sock *s = v; | 1431 | struct sock *s = sk_entry(v); |
1448 | struct rose_sock *rose = rose_sk(s); | 1432 | struct rose_sock *rose = rose_sk(s); |
1449 | const char *devname, *callsign; | 1433 | const char *devname, *callsign; |
1450 | const struct net_device *dev = rose->device; | 1434 | const struct net_device *dev = rose->device; |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 49278f830367..9ea45383480e 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -78,7 +78,7 @@ rpc_timeout_upcall_queue(struct work_struct *work) | |||
78 | } | 78 | } |
79 | 79 | ||
80 | /** | 80 | /** |
81 | * rpc_queue_upcall | 81 | * rpc_queue_upcall - queue an upcall message to userspace |
82 | * @inode: inode of upcall pipe on which to queue given message | 82 | * @inode: inode of upcall pipe on which to queue given message |
83 | * @msg: message to queue | 83 | * @msg: message to queue |
84 | * | 84 | * |
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c index f591871a7b4f..1332c445d1c7 100644 --- a/net/wireless/radiotap.c +++ b/net/wireless/radiotap.c | |||
@@ -2,6 +2,16 @@ | |||
2 | * Radiotap parser | 2 | * Radiotap parser |
3 | * | 3 | * |
4 | * Copyright 2007 Andy Green <andy@warmcat.com> | 4 | * Copyright 2007 Andy Green <andy@warmcat.com> |
5 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * Alternatively, this software may be distributed under the terms of BSD | ||
12 | * license. | ||
13 | * | ||
14 | * See COPYING for more details. | ||
5 | */ | 15 | */ |
6 | 16 | ||
7 | #include <net/cfg80211.h> | 17 | #include <net/cfg80211.h> |
@@ -10,6 +20,35 @@ | |||
10 | 20 | ||
11 | /* function prototypes and related defs are in include/net/cfg80211.h */ | 21 | /* function prototypes and related defs are in include/net/cfg80211.h */ |
12 | 22 | ||
23 | static const struct radiotap_align_size rtap_namespace_sizes[] = { | ||
24 | [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, }, | ||
25 | [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, }, | ||
26 | [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, }, | ||
27 | [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, }, | ||
28 | [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, }, | ||
29 | [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, }, | ||
30 | [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, }, | ||
31 | [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, }, | ||
32 | [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, }, | ||
33 | [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, }, | ||
34 | [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, }, | ||
35 | [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, }, | ||
36 | [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, }, | ||
37 | [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, }, | ||
38 | [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, }, | ||
39 | [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, }, | ||
40 | [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, }, | ||
41 | [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, | ||
42 | /* | ||
43 | * add more here as they are defined in radiotap.h | ||
44 | */ | ||
45 | }; | ||
46 | |||
47 | static const struct ieee80211_radiotap_namespace radiotap_ns = { | ||
48 | .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), | ||
49 | .align_size = rtap_namespace_sizes, | ||
50 | }; | ||
51 | |||
13 | /** | 52 | /** |
14 | * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization | 53 | * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization |
15 | * @iterator: radiotap_iterator to initialize | 54 | * @iterator: radiotap_iterator to initialize |
@@ -50,9 +89,9 @@ | |||
50 | */ | 89 | */ |
51 | 90 | ||
52 | int ieee80211_radiotap_iterator_init( | 91 | int ieee80211_radiotap_iterator_init( |
53 | struct ieee80211_radiotap_iterator *iterator, | 92 | struct ieee80211_radiotap_iterator *iterator, |
54 | struct ieee80211_radiotap_header *radiotap_header, | 93 | struct ieee80211_radiotap_header *radiotap_header, |
55 | int max_length) | 94 | int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns) |
56 | { | 95 | { |
57 | /* Linux only supports version 0 radiotap format */ | 96 | /* Linux only supports version 0 radiotap format */ |
58 | if (radiotap_header->it_version) | 97 | if (radiotap_header->it_version) |
@@ -62,19 +101,24 @@ int ieee80211_radiotap_iterator_init( | |||
62 | if (max_length < get_unaligned_le16(&radiotap_header->it_len)) | 101 | if (max_length < get_unaligned_le16(&radiotap_header->it_len)) |
63 | return -EINVAL; | 102 | return -EINVAL; |
64 | 103 | ||
65 | iterator->rtheader = radiotap_header; | 104 | iterator->_rtheader = radiotap_header; |
66 | iterator->max_length = get_unaligned_le16(&radiotap_header->it_len); | 105 | iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len); |
67 | iterator->arg_index = 0; | 106 | iterator->_arg_index = 0; |
68 | iterator->bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); | 107 | iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present); |
69 | iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); | 108 | iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header); |
70 | iterator->this_arg = NULL; | 109 | iterator->_reset_on_ext = 0; |
110 | iterator->_next_bitmap = &radiotap_header->it_present; | ||
111 | iterator->_next_bitmap++; | ||
112 | iterator->_vns = vns; | ||
113 | iterator->current_namespace = &radiotap_ns; | ||
114 | iterator->is_radiotap_ns = 1; | ||
71 | 115 | ||
72 | /* find payload start allowing for extended bitmap(s) */ | 116 | /* find payload start allowing for extended bitmap(s) */ |
73 | 117 | ||
74 | if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) { | 118 | if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) { |
75 | while (get_unaligned_le32(iterator->arg) & | 119 | while (get_unaligned_le32(iterator->_arg) & |
76 | (1 << IEEE80211_RADIOTAP_EXT)) { | 120 | (1 << IEEE80211_RADIOTAP_EXT)) { |
77 | iterator->arg += sizeof(u32); | 121 | iterator->_arg += sizeof(uint32_t); |
78 | 122 | ||
79 | /* | 123 | /* |
80 | * check for insanity where the present bitmaps | 124 | * check for insanity where the present bitmaps |
@@ -82,12 +126,13 @@ int ieee80211_radiotap_iterator_init( | |||
82 | * stated radiotap header length | 126 | * stated radiotap header length |
83 | */ | 127 | */ |
84 | 128 | ||
85 | if (((ulong)iterator->arg - | 129 | if ((unsigned long)iterator->_arg - |
86 | (ulong)iterator->rtheader) > iterator->max_length) | 130 | (unsigned long)iterator->_rtheader > |
131 | (unsigned long)iterator->_max_length) | ||
87 | return -EINVAL; | 132 | return -EINVAL; |
88 | } | 133 | } |
89 | 134 | ||
90 | iterator->arg += sizeof(u32); | 135 | iterator->_arg += sizeof(uint32_t); |
91 | 136 | ||
92 | /* | 137 | /* |
93 | * no need to check again for blowing past stated radiotap | 138 | * no need to check again for blowing past stated radiotap |
@@ -96,12 +141,36 @@ int ieee80211_radiotap_iterator_init( | |||
96 | */ | 141 | */ |
97 | } | 142 | } |
98 | 143 | ||
144 | iterator->this_arg = iterator->_arg; | ||
145 | |||
99 | /* we are all initialized happily */ | 146 | /* we are all initialized happily */ |
100 | 147 | ||
101 | return 0; | 148 | return 0; |
102 | } | 149 | } |
103 | EXPORT_SYMBOL(ieee80211_radiotap_iterator_init); | 150 | EXPORT_SYMBOL(ieee80211_radiotap_iterator_init); |
104 | 151 | ||
152 | static void find_ns(struct ieee80211_radiotap_iterator *iterator, | ||
153 | uint32_t oui, uint8_t subns) | ||
154 | { | ||
155 | int i; | ||
156 | |||
157 | iterator->current_namespace = NULL; | ||
158 | |||
159 | if (!iterator->_vns) | ||
160 | return; | ||
161 | |||
162 | for (i = 0; i < iterator->_vns->n_ns; i++) { | ||
163 | if (iterator->_vns->ns[i].oui != oui) | ||
164 | continue; | ||
165 | if (iterator->_vns->ns[i].subns != subns) | ||
166 | continue; | ||
167 | |||
168 | iterator->current_namespace = &iterator->_vns->ns[i]; | ||
169 | break; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | |||
105 | 174 | ||
106 | /** | 175 | /** |
107 | * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg | 176 | * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg |
@@ -127,99 +196,80 @@ EXPORT_SYMBOL(ieee80211_radiotap_iterator_init); | |||
127 | */ | 196 | */ |
128 | 197 | ||
129 | int ieee80211_radiotap_iterator_next( | 198 | int ieee80211_radiotap_iterator_next( |
130 | struct ieee80211_radiotap_iterator *iterator) | 199 | struct ieee80211_radiotap_iterator *iterator) |
131 | { | 200 | { |
132 | 201 | while (1) { | |
133 | /* | ||
134 | * small length lookup table for all radiotap types we heard of | ||
135 | * starting from b0 in the bitmap, so we can walk the payload | ||
136 | * area of the radiotap header | ||
137 | * | ||
138 | * There is a requirement to pad args, so that args | ||
139 | * of a given length must begin at a boundary of that length | ||
140 | * -- but note that compound args are allowed (eg, 2 x u16 | ||
141 | * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not | ||
142 | * a reliable indicator of alignment requirement. | ||
143 | * | ||
144 | * upper nybble: content alignment for arg | ||
145 | * lower nybble: content length for arg | ||
146 | */ | ||
147 | |||
148 | static const u8 rt_sizes[] = { | ||
149 | [IEEE80211_RADIOTAP_TSFT] = 0x88, | ||
150 | [IEEE80211_RADIOTAP_FLAGS] = 0x11, | ||
151 | [IEEE80211_RADIOTAP_RATE] = 0x11, | ||
152 | [IEEE80211_RADIOTAP_CHANNEL] = 0x24, | ||
153 | [IEEE80211_RADIOTAP_FHSS] = 0x22, | ||
154 | [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, | ||
155 | [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, | ||
156 | [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, | ||
157 | [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, | ||
158 | [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, | ||
159 | [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, | ||
160 | [IEEE80211_RADIOTAP_ANTENNA] = 0x11, | ||
161 | [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, | ||
162 | [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11, | ||
163 | [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22, | ||
164 | [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22, | ||
165 | [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11, | ||
166 | [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11, | ||
167 | /* | ||
168 | * add more here as they are defined in | ||
169 | * include/net/ieee80211_radiotap.h | ||
170 | */ | ||
171 | }; | ||
172 | |||
173 | /* | ||
174 | * for every radiotap entry we can at | ||
175 | * least skip (by knowing the length)... | ||
176 | */ | ||
177 | |||
178 | while (iterator->arg_index < sizeof(rt_sizes)) { | ||
179 | int hit = 0; | 202 | int hit = 0; |
180 | int pad; | 203 | int pad, align, size, subns, vnslen; |
204 | uint32_t oui; | ||
181 | 205 | ||
182 | if (!(iterator->bitmap_shifter & 1)) | 206 | /* if no more EXT bits, that's it */ |
207 | if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && | ||
208 | !(iterator->_bitmap_shifter & 1)) | ||
209 | return -ENOENT; | ||
210 | |||
211 | if (!(iterator->_bitmap_shifter & 1)) | ||
183 | goto next_entry; /* arg not present */ | 212 | goto next_entry; /* arg not present */ |
184 | 213 | ||
214 | /* get alignment/size of data */ | ||
215 | switch (iterator->_arg_index % 32) { | ||
216 | case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: | ||
217 | case IEEE80211_RADIOTAP_EXT: | ||
218 | align = 1; | ||
219 | size = 0; | ||
220 | break; | ||
221 | case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: | ||
222 | align = 2; | ||
223 | size = 6; | ||
224 | break; | ||
225 | default: | ||
226 | if (!iterator->current_namespace || | ||
227 | iterator->_arg_index >= iterator->current_namespace->n_bits) { | ||
228 | if (iterator->current_namespace == &radiotap_ns) | ||
229 | return -ENOENT; | ||
230 | align = 0; | ||
231 | } else { | ||
232 | align = iterator->current_namespace->align_size[iterator->_arg_index].align; | ||
233 | size = iterator->current_namespace->align_size[iterator->_arg_index].size; | ||
234 | } | ||
235 | if (!align) { | ||
236 | /* skip all subsequent data */ | ||
237 | iterator->_arg = iterator->_next_ns_data; | ||
238 | /* give up on this namespace */ | ||
239 | iterator->current_namespace = NULL; | ||
240 | goto next_entry; | ||
241 | } | ||
242 | break; | ||
243 | } | ||
244 | |||
185 | /* | 245 | /* |
186 | * arg is present, account for alignment padding | 246 | * arg is present, account for alignment padding |
187 | * 8-bit args can be at any alignment | ||
188 | * 16-bit args must start on 16-bit boundary | ||
189 | * 32-bit args must start on 32-bit boundary | ||
190 | * 64-bit args must start on 64-bit boundary | ||
191 | * | 247 | * |
192 | * note that total arg size can differ from alignment of | 248 | * Note that these alignments are relative to the start |
193 | * elements inside arg, so we use upper nybble of length | 249 | * of the radiotap header. There is no guarantee |
194 | * table to base alignment on | ||
195 | * | ||
196 | * also note: these alignments are ** relative to the | ||
197 | * start of the radiotap header **. There is no guarantee | ||
198 | * that the radiotap header itself is aligned on any | 250 | * that the radiotap header itself is aligned on any |
199 | * kind of boundary. | 251 | * kind of boundary. |
200 | * | 252 | * |
201 | * the above is why get_unaligned() is used to dereference | 253 | * The above is why get_unaligned() is used to dereference |
202 | * multibyte elements from the radiotap area | 254 | * multibyte elements from the radiotap area. |
203 | */ | 255 | */ |
204 | 256 | ||
205 | pad = (((ulong)iterator->arg) - | 257 | pad = ((unsigned long)iterator->_arg - |
206 | ((ulong)iterator->rtheader)) & | 258 | (unsigned long)iterator->_rtheader) & (align - 1); |
207 | ((rt_sizes[iterator->arg_index] >> 4) - 1); | ||
208 | 259 | ||
209 | if (pad) | 260 | if (pad) |
210 | iterator->arg += | 261 | iterator->_arg += align - pad; |
211 | (rt_sizes[iterator->arg_index] >> 4) - pad; | ||
212 | 262 | ||
213 | /* | 263 | /* |
214 | * this is what we will return to user, but we need to | 264 | * this is what we will return to user, but we need to |
215 | * move on first so next call has something fresh to test | 265 | * move on first so next call has something fresh to test |
216 | */ | 266 | */ |
217 | iterator->this_arg_index = iterator->arg_index; | 267 | iterator->this_arg_index = iterator->_arg_index; |
218 | iterator->this_arg = iterator->arg; | 268 | iterator->this_arg = iterator->_arg; |
219 | hit = 1; | 269 | iterator->this_arg_size = size; |
220 | 270 | ||
221 | /* internally move on the size of this arg */ | 271 | /* internally move on the size of this arg */ |
222 | iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; | 272 | iterator->_arg += size; |
223 | 273 | ||
224 | /* | 274 | /* |
225 | * check for insanity where we are given a bitmap that | 275 | * check for insanity where we are given a bitmap that |
@@ -228,32 +278,73 @@ int ieee80211_radiotap_iterator_next( | |||
228 | * max_length on the last arg, never exceeding it. | 278 | * max_length on the last arg, never exceeding it. |
229 | */ | 279 | */ |
230 | 280 | ||
231 | if (((ulong)iterator->arg - (ulong)iterator->rtheader) > | 281 | if ((unsigned long)iterator->_arg - |
232 | iterator->max_length) | 282 | (unsigned long)iterator->_rtheader > |
283 | (unsigned long)iterator->_max_length) | ||
233 | return -EINVAL; | 284 | return -EINVAL; |
234 | 285 | ||
235 | next_entry: | 286 | /* these special ones are valid in each bitmap word */ |
236 | iterator->arg_index++; | 287 | switch (iterator->_arg_index % 32) { |
237 | if (unlikely((iterator->arg_index & 31) == 0)) { | 288 | case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: |
238 | /* completed current u32 bitmap */ | 289 | iterator->_bitmap_shifter >>= 1; |
239 | if (iterator->bitmap_shifter & 1) { | 290 | iterator->_arg_index++; |
240 | /* b31 was set, there is more */ | 291 | |
241 | /* move to next u32 bitmap */ | 292 | iterator->_reset_on_ext = 1; |
242 | iterator->bitmap_shifter = | 293 | |
243 | get_unaligned_le32(iterator->next_bitmap); | 294 | vnslen = get_unaligned_le16(iterator->this_arg + 4); |
244 | iterator->next_bitmap++; | 295 | iterator->_next_ns_data = iterator->_arg + vnslen; |
245 | } else | 296 | oui = (*iterator->this_arg << 16) | |
246 | /* no more bitmaps: end */ | 297 | (*(iterator->this_arg + 1) << 8) | |
247 | iterator->arg_index = sizeof(rt_sizes); | 298 | *(iterator->this_arg + 2); |
248 | } else /* just try the next bit */ | 299 | subns = *(iterator->this_arg + 3); |
249 | iterator->bitmap_shifter >>= 1; | 300 | |
301 | find_ns(iterator, oui, subns); | ||
302 | |||
303 | iterator->is_radiotap_ns = 0; | ||
304 | /* allow parsers to show this information */ | ||
305 | iterator->this_arg_index = | ||
306 | IEEE80211_RADIOTAP_VENDOR_NAMESPACE; | ||
307 | iterator->this_arg_size += vnslen; | ||
308 | if ((unsigned long)iterator->this_arg + | ||
309 | iterator->this_arg_size - | ||
310 | (unsigned long)iterator->_rtheader > | ||
311 | (unsigned long)(unsigned long)iterator->_max_length) | ||
312 | return -EINVAL; | ||
313 | hit = 1; | ||
314 | break; | ||
315 | case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: | ||
316 | iterator->_bitmap_shifter >>= 1; | ||
317 | iterator->_arg_index++; | ||
318 | |||
319 | iterator->_reset_on_ext = 1; | ||
320 | iterator->current_namespace = &radiotap_ns; | ||
321 | iterator->is_radiotap_ns = 1; | ||
322 | break; | ||
323 | case IEEE80211_RADIOTAP_EXT: | ||
324 | /* | ||
325 | * bit 31 was set, there is more | ||
326 | * -- move to next u32 bitmap | ||
327 | */ | ||
328 | iterator->_bitmap_shifter = | ||
329 | get_unaligned_le32(iterator->_next_bitmap); | ||
330 | iterator->_next_bitmap++; | ||
331 | if (iterator->_reset_on_ext) | ||
332 | iterator->_arg_index = 0; | ||
333 | else | ||
334 | iterator->_arg_index++; | ||
335 | iterator->_reset_on_ext = 0; | ||
336 | break; | ||
337 | default: | ||
338 | /* we've got a hit! */ | ||
339 | hit = 1; | ||
340 | next_entry: | ||
341 | iterator->_bitmap_shifter >>= 1; | ||
342 | iterator->_arg_index++; | ||
343 | } | ||
250 | 344 | ||
251 | /* if we found a valid arg earlier, return it now */ | 345 | /* if we found a valid arg earlier, return it now */ |
252 | if (hit) | 346 | if (hit) |
253 | return 0; | 347 | return 0; |
254 | } | 348 | } |
255 | |||
256 | /* we don't know how to handle any more args, we're done */ | ||
257 | return -ENOENT; | ||
258 | } | 349 | } |
259 | EXPORT_SYMBOL(ieee80211_radiotap_iterator_next); | 350 | EXPORT_SYMBOL(ieee80211_radiotap_iterator_next); |
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index e3219e4cd044..9796f3ed1edb 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #include <linux/notifier.h> | 55 | #include <linux/notifier.h> |
56 | #include <linux/init.h> | 56 | #include <linux/init.h> |
57 | #include <linux/compat.h> | 57 | #include <linux/compat.h> |
58 | #include <linux/ctype.h> | ||
58 | 59 | ||
59 | #include <net/x25.h> | 60 | #include <net/x25.h> |
60 | #include <net/compat.h> | 61 | #include <net/compat.h> |
@@ -512,15 +513,20 @@ static int x25_create(struct net *net, struct socket *sock, int protocol, | |||
512 | { | 513 | { |
513 | struct sock *sk; | 514 | struct sock *sk; |
514 | struct x25_sock *x25; | 515 | struct x25_sock *x25; |
515 | int rc = -ESOCKTNOSUPPORT; | 516 | int rc = -EAFNOSUPPORT; |
516 | 517 | ||
517 | if (!net_eq(net, &init_net)) | 518 | if (!net_eq(net, &init_net)) |
518 | return -EAFNOSUPPORT; | 519 | goto out; |
519 | 520 | ||
520 | if (sock->type != SOCK_SEQPACKET || protocol) | 521 | rc = -ESOCKTNOSUPPORT; |
522 | if (sock->type != SOCK_SEQPACKET) | ||
521 | goto out; | 523 | goto out; |
522 | 524 | ||
523 | rc = -ENOMEM; | 525 | rc = -EINVAL; |
526 | if (protocol) | ||
527 | goto out; | ||
528 | |||
529 | rc = -ENOBUFS; | ||
524 | if ((sk = x25_alloc_socket(net)) == NULL) | 530 | if ((sk = x25_alloc_socket(net)) == NULL) |
525 | goto out; | 531 | goto out; |
526 | 532 | ||
@@ -643,7 +649,7 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
643 | { | 649 | { |
644 | struct sock *sk = sock->sk; | 650 | struct sock *sk = sock->sk; |
645 | struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; | 651 | struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; |
646 | int rc = 0; | 652 | int len, i, rc = 0; |
647 | 653 | ||
648 | lock_kernel(); | 654 | lock_kernel(); |
649 | if (!sock_flag(sk, SOCK_ZAPPED) || | 655 | if (!sock_flag(sk, SOCK_ZAPPED) || |
@@ -653,6 +659,14 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) | |||
653 | goto out; | 659 | goto out; |
654 | } | 660 | } |
655 | 661 | ||
662 | len = strlen(addr->sx25_addr.x25_addr); | ||
663 | for (i = 0; i < len; i++) { | ||
664 | if (!isdigit(addr->sx25_addr.x25_addr[i])) { | ||
665 | rc = -EINVAL; | ||
666 | goto out; | ||
667 | } | ||
668 | } | ||
669 | |||
656 | x25_sk(sk)->source_addr = addr->sx25_addr; | 670 | x25_sk(sk)->source_addr = addr->sx25_addr; |
657 | x25_insert_socket(sk); | 671 | x25_insert_socket(sk); |
658 | sock_reset_flag(sk, SOCK_ZAPPED); | 672 | sock_reset_flag(sk, SOCK_ZAPPED); |
diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c index 0a04e62e0e18..7ff373792324 100644 --- a/net/x25/x25_proc.c +++ b/net/x25/x25_proc.c | |||
@@ -25,49 +25,17 @@ | |||
25 | #include <net/x25.h> | 25 | #include <net/x25.h> |
26 | 26 | ||
27 | #ifdef CONFIG_PROC_FS | 27 | #ifdef CONFIG_PROC_FS |
28 | static __inline__ struct x25_route *x25_get_route_idx(loff_t pos) | ||
29 | { | ||
30 | struct list_head *route_entry; | ||
31 | struct x25_route *rt = NULL; | ||
32 | |||
33 | list_for_each(route_entry, &x25_route_list) { | ||
34 | rt = list_entry(route_entry, struct x25_route, node); | ||
35 | if (!pos--) | ||
36 | goto found; | ||
37 | } | ||
38 | rt = NULL; | ||
39 | found: | ||
40 | return rt; | ||
41 | } | ||
42 | 28 | ||
43 | static void *x25_seq_route_start(struct seq_file *seq, loff_t *pos) | 29 | static void *x25_seq_route_start(struct seq_file *seq, loff_t *pos) |
44 | __acquires(x25_route_list_lock) | 30 | __acquires(x25_route_list_lock) |
45 | { | 31 | { |
46 | loff_t l = *pos; | ||
47 | |||
48 | read_lock_bh(&x25_route_list_lock); | 32 | read_lock_bh(&x25_route_list_lock); |
49 | return l ? x25_get_route_idx(--l) : SEQ_START_TOKEN; | 33 | return seq_list_start_head(&x25_route_list, *pos); |
50 | } | 34 | } |
51 | 35 | ||
52 | static void *x25_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) | 36 | static void *x25_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) |
53 | { | 37 | { |
54 | struct x25_route *rt; | 38 | return seq_list_next(v, &x25_route_list, pos); |
55 | |||
56 | ++*pos; | ||
57 | if (v == SEQ_START_TOKEN) { | ||
58 | rt = NULL; | ||
59 | if (!list_empty(&x25_route_list)) | ||
60 | rt = list_entry(x25_route_list.next, | ||
61 | struct x25_route, node); | ||
62 | goto out; | ||
63 | } | ||
64 | rt = v; | ||
65 | if (rt->node.next != &x25_route_list) | ||
66 | rt = list_entry(rt->node.next, struct x25_route, node); | ||
67 | else | ||
68 | rt = NULL; | ||
69 | out: | ||
70 | return rt; | ||
71 | } | 39 | } |
72 | 40 | ||
73 | static void x25_seq_route_stop(struct seq_file *seq, void *v) | 41 | static void x25_seq_route_stop(struct seq_file *seq, void *v) |
@@ -78,9 +46,9 @@ static void x25_seq_route_stop(struct seq_file *seq, void *v) | |||
78 | 46 | ||
79 | static int x25_seq_route_show(struct seq_file *seq, void *v) | 47 | static int x25_seq_route_show(struct seq_file *seq, void *v) |
80 | { | 48 | { |
81 | struct x25_route *rt; | 49 | struct x25_route *rt = list_entry(v, struct x25_route, node); |
82 | 50 | ||
83 | if (v == SEQ_START_TOKEN) { | 51 | if (v == &x25_route_list) { |
84 | seq_puts(seq, "Address Digits Device\n"); | 52 | seq_puts(seq, "Address Digits Device\n"); |
85 | goto out; | 53 | goto out; |
86 | } | 54 | } |
@@ -93,40 +61,16 @@ out: | |||
93 | return 0; | 61 | return 0; |
94 | } | 62 | } |
95 | 63 | ||
96 | static __inline__ struct sock *x25_get_socket_idx(loff_t pos) | ||
97 | { | ||
98 | struct sock *s; | ||
99 | struct hlist_node *node; | ||
100 | |||
101 | sk_for_each(s, node, &x25_list) | ||
102 | if (!pos--) | ||
103 | goto found; | ||
104 | s = NULL; | ||
105 | found: | ||
106 | return s; | ||
107 | } | ||
108 | |||
109 | static void *x25_seq_socket_start(struct seq_file *seq, loff_t *pos) | 64 | static void *x25_seq_socket_start(struct seq_file *seq, loff_t *pos) |
110 | __acquires(x25_list_lock) | 65 | __acquires(x25_list_lock) |
111 | { | 66 | { |
112 | loff_t l = *pos; | ||
113 | |||
114 | read_lock_bh(&x25_list_lock); | 67 | read_lock_bh(&x25_list_lock); |
115 | return l ? x25_get_socket_idx(--l) : SEQ_START_TOKEN; | 68 | return seq_hlist_start_head(&x25_list, *pos); |
116 | } | 69 | } |
117 | 70 | ||
118 | static void *x25_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) | 71 | static void *x25_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) |
119 | { | 72 | { |
120 | struct sock *s; | 73 | return seq_hlist_next(v, &x25_list, pos); |
121 | |||
122 | ++*pos; | ||
123 | if (v == SEQ_START_TOKEN) { | ||
124 | s = sk_head(&x25_list); | ||
125 | goto out; | ||
126 | } | ||
127 | s = sk_next(v); | ||
128 | out: | ||
129 | return s; | ||
130 | } | 74 | } |
131 | 75 | ||
132 | static void x25_seq_socket_stop(struct seq_file *seq, void *v) | 76 | static void x25_seq_socket_stop(struct seq_file *seq, void *v) |
@@ -148,7 +92,7 @@ static int x25_seq_socket_show(struct seq_file *seq, void *v) | |||
148 | goto out; | 92 | goto out; |
149 | } | 93 | } |
150 | 94 | ||
151 | s = v; | 95 | s = sk_entry(v); |
152 | x25 = x25_sk(s); | 96 | x25 = x25_sk(s); |
153 | 97 | ||
154 | if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL) | 98 | if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL) |
@@ -170,51 +114,16 @@ out: | |||
170 | return 0; | 114 | return 0; |
171 | } | 115 | } |
172 | 116 | ||
173 | static __inline__ struct x25_forward *x25_get_forward_idx(loff_t pos) | ||
174 | { | ||
175 | struct x25_forward *f; | ||
176 | struct list_head *entry; | ||
177 | |||
178 | list_for_each(entry, &x25_forward_list) { | ||
179 | f = list_entry(entry, struct x25_forward, node); | ||
180 | if (!pos--) | ||
181 | goto found; | ||
182 | } | ||
183 | |||
184 | f = NULL; | ||
185 | found: | ||
186 | return f; | ||
187 | } | ||
188 | |||
189 | static void *x25_seq_forward_start(struct seq_file *seq, loff_t *pos) | 117 | static void *x25_seq_forward_start(struct seq_file *seq, loff_t *pos) |
190 | __acquires(x25_forward_list_lock) | 118 | __acquires(x25_forward_list_lock) |
191 | { | 119 | { |
192 | loff_t l = *pos; | ||
193 | |||
194 | read_lock_bh(&x25_forward_list_lock); | 120 | read_lock_bh(&x25_forward_list_lock); |
195 | return l ? x25_get_forward_idx(--l) : SEQ_START_TOKEN; | 121 | return seq_list_start_head(&x25_forward_list, *pos); |
196 | } | 122 | } |
197 | 123 | ||
198 | static void *x25_seq_forward_next(struct seq_file *seq, void *v, loff_t *pos) | 124 | static void *x25_seq_forward_next(struct seq_file *seq, void *v, loff_t *pos) |
199 | { | 125 | { |
200 | struct x25_forward *f; | 126 | return seq_list_next(v, &x25_forward_list, pos); |
201 | |||
202 | ++*pos; | ||
203 | if (v == SEQ_START_TOKEN) { | ||
204 | f = NULL; | ||
205 | if (!list_empty(&x25_forward_list)) | ||
206 | f = list_entry(x25_forward_list.next, | ||
207 | struct x25_forward, node); | ||
208 | goto out; | ||
209 | } | ||
210 | f = v; | ||
211 | if (f->node.next != &x25_forward_list) | ||
212 | f = list_entry(f->node.next, struct x25_forward, node); | ||
213 | else | ||
214 | f = NULL; | ||
215 | out: | ||
216 | return f; | ||
217 | |||
218 | } | 127 | } |
219 | 128 | ||
220 | static void x25_seq_forward_stop(struct seq_file *seq, void *v) | 129 | static void x25_seq_forward_stop(struct seq_file *seq, void *v) |
@@ -225,9 +134,9 @@ static void x25_seq_forward_stop(struct seq_file *seq, void *v) | |||
225 | 134 | ||
226 | static int x25_seq_forward_show(struct seq_file *seq, void *v) | 135 | static int x25_seq_forward_show(struct seq_file *seq, void *v) |
227 | { | 136 | { |
228 | struct x25_forward *f; | 137 | struct x25_forward *f = list_entry(v, struct x25_forward, node); |
229 | 138 | ||
230 | if (v == SEQ_START_TOKEN) { | 139 | if (v == &x25_forward_list) { |
231 | seq_printf(seq, "lci dev1 dev2\n"); | 140 | seq_printf(seq, "lci dev1 dev2\n"); |
232 | goto out; | 141 | goto out; |
233 | } | 142 | } |
@@ -236,7 +145,6 @@ static int x25_seq_forward_show(struct seq_file *seq, void *v) | |||
236 | 145 | ||
237 | seq_printf(seq, "%d %-10s %-10s\n", | 146 | seq_printf(seq, "%d %-10s %-10s\n", |
238 | f->lci, f->dev1->name, f->dev2->name); | 147 | f->lci, f->dev1->name, f->dev2->name); |
239 | |||
240 | out: | 148 | out: |
241 | return 0; | 149 | return 0; |
242 | } | 150 | } |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 0ecb16a9a883..eb870fcc29cc 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -771,7 +771,8 @@ xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audi | |||
771 | 771 | ||
772 | int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | 772 | int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) |
773 | { | 773 | { |
774 | int dir, err = 0; | 774 | int dir, err = 0, cnt = 0; |
775 | struct xfrm_policy *dp; | ||
775 | 776 | ||
776 | write_lock_bh(&xfrm_policy_lock); | 777 | write_lock_bh(&xfrm_policy_lock); |
777 | 778 | ||
@@ -789,8 +790,10 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
789 | &net->xfrm.policy_inexact[dir], bydst) { | 790 | &net->xfrm.policy_inexact[dir], bydst) { |
790 | if (pol->type != type) | 791 | if (pol->type != type) |
791 | continue; | 792 | continue; |
792 | __xfrm_policy_unlink(pol, dir); | 793 | dp = __xfrm_policy_unlink(pol, dir); |
793 | write_unlock_bh(&xfrm_policy_lock); | 794 | write_unlock_bh(&xfrm_policy_lock); |
795 | if (dp) | ||
796 | cnt++; | ||
794 | 797 | ||
795 | xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, | 798 | xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, |
796 | audit_info->sessionid, | 799 | audit_info->sessionid, |
@@ -809,8 +812,10 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
809 | bydst) { | 812 | bydst) { |
810 | if (pol->type != type) | 813 | if (pol->type != type) |
811 | continue; | 814 | continue; |
812 | __xfrm_policy_unlink(pol, dir); | 815 | dp = __xfrm_policy_unlink(pol, dir); |
813 | write_unlock_bh(&xfrm_policy_lock); | 816 | write_unlock_bh(&xfrm_policy_lock); |
817 | if (dp) | ||
818 | cnt++; | ||
814 | 819 | ||
815 | xfrm_audit_policy_delete(pol, 1, | 820 | xfrm_audit_policy_delete(pol, 1, |
816 | audit_info->loginuid, | 821 | audit_info->loginuid, |
@@ -824,6 +829,8 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
824 | } | 829 | } |
825 | 830 | ||
826 | } | 831 | } |
832 | if (!cnt) | ||
833 | err = -ESRCH; | ||
827 | atomic_inc(&flow_cache_genid); | 834 | atomic_inc(&flow_cache_genid); |
828 | out: | 835 | out: |
829 | write_unlock_bh(&xfrm_policy_lock); | 836 | write_unlock_bh(&xfrm_policy_lock); |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index b36cc344474b..f50ee9badf47 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -603,13 +603,14 @@ xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audi | |||
603 | 603 | ||
604 | int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) | 604 | int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) |
605 | { | 605 | { |
606 | int i, err = 0; | 606 | int i, err = 0, cnt = 0; |
607 | 607 | ||
608 | spin_lock_bh(&xfrm_state_lock); | 608 | spin_lock_bh(&xfrm_state_lock); |
609 | err = xfrm_state_flush_secctx_check(net, proto, audit_info); | 609 | err = xfrm_state_flush_secctx_check(net, proto, audit_info); |
610 | if (err) | 610 | if (err) |
611 | goto out; | 611 | goto out; |
612 | 612 | ||
613 | err = -ESRCH; | ||
613 | for (i = 0; i <= net->xfrm.state_hmask; i++) { | 614 | for (i = 0; i <= net->xfrm.state_hmask; i++) { |
614 | struct hlist_node *entry; | 615 | struct hlist_node *entry; |
615 | struct xfrm_state *x; | 616 | struct xfrm_state *x; |
@@ -626,13 +627,16 @@ restart: | |||
626 | audit_info->sessionid, | 627 | audit_info->sessionid, |
627 | audit_info->secid); | 628 | audit_info->secid); |
628 | xfrm_state_put(x); | 629 | xfrm_state_put(x); |
630 | if (!err) | ||
631 | cnt++; | ||
629 | 632 | ||
630 | spin_lock_bh(&xfrm_state_lock); | 633 | spin_lock_bh(&xfrm_state_lock); |
631 | goto restart; | 634 | goto restart; |
632 | } | 635 | } |
633 | } | 636 | } |
634 | } | 637 | } |
635 | err = 0; | 638 | if (cnt) |
639 | err = 0; | ||
636 | 640 | ||
637 | out: | 641 | out: |
638 | spin_unlock_bh(&xfrm_state_lock); | 642 | spin_unlock_bh(&xfrm_state_lock); |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index d5a712976004..b0fb7d3bc15e 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -1525,7 +1525,7 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1525 | audit_info.secid = NETLINK_CB(skb).sid; | 1525 | audit_info.secid = NETLINK_CB(skb).sid; |
1526 | err = xfrm_state_flush(net, p->proto, &audit_info); | 1526 | err = xfrm_state_flush(net, p->proto, &audit_info); |
1527 | if (err) | 1527 | if (err) |
1528 | return err; | 1528 | return 0; |
1529 | c.data.proto = p->proto; | 1529 | c.data.proto = p->proto; |
1530 | c.event = nlh->nlmsg_type; | 1530 | c.event = nlh->nlmsg_type; |
1531 | c.seq = nlh->nlmsg_seq; | 1531 | c.seq = nlh->nlmsg_seq; |
@@ -1677,7 +1677,7 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1677 | audit_info.secid = NETLINK_CB(skb).sid; | 1677 | audit_info.secid = NETLINK_CB(skb).sid; |
1678 | err = xfrm_policy_flush(net, type, &audit_info); | 1678 | err = xfrm_policy_flush(net, type, &audit_info); |
1679 | if (err) | 1679 | if (err) |
1680 | return err; | 1680 | return 0; |
1681 | c.data.type = type; | 1681 | c.data.type = type; |
1682 | c.event = nlh->nlmsg_type; | 1682 | c.event = nlh->nlmsg_type; |
1683 | c.seq = nlh->nlmsg_seq; | 1683 | c.seq = nlh->nlmsg_seq; |
@@ -2054,6 +2054,10 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { | |||
2054 | #undef XMSGSIZE | 2054 | #undef XMSGSIZE |
2055 | 2055 | ||
2056 | static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | 2056 | static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { |
2057 | [XFRMA_SA] = { .len = sizeof(struct xfrm_usersa_info)}, | ||
2058 | [XFRMA_POLICY] = { .len = sizeof(struct xfrm_userpolicy_info)}, | ||
2059 | [XFRMA_LASTUSED] = { .type = NLA_U64}, | ||
2060 | [XFRMA_ALG_AUTH_TRUNC] = { .len = sizeof(struct xfrm_algo_auth)}, | ||
2057 | [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) }, | 2061 | [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) }, |
2058 | [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, | 2062 | [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, |
2059 | [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, | 2063 | [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, |