diff options
Diffstat (limited to 'net/mac80211/ieee80211.c')
-rw-r--r-- | net/mac80211/ieee80211.c | 1205 |
1 files changed, 599 insertions, 606 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 2b15505a6e48..f240f9706081 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
@@ -61,6 +61,605 @@ struct ieee80211_tx_status_rtap_hdr { | |||
61 | u8 data_retries; | 61 | u8 data_retries; |
62 | } __attribute__ ((packed)); | 62 | } __attribute__ ((packed)); |
63 | 63 | ||
64 | /* common interface routines */ | ||
65 | |||
66 | static struct net_device_stats *ieee80211_get_stats(struct net_device *dev) | ||
67 | { | ||
68 | struct ieee80211_sub_if_data *sdata; | ||
69 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
70 | return &(sdata->stats); | ||
71 | } | ||
72 | |||
73 | static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr) | ||
74 | { | ||
75 | memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ | ||
76 | return ETH_ALEN; | ||
77 | } | ||
78 | |||
79 | /* master interface */ | ||
80 | |||
81 | static int ieee80211_master_open(struct net_device *dev) | ||
82 | { | ||
83 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
84 | struct ieee80211_sub_if_data *sdata; | ||
85 | int res = -EOPNOTSUPP; | ||
86 | |||
87 | read_lock(&local->sub_if_lock); | ||
88 | list_for_each_entry(sdata, &local->sub_if_list, list) { | ||
89 | if (sdata->dev != dev && netif_running(sdata->dev)) { | ||
90 | res = 0; | ||
91 | break; | ||
92 | } | ||
93 | } | ||
94 | read_unlock(&local->sub_if_lock); | ||
95 | return res; | ||
96 | } | ||
97 | |||
98 | static int ieee80211_master_stop(struct net_device *dev) | ||
99 | { | ||
100 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
101 | struct ieee80211_sub_if_data *sdata; | ||
102 | |||
103 | read_lock(&local->sub_if_lock); | ||
104 | list_for_each_entry(sdata, &local->sub_if_list, list) | ||
105 | if (sdata->dev != dev && netif_running(sdata->dev)) | ||
106 | dev_close(sdata->dev); | ||
107 | read_unlock(&local->sub_if_lock); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | /* management interface */ | ||
113 | |||
114 | static void | ||
115 | ieee80211_fill_frame_info(struct ieee80211_local *local, | ||
116 | struct ieee80211_frame_info *fi, | ||
117 | struct ieee80211_rx_status *status) | ||
118 | { | ||
119 | if (status) { | ||
120 | struct timespec ts; | ||
121 | struct ieee80211_rate *rate; | ||
122 | |||
123 | jiffies_to_timespec(jiffies, &ts); | ||
124 | fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 + | ||
125 | ts.tv_nsec / 1000); | ||
126 | fi->mactime = cpu_to_be64(status->mactime); | ||
127 | switch (status->phymode) { | ||
128 | case MODE_IEEE80211A: | ||
129 | fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a); | ||
130 | break; | ||
131 | case MODE_IEEE80211B: | ||
132 | fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b); | ||
133 | break; | ||
134 | case MODE_IEEE80211G: | ||
135 | fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g); | ||
136 | break; | ||
137 | case MODE_ATHEROS_TURBO: | ||
138 | fi->phytype = | ||
139 | htonl(ieee80211_phytype_dsss_dot11_turbo); | ||
140 | break; | ||
141 | default: | ||
142 | fi->phytype = htonl(0xAAAAAAAA); | ||
143 | break; | ||
144 | } | ||
145 | fi->channel = htonl(status->channel); | ||
146 | rate = ieee80211_get_rate(local, status->phymode, | ||
147 | status->rate); | ||
148 | if (rate) { | ||
149 | fi->datarate = htonl(rate->rate); | ||
150 | if (rate->flags & IEEE80211_RATE_PREAMBLE2) { | ||
151 | if (status->rate == rate->val) | ||
152 | fi->preamble = htonl(2); /* long */ | ||
153 | else if (status->rate == rate->val2) | ||
154 | fi->preamble = htonl(1); /* short */ | ||
155 | } else | ||
156 | fi->preamble = htonl(0); | ||
157 | } else { | ||
158 | fi->datarate = htonl(0); | ||
159 | fi->preamble = htonl(0); | ||
160 | } | ||
161 | |||
162 | fi->antenna = htonl(status->antenna); | ||
163 | fi->priority = htonl(0xffffffff); /* no clue */ | ||
164 | fi->ssi_type = htonl(ieee80211_ssi_raw); | ||
165 | fi->ssi_signal = htonl(status->ssi); | ||
166 | fi->ssi_noise = 0x00000000; | ||
167 | fi->encoding = 0; | ||
168 | } else { | ||
169 | /* clear everything because we really don't know. | ||
170 | * the msg_type field isn't present on monitor frames | ||
171 | * so we don't know whether it will be present or not, | ||
172 | * but it's ok to not clear it since it'll be assigned | ||
173 | * anyway */ | ||
174 | memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type)); | ||
175 | |||
176 | fi->ssi_type = htonl(ieee80211_ssi_none); | ||
177 | } | ||
178 | fi->version = htonl(IEEE80211_FI_VERSION); | ||
179 | fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type)); | ||
180 | } | ||
181 | |||
182 | /* this routine is actually not just for this, but also | ||
183 | * for pushing fake 'management' frames into userspace. | ||
184 | * it shall be replaced by a netlink-based system. */ | ||
185 | void | ||
186 | ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, | ||
187 | struct ieee80211_rx_status *status, u32 msg_type) | ||
188 | { | ||
189 | struct ieee80211_frame_info *fi; | ||
190 | const size_t hlen = sizeof(struct ieee80211_frame_info); | ||
191 | struct ieee80211_sub_if_data *sdata; | ||
192 | |||
193 | skb->dev = local->apdev; | ||
194 | |||
195 | sdata = IEEE80211_DEV_TO_SUB_IF(local->apdev); | ||
196 | |||
197 | if (skb_headroom(skb) < hlen) { | ||
198 | I802_DEBUG_INC(local->rx_expand_skb_head); | ||
199 | if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) { | ||
200 | dev_kfree_skb(skb); | ||
201 | return; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | fi = (struct ieee80211_frame_info *) skb_push(skb, hlen); | ||
206 | |||
207 | ieee80211_fill_frame_info(local, fi, status); | ||
208 | fi->msg_type = htonl(msg_type); | ||
209 | |||
210 | sdata->stats.rx_packets++; | ||
211 | sdata->stats.rx_bytes += skb->len; | ||
212 | |||
213 | skb_set_mac_header(skb, 0); | ||
214 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
215 | skb->pkt_type = PACKET_OTHERHOST; | ||
216 | skb->protocol = htons(ETH_P_802_2); | ||
217 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
218 | netif_rx(skb); | ||
219 | } | ||
220 | |||
221 | int ieee80211_radar_status(struct ieee80211_hw *hw, int channel, | ||
222 | int radar, int radar_type) | ||
223 | { | ||
224 | struct sk_buff *skb; | ||
225 | struct ieee80211_radar_info *msg; | ||
226 | struct ieee80211_local *local = hw_to_local(hw); | ||
227 | |||
228 | if (!local->apdev) | ||
229 | return 0; | ||
230 | |||
231 | skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + | ||
232 | sizeof(struct ieee80211_radar_info)); | ||
233 | |||
234 | if (!skb) | ||
235 | return -ENOMEM; | ||
236 | skb_reserve(skb, sizeof(struct ieee80211_frame_info)); | ||
237 | |||
238 | msg = (struct ieee80211_radar_info *) | ||
239 | skb_put(skb, sizeof(struct ieee80211_radar_info)); | ||
240 | msg->channel = channel; | ||
241 | msg->radar = radar; | ||
242 | msg->radar_type = radar_type; | ||
243 | |||
244 | ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_radar); | ||
245 | return 0; | ||
246 | } | ||
247 | EXPORT_SYMBOL(ieee80211_radar_status); | ||
248 | |||
249 | void ieee80211_key_threshold_notify(struct net_device *dev, | ||
250 | struct ieee80211_key *key, | ||
251 | struct sta_info *sta) | ||
252 | { | ||
253 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
254 | struct sk_buff *skb; | ||
255 | struct ieee80211_msg_key_notification *msg; | ||
256 | |||
257 | /* if no one will get it anyway, don't even allocate it. | ||
258 | * unlikely because this is only relevant for APs | ||
259 | * where the device must be open... */ | ||
260 | if (unlikely(!local->apdev)) | ||
261 | return; | ||
262 | |||
263 | skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + | ||
264 | sizeof(struct ieee80211_msg_key_notification)); | ||
265 | if (!skb) | ||
266 | return; | ||
267 | |||
268 | skb_reserve(skb, sizeof(struct ieee80211_frame_info)); | ||
269 | msg = (struct ieee80211_msg_key_notification *) | ||
270 | skb_put(skb, sizeof(struct ieee80211_msg_key_notification)); | ||
271 | msg->tx_rx_count = key->tx_rx_count; | ||
272 | memcpy(msg->ifname, dev->name, IFNAMSIZ); | ||
273 | if (sta) | ||
274 | memcpy(msg->addr, sta->addr, ETH_ALEN); | ||
275 | else | ||
276 | memset(msg->addr, 0xff, ETH_ALEN); | ||
277 | |||
278 | key->tx_rx_count = 0; | ||
279 | |||
280 | ieee80211_rx_mgmt(local, skb, NULL, | ||
281 | ieee80211_msg_key_threshold_notification); | ||
282 | } | ||
283 | |||
284 | static int ieee80211_mgmt_open(struct net_device *dev) | ||
285 | { | ||
286 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
287 | |||
288 | if (!netif_running(local->mdev)) | ||
289 | return -EOPNOTSUPP; | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static int ieee80211_mgmt_stop(struct net_device *dev) | ||
294 | { | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu) | ||
299 | { | ||
300 | /* FIX: what would be proper limits for MTU? | ||
301 | * This interface uses 802.11 frames. */ | ||
302 | if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) { | ||
303 | printk(KERN_WARNING "%s: invalid MTU %d\n", | ||
304 | dev->name, new_mtu); | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | |||
308 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
309 | printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); | ||
310 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
311 | dev->mtu = new_mtu; | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | void ieee80211_if_mgmt_setup(struct net_device *dev) | ||
316 | { | ||
317 | ether_setup(dev); | ||
318 | dev->hard_start_xmit = ieee80211_mgmt_start_xmit; | ||
319 | dev->change_mtu = ieee80211_change_mtu_apdev; | ||
320 | dev->get_stats = ieee80211_get_stats; | ||
321 | dev->open = ieee80211_mgmt_open; | ||
322 | dev->stop = ieee80211_mgmt_stop; | ||
323 | dev->type = ARPHRD_IEEE80211_PRISM; | ||
324 | dev->hard_header_parse = header_parse_80211; | ||
325 | dev->uninit = ieee80211_if_reinit; | ||
326 | dev->destructor = ieee80211_if_free; | ||
327 | } | ||
328 | |||
329 | /* regular interfaces */ | ||
330 | |||
331 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | ||
332 | { | ||
333 | /* FIX: what would be proper limits for MTU? | ||
334 | * This interface uses 802.3 frames. */ | ||
335 | if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) { | ||
336 | printk(KERN_WARNING "%s: invalid MTU %d\n", | ||
337 | dev->name, new_mtu); | ||
338 | return -EINVAL; | ||
339 | } | ||
340 | |||
341 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
342 | printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); | ||
343 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
344 | dev->mtu = new_mtu; | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static inline int identical_mac_addr_allowed(int type1, int type2) | ||
349 | { | ||
350 | return (type1 == IEEE80211_IF_TYPE_MNTR || | ||
351 | type2 == IEEE80211_IF_TYPE_MNTR || | ||
352 | (type1 == IEEE80211_IF_TYPE_AP && | ||
353 | type2 == IEEE80211_IF_TYPE_WDS) || | ||
354 | (type1 == IEEE80211_IF_TYPE_WDS && | ||
355 | (type2 == IEEE80211_IF_TYPE_WDS || | ||
356 | type2 == IEEE80211_IF_TYPE_AP)) || | ||
357 | (type1 == IEEE80211_IF_TYPE_AP && | ||
358 | type2 == IEEE80211_IF_TYPE_VLAN) || | ||
359 | (type1 == IEEE80211_IF_TYPE_VLAN && | ||
360 | (type2 == IEEE80211_IF_TYPE_AP || | ||
361 | type2 == IEEE80211_IF_TYPE_VLAN))); | ||
362 | } | ||
363 | |||
364 | /* Check if running monitor interfaces should go to a "soft monitor" mode | ||
365 | * and switch them if necessary. */ | ||
366 | static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local) | ||
367 | { | ||
368 | struct ieee80211_if_init_conf conf; | ||
369 | |||
370 | if (local->open_count && local->open_count == local->monitors && | ||
371 | !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) && | ||
372 | local->ops->remove_interface) { | ||
373 | conf.if_id = -1; | ||
374 | conf.type = IEEE80211_IF_TYPE_MNTR; | ||
375 | conf.mac_addr = NULL; | ||
376 | local->ops->remove_interface(local_to_hw(local), &conf); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | /* Check if running monitor interfaces should go to a "hard monitor" mode | ||
381 | * and switch them if necessary. */ | ||
382 | static void ieee80211_start_hard_monitor(struct ieee80211_local *local) | ||
383 | { | ||
384 | struct ieee80211_if_init_conf conf; | ||
385 | |||
386 | if (local->open_count && local->open_count == local->monitors && | ||
387 | !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { | ||
388 | conf.if_id = -1; | ||
389 | conf.type = IEEE80211_IF_TYPE_MNTR; | ||
390 | conf.mac_addr = NULL; | ||
391 | local->ops->add_interface(local_to_hw(local), &conf); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | static int ieee80211_open(struct net_device *dev) | ||
396 | { | ||
397 | struct ieee80211_sub_if_data *sdata, *nsdata; | ||
398 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
399 | struct ieee80211_if_init_conf conf; | ||
400 | int res; | ||
401 | |||
402 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
403 | read_lock(&local->sub_if_lock); | ||
404 | list_for_each_entry(nsdata, &local->sub_if_list, list) { | ||
405 | struct net_device *ndev = nsdata->dev; | ||
406 | |||
407 | if (ndev != dev && ndev != local->mdev && netif_running(ndev) && | ||
408 | compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 && | ||
409 | !identical_mac_addr_allowed(sdata->type, nsdata->type)) { | ||
410 | read_unlock(&local->sub_if_lock); | ||
411 | return -ENOTUNIQ; | ||
412 | } | ||
413 | } | ||
414 | read_unlock(&local->sub_if_lock); | ||
415 | |||
416 | if (sdata->type == IEEE80211_IF_TYPE_WDS && | ||
417 | is_zero_ether_addr(sdata->u.wds.remote_addr)) | ||
418 | return -ENOLINK; | ||
419 | |||
420 | if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count && | ||
421 | !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { | ||
422 | /* run the interface in a "soft monitor" mode */ | ||
423 | local->monitors++; | ||
424 | local->open_count++; | ||
425 | local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; | ||
426 | return 0; | ||
427 | } | ||
428 | ieee80211_start_soft_monitor(local); | ||
429 | |||
430 | conf.if_id = dev->ifindex; | ||
431 | conf.type = sdata->type; | ||
432 | conf.mac_addr = dev->dev_addr; | ||
433 | res = local->ops->add_interface(local_to_hw(local), &conf); | ||
434 | if (res) { | ||
435 | if (sdata->type == IEEE80211_IF_TYPE_MNTR) | ||
436 | ieee80211_start_hard_monitor(local); | ||
437 | return res; | ||
438 | } | ||
439 | |||
440 | if (local->open_count == 0) { | ||
441 | res = 0; | ||
442 | tasklet_enable(&local->tx_pending_tasklet); | ||
443 | tasklet_enable(&local->tasklet); | ||
444 | if (local->ops->open) | ||
445 | res = local->ops->open(local_to_hw(local)); | ||
446 | if (res == 0) { | ||
447 | res = dev_open(local->mdev); | ||
448 | if (res) { | ||
449 | if (local->ops->stop) | ||
450 | local->ops->stop(local_to_hw(local)); | ||
451 | } else { | ||
452 | res = ieee80211_hw_config(local); | ||
453 | if (res && local->ops->stop) | ||
454 | local->ops->stop(local_to_hw(local)); | ||
455 | else if (!res && local->apdev) | ||
456 | dev_open(local->apdev); | ||
457 | } | ||
458 | } | ||
459 | if (res) { | ||
460 | if (local->ops->remove_interface) | ||
461 | local->ops->remove_interface(local_to_hw(local), | ||
462 | &conf); | ||
463 | return res; | ||
464 | } | ||
465 | } | ||
466 | local->open_count++; | ||
467 | |||
468 | if (sdata->type == IEEE80211_IF_TYPE_MNTR) { | ||
469 | local->monitors++; | ||
470 | local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; | ||
471 | } else | ||
472 | ieee80211_if_config(dev); | ||
473 | |||
474 | if (sdata->type == IEEE80211_IF_TYPE_STA && | ||
475 | !local->user_space_mlme) | ||
476 | netif_carrier_off(dev); | ||
477 | else | ||
478 | netif_carrier_on(dev); | ||
479 | |||
480 | netif_start_queue(dev); | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static void ieee80211_if_shutdown(struct net_device *dev) | ||
485 | { | ||
486 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
487 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
488 | |||
489 | ASSERT_RTNL(); | ||
490 | switch (sdata->type) { | ||
491 | case IEEE80211_IF_TYPE_STA: | ||
492 | case IEEE80211_IF_TYPE_IBSS: | ||
493 | sdata->u.sta.state = IEEE80211_DISABLED; | ||
494 | del_timer_sync(&sdata->u.sta.timer); | ||
495 | skb_queue_purge(&sdata->u.sta.skb_queue); | ||
496 | if (!local->ops->hw_scan && | ||
497 | local->scan_dev == sdata->dev) { | ||
498 | local->sta_scanning = 0; | ||
499 | cancel_delayed_work(&local->scan_work); | ||
500 | } | ||
501 | flush_workqueue(local->hw.workqueue); | ||
502 | break; | ||
503 | } | ||
504 | } | ||
505 | |||
506 | static int ieee80211_stop(struct net_device *dev) | ||
507 | { | ||
508 | struct ieee80211_sub_if_data *sdata; | ||
509 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
510 | |||
511 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
512 | |||
513 | if (sdata->type == IEEE80211_IF_TYPE_MNTR && | ||
514 | local->open_count > 1 && | ||
515 | !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { | ||
516 | /* remove "soft monitor" interface */ | ||
517 | local->open_count--; | ||
518 | local->monitors--; | ||
519 | if (!local->monitors) | ||
520 | local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; | ||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | netif_stop_queue(dev); | ||
525 | ieee80211_if_shutdown(dev); | ||
526 | |||
527 | if (sdata->type == IEEE80211_IF_TYPE_MNTR) { | ||
528 | local->monitors--; | ||
529 | if (!local->monitors) | ||
530 | local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; | ||
531 | } | ||
532 | |||
533 | local->open_count--; | ||
534 | if (local->open_count == 0) { | ||
535 | if (netif_running(local->mdev)) | ||
536 | dev_close(local->mdev); | ||
537 | if (local->apdev) | ||
538 | dev_close(local->apdev); | ||
539 | if (local->ops->stop) | ||
540 | local->ops->stop(local_to_hw(local)); | ||
541 | tasklet_disable(&local->tx_pending_tasklet); | ||
542 | tasklet_disable(&local->tasklet); | ||
543 | } | ||
544 | if (local->ops->remove_interface) { | ||
545 | struct ieee80211_if_init_conf conf; | ||
546 | |||
547 | conf.if_id = dev->ifindex; | ||
548 | conf.type = sdata->type; | ||
549 | conf.mac_addr = dev->dev_addr; | ||
550 | local->ops->remove_interface(local_to_hw(local), &conf); | ||
551 | } | ||
552 | |||
553 | ieee80211_start_hard_monitor(local); | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | enum netif_tx_lock_class { | ||
559 | TX_LOCK_NORMAL, | ||
560 | TX_LOCK_MASTER, | ||
561 | }; | ||
562 | |||
563 | static inline void netif_tx_lock_nested(struct net_device *dev, int subclass) | ||
564 | { | ||
565 | spin_lock_nested(&dev->_xmit_lock, subclass); | ||
566 | dev->xmit_lock_owner = smp_processor_id(); | ||
567 | } | ||
568 | |||
569 | static void ieee80211_set_multicast_list(struct net_device *dev) | ||
570 | { | ||
571 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
572 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
573 | unsigned short flags; | ||
574 | |||
575 | netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER); | ||
576 | if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) { | ||
577 | if (sdata->allmulti) { | ||
578 | sdata->allmulti = 0; | ||
579 | local->iff_allmultis--; | ||
580 | } else { | ||
581 | sdata->allmulti = 1; | ||
582 | local->iff_allmultis++; | ||
583 | } | ||
584 | } | ||
585 | if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) { | ||
586 | if (sdata->promisc) { | ||
587 | sdata->promisc = 0; | ||
588 | local->iff_promiscs--; | ||
589 | } else { | ||
590 | sdata->promisc = 1; | ||
591 | local->iff_promiscs++; | ||
592 | } | ||
593 | } | ||
594 | if (dev->mc_count != sdata->mc_count) { | ||
595 | local->mc_count = local->mc_count - sdata->mc_count + | ||
596 | dev->mc_count; | ||
597 | sdata->mc_count = dev->mc_count; | ||
598 | } | ||
599 | if (local->ops->set_multicast_list) { | ||
600 | flags = local->mdev->flags; | ||
601 | if (local->iff_allmultis) | ||
602 | flags |= IFF_ALLMULTI; | ||
603 | if (local->iff_promiscs) | ||
604 | flags |= IFF_PROMISC; | ||
605 | read_lock(&local->sub_if_lock); | ||
606 | local->ops->set_multicast_list(local_to_hw(local), flags, | ||
607 | local->mc_count); | ||
608 | read_unlock(&local->sub_if_lock); | ||
609 | } | ||
610 | netif_tx_unlock(local->mdev); | ||
611 | } | ||
612 | |||
613 | /* Must not be called for mdev and apdev */ | ||
614 | void ieee80211_if_setup(struct net_device *dev) | ||
615 | { | ||
616 | ether_setup(dev); | ||
617 | dev->hard_start_xmit = ieee80211_subif_start_xmit; | ||
618 | dev->wireless_handlers = &ieee80211_iw_handler_def; | ||
619 | dev->set_multicast_list = ieee80211_set_multicast_list; | ||
620 | dev->change_mtu = ieee80211_change_mtu; | ||
621 | dev->get_stats = ieee80211_get_stats; | ||
622 | dev->open = ieee80211_open; | ||
623 | dev->stop = ieee80211_stop; | ||
624 | dev->uninit = ieee80211_if_reinit; | ||
625 | dev->destructor = ieee80211_if_free; | ||
626 | } | ||
627 | |||
628 | /* WDS specialties */ | ||
629 | |||
630 | int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) | ||
631 | { | ||
632 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
633 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
634 | struct sta_info *sta; | ||
635 | |||
636 | if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) | ||
637 | return 0; | ||
638 | |||
639 | /* Create STA entry for the new peer */ | ||
640 | sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); | ||
641 | if (!sta) | ||
642 | return -ENOMEM; | ||
643 | sta_info_put(sta); | ||
644 | |||
645 | /* Remove STA entry for the old peer */ | ||
646 | sta = sta_info_get(local, sdata->u.wds.remote_addr); | ||
647 | if (sta) { | ||
648 | sta_info_put(sta); | ||
649 | sta_info_free(sta, 0); | ||
650 | } else { | ||
651 | printk(KERN_DEBUG "%s: could not find STA entry for WDS link " | ||
652 | "peer " MAC_FMT "\n", | ||
653 | dev->name, MAC_ARG(sdata->u.wds.remote_addr)); | ||
654 | } | ||
655 | |||
656 | /* Update WDS link data */ | ||
657 | memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); | ||
658 | |||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | /* everything else */ | ||
64 | 663 | ||
65 | static int rate_list_match(const int *rate_list, int rate) | 664 | static int rate_list_match(const int *rate_list, int rate) |
66 | { | 665 | { |
@@ -76,7 +675,6 @@ static int rate_list_match(const int *rate_list, int rate) | |||
76 | return 0; | 675 | return 0; |
77 | } | 676 | } |
78 | 677 | ||
79 | |||
80 | void ieee80211_prepare_rates(struct ieee80211_local *local, | 678 | void ieee80211_prepare_rates(struct ieee80211_local *local, |
81 | struct ieee80211_hw_mode *mode) | 679 | struct ieee80211_hw_mode *mode) |
82 | { | 680 | { |
@@ -150,43 +748,6 @@ void ieee80211_prepare_rates(struct ieee80211_local *local, | |||
150 | } | 748 | } |
151 | } | 749 | } |
152 | 750 | ||
153 | |||
154 | void ieee80211_key_threshold_notify(struct net_device *dev, | ||
155 | struct ieee80211_key *key, | ||
156 | struct sta_info *sta) | ||
157 | { | ||
158 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
159 | struct sk_buff *skb; | ||
160 | struct ieee80211_msg_key_notification *msg; | ||
161 | |||
162 | /* if no one will get it anyway, don't even allocate it. | ||
163 | * unlikely because this is only relevant for APs | ||
164 | * where the device must be open... */ | ||
165 | if (unlikely(!local->apdev)) | ||
166 | return; | ||
167 | |||
168 | skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + | ||
169 | sizeof(struct ieee80211_msg_key_notification)); | ||
170 | if (!skb) | ||
171 | return; | ||
172 | |||
173 | skb_reserve(skb, sizeof(struct ieee80211_frame_info)); | ||
174 | msg = (struct ieee80211_msg_key_notification *) | ||
175 | skb_put(skb, sizeof(struct ieee80211_msg_key_notification)); | ||
176 | msg->tx_rx_count = key->tx_rx_count; | ||
177 | memcpy(msg->ifname, dev->name, IFNAMSIZ); | ||
178 | if (sta) | ||
179 | memcpy(msg->addr, sta->addr, ETH_ALEN); | ||
180 | else | ||
181 | memset(msg->addr, 0xff, ETH_ALEN); | ||
182 | |||
183 | key->tx_rx_count = 0; | ||
184 | |||
185 | ieee80211_rx_mgmt(local, skb, NULL, | ||
186 | ieee80211_msg_key_threshold_notification); | ||
187 | } | ||
188 | |||
189 | |||
190 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) | 751 | u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len) |
191 | { | 752 | { |
192 | u16 fc; | 753 | u16 fc; |
@@ -300,7 +861,6 @@ int ieee80211_is_eapol(const struct sk_buff *skb) | |||
300 | return 0; | 861 | return 0; |
301 | } | 862 | } |
302 | 863 | ||
303 | |||
304 | void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) | 864 | void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) |
305 | { | 865 | { |
306 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; | 866 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; |
@@ -317,7 +877,6 @@ void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) | |||
317 | } | 877 | } |
318 | } | 878 | } |
319 | 879 | ||
320 | |||
321 | static int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, | 880 | static int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, |
322 | int rate, int erp, int short_preamble) | 881 | int rate, int erp, int short_preamble) |
323 | { | 882 | { |
@@ -373,7 +932,6 @@ static int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, | |||
373 | return dur; | 932 | return dur; |
374 | } | 933 | } |
375 | 934 | ||
376 | |||
377 | /* Exported duration function for driver use */ | 935 | /* Exported duration function for driver use */ |
378 | __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, | 936 | __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, |
379 | size_t frame_len, int rate) | 937 | size_t frame_len, int rate) |
@@ -390,7 +948,6 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, | |||
390 | } | 948 | } |
391 | EXPORT_SYMBOL(ieee80211_generic_frame_duration); | 949 | EXPORT_SYMBOL(ieee80211_generic_frame_duration); |
392 | 950 | ||
393 | |||
394 | __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, | 951 | __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, |
395 | size_t frame_len, | 952 | size_t frame_len, |
396 | const struct ieee80211_tx_control *frame_txctl) | 953 | const struct ieee80211_tx_control *frame_txctl) |
@@ -418,7 +975,6 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, | |||
418 | } | 975 | } |
419 | EXPORT_SYMBOL(ieee80211_rts_duration); | 976 | EXPORT_SYMBOL(ieee80211_rts_duration); |
420 | 977 | ||
421 | |||
422 | __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, | 978 | __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, |
423 | size_t frame_len, | 979 | size_t frame_len, |
424 | const struct ieee80211_tx_control *frame_txctl) | 980 | const struct ieee80211_tx_control *frame_txctl) |
@@ -536,97 +1092,6 @@ int ieee80211_hw_config(struct ieee80211_local *local) | |||
536 | return ret; | 1092 | return ret; |
537 | } | 1093 | } |
538 | 1094 | ||
539 | |||
540 | static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) | ||
541 | { | ||
542 | /* FIX: what would be proper limits for MTU? | ||
543 | * This interface uses 802.3 frames. */ | ||
544 | if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) { | ||
545 | printk(KERN_WARNING "%s: invalid MTU %d\n", | ||
546 | dev->name, new_mtu); | ||
547 | return -EINVAL; | ||
548 | } | ||
549 | |||
550 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
551 | printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); | ||
552 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
553 | dev->mtu = new_mtu; | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | |||
558 | static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu) | ||
559 | { | ||
560 | /* FIX: what would be proper limits for MTU? | ||
561 | * This interface uses 802.11 frames. */ | ||
562 | if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) { | ||
563 | printk(KERN_WARNING "%s: invalid MTU %d\n", | ||
564 | dev->name, new_mtu); | ||
565 | return -EINVAL; | ||
566 | } | ||
567 | |||
568 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
569 | printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); | ||
570 | #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ | ||
571 | dev->mtu = new_mtu; | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | enum netif_tx_lock_class { | ||
576 | TX_LOCK_NORMAL, | ||
577 | TX_LOCK_MASTER, | ||
578 | }; | ||
579 | |||
580 | static inline void netif_tx_lock_nested(struct net_device *dev, int subclass) | ||
581 | { | ||
582 | spin_lock_nested(&dev->_xmit_lock, subclass); | ||
583 | dev->xmit_lock_owner = smp_processor_id(); | ||
584 | } | ||
585 | |||
586 | static void ieee80211_set_multicast_list(struct net_device *dev) | ||
587 | { | ||
588 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
589 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
590 | unsigned short flags; | ||
591 | |||
592 | netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER); | ||
593 | if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) { | ||
594 | if (sdata->allmulti) { | ||
595 | sdata->allmulti = 0; | ||
596 | local->iff_allmultis--; | ||
597 | } else { | ||
598 | sdata->allmulti = 1; | ||
599 | local->iff_allmultis++; | ||
600 | } | ||
601 | } | ||
602 | if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) { | ||
603 | if (sdata->promisc) { | ||
604 | sdata->promisc = 0; | ||
605 | local->iff_promiscs--; | ||
606 | } else { | ||
607 | sdata->promisc = 1; | ||
608 | local->iff_promiscs++; | ||
609 | } | ||
610 | } | ||
611 | if (dev->mc_count != sdata->mc_count) { | ||
612 | local->mc_count = local->mc_count - sdata->mc_count + | ||
613 | dev->mc_count; | ||
614 | sdata->mc_count = dev->mc_count; | ||
615 | } | ||
616 | if (local->ops->set_multicast_list) { | ||
617 | flags = local->mdev->flags; | ||
618 | if (local->iff_allmultis) | ||
619 | flags |= IFF_ALLMULTI; | ||
620 | if (local->iff_promiscs) | ||
621 | flags |= IFF_PROMISC; | ||
622 | read_lock(&local->sub_if_lock); | ||
623 | local->ops->set_multicast_list(local_to_hw(local), flags, | ||
624 | local->mc_count); | ||
625 | read_unlock(&local->sub_if_lock); | ||
626 | } | ||
627 | netif_tx_unlock(local->mdev); | ||
628 | } | ||
629 | |||
630 | struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, | 1095 | struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, |
631 | struct dev_mc_list *prev, | 1096 | struct dev_mc_list *prev, |
632 | void **ptr) | 1097 | void **ptr) |
@@ -658,276 +1123,6 @@ struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw, | |||
658 | } | 1123 | } |
659 | EXPORT_SYMBOL(ieee80211_get_mc_list_item); | 1124 | EXPORT_SYMBOL(ieee80211_get_mc_list_item); |
660 | 1125 | ||
661 | static struct net_device_stats *ieee80211_get_stats(struct net_device *dev) | ||
662 | { | ||
663 | struct ieee80211_sub_if_data *sdata; | ||
664 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
665 | return &(sdata->stats); | ||
666 | } | ||
667 | |||
668 | static void ieee80211_if_shutdown(struct net_device *dev) | ||
669 | { | ||
670 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
671 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
672 | |||
673 | ASSERT_RTNL(); | ||
674 | switch (sdata->type) { | ||
675 | case IEEE80211_IF_TYPE_STA: | ||
676 | case IEEE80211_IF_TYPE_IBSS: | ||
677 | sdata->u.sta.state = IEEE80211_DISABLED; | ||
678 | del_timer_sync(&sdata->u.sta.timer); | ||
679 | skb_queue_purge(&sdata->u.sta.skb_queue); | ||
680 | if (!local->ops->hw_scan && | ||
681 | local->scan_dev == sdata->dev) { | ||
682 | local->sta_scanning = 0; | ||
683 | cancel_delayed_work(&local->scan_work); | ||
684 | } | ||
685 | flush_workqueue(local->hw.workqueue); | ||
686 | break; | ||
687 | } | ||
688 | } | ||
689 | |||
690 | static inline int identical_mac_addr_allowed(int type1, int type2) | ||
691 | { | ||
692 | return (type1 == IEEE80211_IF_TYPE_MNTR || | ||
693 | type2 == IEEE80211_IF_TYPE_MNTR || | ||
694 | (type1 == IEEE80211_IF_TYPE_AP && | ||
695 | type2 == IEEE80211_IF_TYPE_WDS) || | ||
696 | (type1 == IEEE80211_IF_TYPE_WDS && | ||
697 | (type2 == IEEE80211_IF_TYPE_WDS || | ||
698 | type2 == IEEE80211_IF_TYPE_AP)) || | ||
699 | (type1 == IEEE80211_IF_TYPE_AP && | ||
700 | type2 == IEEE80211_IF_TYPE_VLAN) || | ||
701 | (type1 == IEEE80211_IF_TYPE_VLAN && | ||
702 | (type2 == IEEE80211_IF_TYPE_AP || | ||
703 | type2 == IEEE80211_IF_TYPE_VLAN))); | ||
704 | } | ||
705 | |||
706 | static int ieee80211_master_open(struct net_device *dev) | ||
707 | { | ||
708 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
709 | struct ieee80211_sub_if_data *sdata; | ||
710 | int res = -EOPNOTSUPP; | ||
711 | |||
712 | read_lock(&local->sub_if_lock); | ||
713 | list_for_each_entry(sdata, &local->sub_if_list, list) { | ||
714 | if (sdata->dev != dev && netif_running(sdata->dev)) { | ||
715 | res = 0; | ||
716 | break; | ||
717 | } | ||
718 | } | ||
719 | read_unlock(&local->sub_if_lock); | ||
720 | return res; | ||
721 | } | ||
722 | |||
723 | static int ieee80211_master_stop(struct net_device *dev) | ||
724 | { | ||
725 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
726 | struct ieee80211_sub_if_data *sdata; | ||
727 | |||
728 | read_lock(&local->sub_if_lock); | ||
729 | list_for_each_entry(sdata, &local->sub_if_list, list) | ||
730 | if (sdata->dev != dev && netif_running(sdata->dev)) | ||
731 | dev_close(sdata->dev); | ||
732 | read_unlock(&local->sub_if_lock); | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static int ieee80211_mgmt_open(struct net_device *dev) | ||
738 | { | ||
739 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
740 | |||
741 | if (!netif_running(local->mdev)) | ||
742 | return -EOPNOTSUPP; | ||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | static int ieee80211_mgmt_stop(struct net_device *dev) | ||
747 | { | ||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | /* Check if running monitor interfaces should go to a "soft monitor" mode | ||
752 | * and switch them if necessary. */ | ||
753 | static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local) | ||
754 | { | ||
755 | struct ieee80211_if_init_conf conf; | ||
756 | |||
757 | if (local->open_count && local->open_count == local->monitors && | ||
758 | !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) && | ||
759 | local->ops->remove_interface) { | ||
760 | conf.if_id = -1; | ||
761 | conf.type = IEEE80211_IF_TYPE_MNTR; | ||
762 | conf.mac_addr = NULL; | ||
763 | local->ops->remove_interface(local_to_hw(local), &conf); | ||
764 | } | ||
765 | } | ||
766 | |||
767 | /* Check if running monitor interfaces should go to a "hard monitor" mode | ||
768 | * and switch them if necessary. */ | ||
769 | static void ieee80211_start_hard_monitor(struct ieee80211_local *local) | ||
770 | { | ||
771 | struct ieee80211_if_init_conf conf; | ||
772 | |||
773 | if (local->open_count && local->open_count == local->monitors && | ||
774 | !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { | ||
775 | conf.if_id = -1; | ||
776 | conf.type = IEEE80211_IF_TYPE_MNTR; | ||
777 | conf.mac_addr = NULL; | ||
778 | local->ops->add_interface(local_to_hw(local), &conf); | ||
779 | } | ||
780 | } | ||
781 | |||
782 | static int ieee80211_open(struct net_device *dev) | ||
783 | { | ||
784 | struct ieee80211_sub_if_data *sdata, *nsdata; | ||
785 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
786 | struct ieee80211_if_init_conf conf; | ||
787 | int res; | ||
788 | |||
789 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
790 | read_lock(&local->sub_if_lock); | ||
791 | list_for_each_entry(nsdata, &local->sub_if_list, list) { | ||
792 | struct net_device *ndev = nsdata->dev; | ||
793 | |||
794 | if (ndev != dev && ndev != local->mdev && netif_running(ndev) && | ||
795 | compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 && | ||
796 | !identical_mac_addr_allowed(sdata->type, nsdata->type)) { | ||
797 | read_unlock(&local->sub_if_lock); | ||
798 | return -ENOTUNIQ; | ||
799 | } | ||
800 | } | ||
801 | read_unlock(&local->sub_if_lock); | ||
802 | |||
803 | if (sdata->type == IEEE80211_IF_TYPE_WDS && | ||
804 | is_zero_ether_addr(sdata->u.wds.remote_addr)) | ||
805 | return -ENOLINK; | ||
806 | |||
807 | if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count && | ||
808 | !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { | ||
809 | /* run the interface in a "soft monitor" mode */ | ||
810 | local->monitors++; | ||
811 | local->open_count++; | ||
812 | local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; | ||
813 | return 0; | ||
814 | } | ||
815 | ieee80211_start_soft_monitor(local); | ||
816 | |||
817 | conf.if_id = dev->ifindex; | ||
818 | conf.type = sdata->type; | ||
819 | conf.mac_addr = dev->dev_addr; | ||
820 | res = local->ops->add_interface(local_to_hw(local), &conf); | ||
821 | if (res) { | ||
822 | if (sdata->type == IEEE80211_IF_TYPE_MNTR) | ||
823 | ieee80211_start_hard_monitor(local); | ||
824 | return res; | ||
825 | } | ||
826 | |||
827 | if (local->open_count == 0) { | ||
828 | res = 0; | ||
829 | tasklet_enable(&local->tx_pending_tasklet); | ||
830 | tasklet_enable(&local->tasklet); | ||
831 | if (local->ops->open) | ||
832 | res = local->ops->open(local_to_hw(local)); | ||
833 | if (res == 0) { | ||
834 | res = dev_open(local->mdev); | ||
835 | if (res) { | ||
836 | if (local->ops->stop) | ||
837 | local->ops->stop(local_to_hw(local)); | ||
838 | } else { | ||
839 | res = ieee80211_hw_config(local); | ||
840 | if (res && local->ops->stop) | ||
841 | local->ops->stop(local_to_hw(local)); | ||
842 | else if (!res && local->apdev) | ||
843 | dev_open(local->apdev); | ||
844 | } | ||
845 | } | ||
846 | if (res) { | ||
847 | if (local->ops->remove_interface) | ||
848 | local->ops->remove_interface(local_to_hw(local), | ||
849 | &conf); | ||
850 | return res; | ||
851 | } | ||
852 | } | ||
853 | local->open_count++; | ||
854 | |||
855 | if (sdata->type == IEEE80211_IF_TYPE_MNTR) { | ||
856 | local->monitors++; | ||
857 | local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; | ||
858 | } else | ||
859 | ieee80211_if_config(dev); | ||
860 | |||
861 | if (sdata->type == IEEE80211_IF_TYPE_STA && | ||
862 | !local->user_space_mlme) | ||
863 | netif_carrier_off(dev); | ||
864 | else | ||
865 | netif_carrier_on(dev); | ||
866 | |||
867 | netif_start_queue(dev); | ||
868 | return 0; | ||
869 | } | ||
870 | |||
871 | |||
872 | static int ieee80211_stop(struct net_device *dev) | ||
873 | { | ||
874 | struct ieee80211_sub_if_data *sdata; | ||
875 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
876 | |||
877 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
878 | |||
879 | if (sdata->type == IEEE80211_IF_TYPE_MNTR && | ||
880 | local->open_count > 1 && | ||
881 | !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) { | ||
882 | /* remove "soft monitor" interface */ | ||
883 | local->open_count--; | ||
884 | local->monitors--; | ||
885 | if (!local->monitors) | ||
886 | local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; | ||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | netif_stop_queue(dev); | ||
891 | ieee80211_if_shutdown(dev); | ||
892 | |||
893 | if (sdata->type == IEEE80211_IF_TYPE_MNTR) { | ||
894 | local->monitors--; | ||
895 | if (!local->monitors) | ||
896 | local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; | ||
897 | } | ||
898 | |||
899 | local->open_count--; | ||
900 | if (local->open_count == 0) { | ||
901 | if (netif_running(local->mdev)) | ||
902 | dev_close(local->mdev); | ||
903 | if (local->apdev) | ||
904 | dev_close(local->apdev); | ||
905 | if (local->ops->stop) | ||
906 | local->ops->stop(local_to_hw(local)); | ||
907 | tasklet_disable(&local->tx_pending_tasklet); | ||
908 | tasklet_disable(&local->tasklet); | ||
909 | } | ||
910 | if (local->ops->remove_interface) { | ||
911 | struct ieee80211_if_init_conf conf; | ||
912 | |||
913 | conf.if_id = dev->ifindex; | ||
914 | conf.type = sdata->type; | ||
915 | conf.mac_addr = dev->dev_addr; | ||
916 | local->ops->remove_interface(local_to_hw(local), &conf); | ||
917 | } | ||
918 | |||
919 | ieee80211_start_hard_monitor(local); | ||
920 | |||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | |||
925 | static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr) | ||
926 | { | ||
927 | memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ | ||
928 | return ETH_ALEN; | ||
929 | } | ||
930 | |||
931 | struct ieee80211_rate * | 1126 | struct ieee80211_rate * |
932 | ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) | 1127 | ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) |
933 | { | 1128 | { |
@@ -949,142 +1144,6 @@ ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) | |||
949 | return NULL; | 1144 | return NULL; |
950 | } | 1145 | } |
951 | 1146 | ||
952 | static void | ||
953 | ieee80211_fill_frame_info(struct ieee80211_local *local, | ||
954 | struct ieee80211_frame_info *fi, | ||
955 | struct ieee80211_rx_status *status) | ||
956 | { | ||
957 | if (status) { | ||
958 | struct timespec ts; | ||
959 | struct ieee80211_rate *rate; | ||
960 | |||
961 | jiffies_to_timespec(jiffies, &ts); | ||
962 | fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 + | ||
963 | ts.tv_nsec / 1000); | ||
964 | fi->mactime = cpu_to_be64(status->mactime); | ||
965 | switch (status->phymode) { | ||
966 | case MODE_IEEE80211A: | ||
967 | fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a); | ||
968 | break; | ||
969 | case MODE_IEEE80211B: | ||
970 | fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b); | ||
971 | break; | ||
972 | case MODE_IEEE80211G: | ||
973 | fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g); | ||
974 | break; | ||
975 | case MODE_ATHEROS_TURBO: | ||
976 | fi->phytype = | ||
977 | htonl(ieee80211_phytype_dsss_dot11_turbo); | ||
978 | break; | ||
979 | default: | ||
980 | fi->phytype = htonl(0xAAAAAAAA); | ||
981 | break; | ||
982 | } | ||
983 | fi->channel = htonl(status->channel); | ||
984 | rate = ieee80211_get_rate(local, status->phymode, | ||
985 | status->rate); | ||
986 | if (rate) { | ||
987 | fi->datarate = htonl(rate->rate); | ||
988 | if (rate->flags & IEEE80211_RATE_PREAMBLE2) { | ||
989 | if (status->rate == rate->val) | ||
990 | fi->preamble = htonl(2); /* long */ | ||
991 | else if (status->rate == rate->val2) | ||
992 | fi->preamble = htonl(1); /* short */ | ||
993 | } else | ||
994 | fi->preamble = htonl(0); | ||
995 | } else { | ||
996 | fi->datarate = htonl(0); | ||
997 | fi->preamble = htonl(0); | ||
998 | } | ||
999 | |||
1000 | fi->antenna = htonl(status->antenna); | ||
1001 | fi->priority = htonl(0xffffffff); /* no clue */ | ||
1002 | fi->ssi_type = htonl(ieee80211_ssi_raw); | ||
1003 | fi->ssi_signal = htonl(status->ssi); | ||
1004 | fi->ssi_noise = 0x00000000; | ||
1005 | fi->encoding = 0; | ||
1006 | } else { | ||
1007 | /* clear everything because we really don't know. | ||
1008 | * the msg_type field isn't present on monitor frames | ||
1009 | * so we don't know whether it will be present or not, | ||
1010 | * but it's ok to not clear it since it'll be assigned | ||
1011 | * anyway */ | ||
1012 | memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type)); | ||
1013 | |||
1014 | fi->ssi_type = htonl(ieee80211_ssi_none); | ||
1015 | } | ||
1016 | fi->version = htonl(IEEE80211_FI_VERSION); | ||
1017 | fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type)); | ||
1018 | } | ||
1019 | |||
1020 | /* this routine is actually not just for this, but also | ||
1021 | * for pushing fake 'management' frames into userspace. | ||
1022 | * it shall be replaced by a netlink-based system. */ | ||
1023 | void | ||
1024 | ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb, | ||
1025 | struct ieee80211_rx_status *status, u32 msg_type) | ||
1026 | { | ||
1027 | struct ieee80211_frame_info *fi; | ||
1028 | const size_t hlen = sizeof(struct ieee80211_frame_info); | ||
1029 | struct ieee80211_sub_if_data *sdata; | ||
1030 | |||
1031 | skb->dev = local->apdev; | ||
1032 | |||
1033 | sdata = IEEE80211_DEV_TO_SUB_IF(local->apdev); | ||
1034 | |||
1035 | if (skb_headroom(skb) < hlen) { | ||
1036 | I802_DEBUG_INC(local->rx_expand_skb_head); | ||
1037 | if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) { | ||
1038 | dev_kfree_skb(skb); | ||
1039 | return; | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | fi = (struct ieee80211_frame_info *) skb_push(skb, hlen); | ||
1044 | |||
1045 | ieee80211_fill_frame_info(local, fi, status); | ||
1046 | fi->msg_type = htonl(msg_type); | ||
1047 | |||
1048 | sdata->stats.rx_packets++; | ||
1049 | sdata->stats.rx_bytes += skb->len; | ||
1050 | |||
1051 | skb_set_mac_header(skb, 0); | ||
1052 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
1053 | skb->pkt_type = PACKET_OTHERHOST; | ||
1054 | skb->protocol = htons(ETH_P_802_2); | ||
1055 | memset(skb->cb, 0, sizeof(skb->cb)); | ||
1056 | netif_rx(skb); | ||
1057 | } | ||
1058 | |||
1059 | int ieee80211_radar_status(struct ieee80211_hw *hw, int channel, | ||
1060 | int radar, int radar_type) | ||
1061 | { | ||
1062 | struct sk_buff *skb; | ||
1063 | struct ieee80211_radar_info *msg; | ||
1064 | struct ieee80211_local *local = hw_to_local(hw); | ||
1065 | |||
1066 | if (!local->apdev) | ||
1067 | return 0; | ||
1068 | |||
1069 | skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) + | ||
1070 | sizeof(struct ieee80211_radar_info)); | ||
1071 | |||
1072 | if (!skb) | ||
1073 | return -ENOMEM; | ||
1074 | skb_reserve(skb, sizeof(struct ieee80211_frame_info)); | ||
1075 | |||
1076 | msg = (struct ieee80211_radar_info *) | ||
1077 | skb_put(skb, sizeof(struct ieee80211_radar_info)); | ||
1078 | msg->channel = channel; | ||
1079 | msg->radar = radar; | ||
1080 | msg->radar_type = radar_type; | ||
1081 | |||
1082 | ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_radar); | ||
1083 | return 0; | ||
1084 | } | ||
1085 | EXPORT_SYMBOL(ieee80211_radar_status); | ||
1086 | |||
1087 | |||
1088 | static void ieee80211_stat_refresh(unsigned long data) | 1147 | static void ieee80211_stat_refresh(unsigned long data) |
1089 | { | 1148 | { |
1090 | struct ieee80211_local *local = (struct ieee80211_local *) data; | 1149 | struct ieee80211_local *local = (struct ieee80211_local *) data; |
@@ -1121,7 +1180,6 @@ static void ieee80211_stat_refresh(unsigned long data) | |||
1121 | add_timer(&local->stat_timer); | 1180 | add_timer(&local->stat_timer); |
1122 | } | 1181 | } |
1123 | 1182 | ||
1124 | |||
1125 | void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, | 1183 | void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, |
1126 | struct sk_buff *skb, | 1184 | struct sk_buff *skb, |
1127 | struct ieee80211_tx_status *status) | 1185 | struct ieee80211_tx_status *status) |
@@ -1198,7 +1256,6 @@ static void ieee80211_tasklet_handler(unsigned long data) | |||
1198 | } | 1256 | } |
1199 | } | 1257 | } |
1200 | 1258 | ||
1201 | |||
1202 | /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to | 1259 | /* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to |
1203 | * make a prepared TX frame (one that has been given to hw) to look like brand | 1260 | * make a prepared TX frame (one that has been given to hw) to look like brand |
1204 | * new IEEE 802.11 frame that is ready to go through TX processing again. | 1261 | * new IEEE 802.11 frame that is ready to go through TX processing again. |
@@ -1261,7 +1318,6 @@ no_key: | |||
1261 | } | 1318 | } |
1262 | } | 1319 | } |
1263 | 1320 | ||
1264 | |||
1265 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | 1321 | void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, |
1266 | struct ieee80211_tx_status *status) | 1322 | struct ieee80211_tx_status *status) |
1267 | { | 1323 | { |
@@ -1480,68 +1536,6 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, | |||
1480 | } | 1536 | } |
1481 | EXPORT_SYMBOL(ieee80211_tx_status); | 1537 | EXPORT_SYMBOL(ieee80211_tx_status); |
1482 | 1538 | ||
1483 | |||
1484 | int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) | ||
1485 | { | ||
1486 | struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); | ||
1487 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
1488 | struct sta_info *sta; | ||
1489 | |||
1490 | if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) | ||
1491 | return 0; | ||
1492 | |||
1493 | /* Create STA entry for the new peer */ | ||
1494 | sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); | ||
1495 | if (!sta) | ||
1496 | return -ENOMEM; | ||
1497 | sta_info_put(sta); | ||
1498 | |||
1499 | /* Remove STA entry for the old peer */ | ||
1500 | sta = sta_info_get(local, sdata->u.wds.remote_addr); | ||
1501 | if (sta) { | ||
1502 | sta_info_put(sta); | ||
1503 | sta_info_free(sta, 0); | ||
1504 | } else { | ||
1505 | printk(KERN_DEBUG "%s: could not find STA entry for WDS link " | ||
1506 | "peer " MAC_FMT "\n", | ||
1507 | dev->name, MAC_ARG(sdata->u.wds.remote_addr)); | ||
1508 | } | ||
1509 | |||
1510 | /* Update WDS link data */ | ||
1511 | memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); | ||
1512 | |||
1513 | return 0; | ||
1514 | } | ||
1515 | |||
1516 | /* Must not be called for mdev and apdev */ | ||
1517 | void ieee80211_if_setup(struct net_device *dev) | ||
1518 | { | ||
1519 | ether_setup(dev); | ||
1520 | dev->hard_start_xmit = ieee80211_subif_start_xmit; | ||
1521 | dev->wireless_handlers = &ieee80211_iw_handler_def; | ||
1522 | dev->set_multicast_list = ieee80211_set_multicast_list; | ||
1523 | dev->change_mtu = ieee80211_change_mtu; | ||
1524 | dev->get_stats = ieee80211_get_stats; | ||
1525 | dev->open = ieee80211_open; | ||
1526 | dev->stop = ieee80211_stop; | ||
1527 | dev->uninit = ieee80211_if_reinit; | ||
1528 | dev->destructor = ieee80211_if_free; | ||
1529 | } | ||
1530 | |||
1531 | void ieee80211_if_mgmt_setup(struct net_device *dev) | ||
1532 | { | ||
1533 | ether_setup(dev); | ||
1534 | dev->hard_start_xmit = ieee80211_mgmt_start_xmit; | ||
1535 | dev->change_mtu = ieee80211_change_mtu_apdev; | ||
1536 | dev->get_stats = ieee80211_get_stats; | ||
1537 | dev->open = ieee80211_mgmt_open; | ||
1538 | dev->stop = ieee80211_mgmt_stop; | ||
1539 | dev->type = ARPHRD_IEEE80211_PRISM; | ||
1540 | dev->hard_header_parse = header_parse_80211; | ||
1541 | dev->uninit = ieee80211_if_reinit; | ||
1542 | dev->destructor = ieee80211_if_free; | ||
1543 | } | ||
1544 | |||
1545 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | 1539 | struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, |
1546 | const struct ieee80211_ops *ops) | 1540 | const struct ieee80211_ops *ops) |
1547 | { | 1541 | { |
@@ -1948,7 +1942,6 @@ static int __init ieee80211_init(void) | |||
1948 | return 0; | 1942 | return 0; |
1949 | } | 1943 | } |
1950 | 1944 | ||
1951 | |||
1952 | static void __exit ieee80211_exit(void) | 1945 | static void __exit ieee80211_exit(void) |
1953 | { | 1946 | { |
1954 | ieee80211_wme_unregister(); | 1947 | ieee80211_wme_unregister(); |