📄 ieee80211.c
字号:
cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | (1 << IEEE80211_RADIOTAP_DATA_RETRIES)); if (!(status->flags & IEEE80211_TX_STATUS_ACK) && !is_multicast_ether_addr(hdr->addr1)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) && (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); rthdr->data_retries = status->retry_count; rcu_read_lock(); monitors = local->monitors; list_for_each_entry_rcu(sdata, &local->interfaces, list) { /* * Using the monitors counter is possibly racy, but * if the value is wrong we simply either clone the skb * once too much or forget sending it to one monitor iface * The latter case isn't nice but fixing the race is much * more complicated. */ if (!monitors || !skb) goto out; if (sdata->type == IEEE80211_IF_TYPE_MNTR) { if (!netif_running(sdata->dev)) continue; monitors--; if (monitors) skb2 = skb_clone(skb, GFP_ATOMIC); else skb2 = NULL; skb->dev = sdata->dev; /* XXX: is this sufficient for BPF? */ skb_set_mac_header(skb, 0); skb->ip_summed = CHECKSUM_UNNECESSARY; skb->pkt_type = PACKET_OTHERHOST; skb->protocol = htons(ETH_P_802_2); memset(skb->cb, 0, sizeof(skb->cb)); netif_rx(skb); skb = skb2; } } out: rcu_read_unlock(); if (skb) dev_kfree_skb(skb);}EXPORT_SYMBOL(ieee80211_tx_status);struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops){ struct net_device *mdev; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; int priv_size; struct wiphy *wiphy; /* Ensure 32-byte alignment of our private data and hw private data. * We use the wiphy priv data for both our ieee80211_local and for * the driver's private data * * In memory it'll be like this: * * +-------------------------+ * | struct wiphy | * +-------------------------+ * | struct ieee80211_local | * +-------------------------+ * | driver's private data | * +-------------------------+ * */ priv_size = ((sizeof(struct ieee80211_local) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + priv_data_len; wiphy = wiphy_new(&mac80211_config_ops, priv_size); if (!wiphy) return NULL; wiphy->privid = mac80211_wiphy_privid; local = wiphy_priv(wiphy); local->hw.wiphy = wiphy; local->hw.priv = (char *)local + ((sizeof(struct ieee80211_local) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); BUG_ON(!ops->tx); BUG_ON(!ops->start); BUG_ON(!ops->stop); BUG_ON(!ops->config); BUG_ON(!ops->add_interface); BUG_ON(!ops->remove_interface); BUG_ON(!ops->configure_filter); local->ops = ops; /* for now, mdev needs sub_if_data :/ */ mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmaster%d", ether_setup); if (!mdev) { wiphy_free(wiphy); return NULL; } sdata = IEEE80211_DEV_TO_SUB_IF(mdev); mdev->ieee80211_ptr = &sdata->wdev; sdata->wdev.wiphy = wiphy; local->hw.queues = 1; /* default */ local->mdev = mdev; local->rx_pre_handlers = ieee80211_rx_pre_handlers; local->rx_handlers = ieee80211_rx_handlers; local->tx_handlers = ieee80211_tx_handlers; local->bridge_packets = 1; local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; local->short_retry_limit = 7; local->long_retry_limit = 4; local->hw.conf.radio_enabled = 1; local->enabled_modes = ~0; INIT_LIST_HEAD(&local->modes_list); INIT_LIST_HEAD(&local->interfaces); INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); ieee80211_rx_bss_list_init(mdev); sta_info_init(local); mdev->hard_start_xmit = ieee80211_master_start_xmit; mdev->open = ieee80211_master_open; mdev->stop = ieee80211_master_stop; mdev->type = ARPHRD_IEEE80211; mdev->header_ops = &ieee80211_header_ops; mdev->set_multicast_list = ieee80211_master_set_multicast_list; sdata->type = IEEE80211_IF_TYPE_AP; sdata->dev = mdev; sdata->local = local; sdata->u.ap.force_unicast_rateidx = -1; sdata->u.ap.max_ratectrl_rateidx = -1; ieee80211_if_sdata_init(sdata); /* no RCU needed since we're still during init phase */ list_add_tail(&sdata->list, &local->interfaces); tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); tasklet_disable(&local->tx_pending_tasklet); tasklet_init(&local->tasklet, ieee80211_tasklet_handler, (unsigned long) local); tasklet_disable(&local->tasklet); skb_queue_head_init(&local->skb_queue); skb_queue_head_init(&local->skb_queue_unreliable); return local_to_hw(local);}EXPORT_SYMBOL(ieee80211_alloc_hw);int ieee80211_register_hw(struct ieee80211_hw *hw){ struct ieee80211_local *local = hw_to_local(hw); const char *name; int result; result = wiphy_register(local->hw.wiphy); if (result < 0) return result; name = wiphy_dev(local->hw.wiphy)->driver->name; local->hw.workqueue = create_singlethread_workqueue(name); if (!local->hw.workqueue) { result = -ENOMEM; goto fail_workqueue; } /* * The hardware needs headroom for sending the frame, * and we need some headroom for passing the frame to monitor * interfaces, but never both at the same time. */ local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, sizeof(struct ieee80211_tx_status_rtap_hdr)); debugfs_hw_add(local); local->hw.conf.beacon_int = 1000; local->wstats_flags |= local->hw.max_rssi ? IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID; local->wstats_flags |= local->hw.max_signal ? IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; local->wstats_flags |= local->hw.max_noise ? IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; if (local->hw.max_rssi < 0 || local->hw.max_noise < 0) local->wstats_flags |= IW_QUAL_DBM; result = sta_info_start(local); if (result < 0) goto fail_sta_info; rtnl_lock(); result = dev_alloc_name(local->mdev, local->mdev->name); if (result < 0) goto fail_dev; memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); result = register_netdevice(local->mdev); if (result < 0) goto fail_dev; ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP); result = ieee80211_init_rate_ctrl_alg(local, hw->rate_control_algorithm); if (result < 0) { printk(KERN_DEBUG "%s: Failed to initialize rate control " "algorithm\n", wiphy_name(local->hw.wiphy)); goto fail_rate; } result = ieee80211_wep_init(local); if (result < 0) { printk(KERN_DEBUG "%s: Failed to initialize wep\n", wiphy_name(local->hw.wiphy)); goto fail_wep; } ieee80211_install_qdisc(local->mdev); /* add one default STA interface */ result = ieee80211_if_add(local->mdev, "wlan%d", NULL, IEEE80211_IF_TYPE_STA); if (result) printk(KERN_WARNING "%s: Failed to add default virtual iface\n", wiphy_name(local->hw.wiphy)); local->reg_state = IEEE80211_DEV_REGISTERED; rtnl_unlock(); ieee80211_led_init(local); return 0;fail_wep: rate_control_deinitialize(local);fail_rate: ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); unregister_netdevice(local->mdev);fail_dev: rtnl_unlock(); sta_info_stop(local);fail_sta_info: debugfs_hw_del(local); destroy_workqueue(local->hw.workqueue);fail_workqueue: wiphy_unregister(local->hw.wiphy); return result;}EXPORT_SYMBOL(ieee80211_register_hw);int ieee80211_register_hwmode(struct ieee80211_hw *hw, struct ieee80211_hw_mode *mode){ struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate; int i; INIT_LIST_HEAD(&mode->list); list_add_tail(&mode->list, &local->modes_list); local->hw_modes |= (1 << mode->mode); for (i = 0; i < mode->num_rates; i++) { rate = &(mode->rates[i]); rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate; } ieee80211_prepare_rates(local, mode); if (!local->oper_hw_mode) { /* Default to this mode */ local->hw.conf.phymode = mode->mode; local->oper_hw_mode = local->scan_hw_mode = mode; local->oper_channel = local->scan_channel = &mode->channels[0]; local->hw.conf.mode = local->oper_hw_mode; local->hw.conf.chan = local->oper_channel; } if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED)) ieee80211_set_default_regdomain(mode); return 0;}EXPORT_SYMBOL(ieee80211_register_hwmode);void ieee80211_unregister_hw(struct ieee80211_hw *hw){ struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata, *tmp; int i; tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tasklet); rtnl_lock(); BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED); local->reg_state = IEEE80211_DEV_UNREGISTERED; /* * At this point, interface list manipulations are fine * because the driver cannot be handing us frames any * more and the tasklet is killed. */ /* * First, we remove all non-master interfaces. Do this because they * may have bss pointer dependency on the master, and when we free * the master these would be freed as well, breaking our list * iteration completely. */ list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { if (sdata->dev == local->mdev) continue; list_del(&sdata->list); __ieee80211_if_del(local, sdata); } /* then, finally, remove the master interface */ __ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev)); rtnl_unlock(); ieee80211_rx_bss_list_deinit(local->mdev); ieee80211_clear_tx_pending(local); sta_info_stop(local); rate_control_deinitialize(local); debugfs_hw_del(local); for (i = 0; i < NUM_IEEE80211_MODES; i++) { kfree(local->supp_rates[i]); kfree(local->basic_rates[i]); } if (skb_queue_len(&local->skb_queue) || skb_queue_len(&local->skb_queue_unreliable)) printk(KERN_WARNING "%s: skb_queue not empty\n", wiphy_name(local->hw.wiphy)); skb_queue_purge(&local->skb_queue); skb_queue_purge(&local->skb_queue_unreliable); destroy_workqueue(local->hw.workqueue); wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); ieee80211_led_exit(local);}EXPORT_SYMBOL(ieee80211_unregister_hw);void ieee80211_free_hw(struct ieee80211_hw *hw){ struct ieee80211_local *local = hw_to_local(hw); ieee80211_if_free(local->mdev); wiphy_free(local->hw.wiphy);}EXPORT_SYMBOL(ieee80211_free_hw);static int __init ieee80211_init(void){ struct sk_buff *skb; int ret; BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));#ifdef CONFIG_MAC80211_RCSIMPLE ret = ieee80211_rate_control_register(&mac80211_rcsimple); if (ret) return ret;#endif ret = ieee80211_wme_register(); if (ret) {#ifdef CONFIG_MAC80211_RCSIMPLE ieee80211_rate_control_unregister(&mac80211_rcsimple);#endif printk(KERN_DEBUG "ieee80211_init: failed to " "initialize WME (err=%d)\n", ret); return ret; } ieee80211_debugfs_netdev_init(); ieee80211_regdomain_init(); return 0;}static void __exit ieee80211_exit(void){#ifdef CONFIG_MAC80211_RCSIMPLE ieee80211_rate_control_unregister(&mac80211_rcsimple);#endif ieee80211_wme_unregister(); ieee80211_debugfs_netdev_exit();}subsys_initcall(ieee80211_init);module_exit(ieee80211_exit);MODULE_DESCRIPTION("IEEE 802.11 subsystem");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -