linux wireless cfg80211

cfg80211工作在内核,是内核中WiFi框架的上半部分,位置在/$(KERNEL)/net/wireless中(其中有一小部分是wext)

从WiFi层次上,cfg80211处于wpa_supplicant和驱动之间,对上通过nl80211和wpa_supplicant通信,对下调用driver注册的cfg80211_ops结构中的回调函数,完成WiFi管理工作。但cfg80211对协议本身的feature实现很少,只实现了一部分辅助工作。大部分还是要靠mac80211或者驱动来完成。

cfg80211可以配置成编译进内核也可以编译成模块,如果编译成模块,那么加载wifi驱动的时候需要同时加载cfg80211.ko。

几个名词的解释:

名词 解释
cfg80211 用于对无线设备进行配置管理。与FullMAC, mac80211和nl80211一起工作。(Kernel态)
mac80211 一个driver开发者可用于为SoftMAC无线设备写驱动的框架 (Kernel态)。
nl80211 用于对无线设备进行配置管理,它是一个基本Netlink的用户态协议(User态)
WNIC Wireless Network Interface Controller, 它总是指望硬件执行协议(如IEEE802.11)描述的功能
MLME 即MAC(Media Access Control ) Layer Management Entity,它管理物理层MAC状态机
SoftMAC 其MLME由软件实现,mac80211为SoftMAC实现提供了一个driver API。 即:SoftMAC设备允许对硬件执行更好地控制,允许用软件实现对802.11的帧管理,包括解析和产生802.11无线帧。目前大多数802.11设 备为SoftMAC,而FullMAC设备较少。
FullMAC 其MLME由硬件管理,当写FullMAC无线驱动时,不需要使用mac80211
wpa_supplicant 用户空间一个应用程序,主要发起MLME命令,然后处理相关结果

核心数据结构和功能

wiphy

cfg80211的核心数据结构是wiphy,它用来描述一个物理WLAN设备,wiphy结构通常由Driver通过wiphy_new申请并初始化,最终t通过wiphy_register注册到cfg80211中,cfg80211本身对wiphy结构不做过多配置。wiphy维护一个私有指针priv,可以由驱动将针对特定硬件的私有结构附在wiphy结构末尾,在Driver初始化中和wiphy结构一并初始化。

cfg80211对wiphy结构的管理是通过cfg80211_registered_device(后文简称rdev)这一结构完成的,cfg80211_registered_devicewiphy结构附在结尾,如下图所示

​```c
/**
 * struct wiphy - wireless hardware description
 * @reg_notifier: the driver's regulatory notification callback,
 *  note that if your driver uses wiphy_apply_custom_regulatory()
 *  the reg_notifier's request can be passed as NULL
 * @regd: the driver's regulatory domain, if one was requested via
 *  the regulatory_hint() API. This can be used by the driver
 *  on the reg_notifier() if it chooses to ignore future
 *  regulatory domain changes caused by other drivers.
 * @signal_type: signal type reported in &struct cfg80211_bss.
 * @cipher_suites: supported cipher suites
 * @n_cipher_suites: number of supported cipher suites
 * @retry_short: Retry limit for short frames (dot11ShortRetryLimit)
 * @retry_long: Retry limit for long frames (dot11LongRetryLimit)
 * @frag_threshold: Fragmentation threshold (dot11FragmentationThreshold);
 *  -1 = fragmentation disabled, only odd values >= 256 used
 * @rts_threshold: RTS threshold (dot11RTSThreshold); -1 = RTS/CTS disabled
 * @_net: the network namespace this wiphy currently lives in
 * @perm_addr: permanent MAC address of this device
 * @addr_mask: If the device supports multiple MAC addresses by masking,
 *  set this to a mask with variable bits set to 1, e.g. if the last
 *  four bits are variable then set it to 00:...:00:0f. The actual
 *  variable bits shall be determined by the interfaces added, with
 *  interfaces not matching the mask being rejected to be brought up.
 * @n_addresses: number of addresses in @addresses.
 * @addresses: If the device has more than one address, set this pointer
 *  to a list of addresses (6 bytes each). The first one will be used
 *  by default for perm_addr. In this case, the mask should be set to
 *  all-zeroes. In this case it is assumed that the device can handle
 *  the same number of arbitrary MAC addresses.
 * @registered: protects ->resume and ->suspend sysfs callbacks against
 *  unregister hardware
 * @debugfsdir: debugfs directory used for this wiphy, will be renamed
 *  automatically on wiphy renames
 * @dev: (virtual) struct device for this wiphy
 * @registered: helps synchronize suspend/resume with wiphy unregister
 * @wext: wireless extension handlers
 * @priv: driver private data (sized according to wiphy_new() parameter)
 * @interface_modes: bitmask of interfaces types valid for this wiphy,
 *  must be set by driver
 * @iface_combinations: Valid interface combinations array, should not
 *  list single interface types.
 * @n_iface_combinations: number of entries in @iface_combinations array.
 * @software_iftypes: bitmask of software interface types, these are not
 *  subject to any restrictions since they are purely managed in SW.
 * @flags: wiphy flags, see &enum wiphy_flags
 * @features: features advertised to nl80211, see &enum nl80211_feature_flags.
 * @bss_priv_size: each BSS struct has private data allocated with it,
 *  this variable determines its size
 * @max_scan_ssids: maximum number of SSIDs the device can scan for in
 *  any given scan
 * @max_sched_scan_ssids: maximum number of SSIDs the device can scan
 *  for in any given scheduled scan
 * @max_match_sets: maximum number of match sets the device can handle
 *  when performing a scheduled scan, 0 if filtering is not
 *  supported.
 * @max_scan_ie_len: maximum length of user-controlled IEs device can
 *  add to probe request frames transmitted during a scan, must not
 *  include fixed IEs like supported rates
 * @max_sched_scan_ie_len: same as max_scan_ie_len, but for scheduled
 *  scans
 * @coverage_class: current coverage class
 * @fw_version: firmware version for ethtool reporting
 * @hw_version: hardware version for ethtool reporting
 * @max_num_pmkids: maximum number of PMKIDs supported by device
 * @privid: a pointer that drivers can use to identify if an arbitrary
 *  wiphy is theirs, e.g. in global notifiers
 * @bands: information about bands/channels supported by this device
 *
 * @mgmt_stypes: bitmasks of frame subtypes that can be subscribed to or
 *  transmitted through nl80211, points to an array indexed by interface
 *  type
 *
 * @available_antennas_tx: bitmap of antennas which are available to be
 *  configured as TX antennas. Antenna configuration commands will be
 *  rejected unless this or @available_antennas_rx is set.
 *
 * @available_antennas_rx: bitmap of antennas which are available to be
 *  configured as RX antennas. Antenna configuration commands will be
 *  rejected unless this or @available_antennas_tx is set.
 *
 * @probe_resp_offload:
 *   Bitmap of supported protocols for probe response offloading.
 *   See &enum nl80211_probe_resp_offload_support_attr. Only valid
 *   when the wiphy flag @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD is set.
 *
 * @max_remain_on_channel_duration: Maximum time a remain-on-channel operation
 *  may request, if implemented.
 *
 * @wowlan: WoWLAN support information
 *
 * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
 * @ht_capa_mod_mask:  Specify what ht_cap values can be over-ridden.
 *  If null, then none can be over-ridden.
 *
 * @max_acl_mac_addrs: Maximum number of MAC addresses that the device
 *  supports for ACL.
 *
 * @extended_capabilities: extended capabilities supported by the driver,
 *  additional capabilities might be supported by userspace; these are
 *  the 802.11 extended capabilities ("Extended Capabilities element")
 *  and are in the same format as in the information element. See
 *  802.11-2012 8.4.2.29 for the defined fields.
 * @extended_capabilities_mask: mask of the valid values
 * @extended_capabilities_len: length of the extended capabilities
 */
struct wiphy {
    /* assign these fields before you register the wiphy */
    /* permanent MAC address(es) */
    u8 perm_addr[ETH_ALEN];
    u8 addr_mask[ETH_ALEN];
    struct mac_address *addresses;
    const struct ieee80211_txrx_stypes *mgmt_stypes;
    const struct ieee80211_iface_combination *iface_combinations;
    int n_iface_combinations;
    u16 software_iftypes;
    u16 n_addresses;
    /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
    u16 interface_modes;
    u16 max_acl_mac_addrs;
    u32 flags, features;
    u32 ap_sme_capa;
    enum cfg80211_signal_type signal_type;
    int bss_priv_size;
    u8 max_scan_ssids;
    u8 max_sched_scan_ssids;
    u8 max_match_sets;
    u16 max_scan_ie_len;
    u16 max_sched_scan_ie_len;
    int n_cipher_suites;
    const u32 *cipher_suites;
    u8 retry_short;
    u8 retry_long;
    u32 frag_threshold;
    u32 rts_threshold;
    u8 coverage_class;
    char fw_version[ETHTOOL_FWVERS_LEN];
    u32 hw_version;
#ifdef CONFIG_PM
    struct wiphy_wowlan_support wowlan;
#endif
    u16 max_remain_on_channel_duration;
    u8 max_num_pmkids;
    u32 available_antennas_tx;
    u32 available_antennas_rx;
    /*
     * Bitmap of supported protocols for probe response offloading
     * see &enum nl80211_probe_resp_offload_support_attr. Only valid
     * when the wiphy flag @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD is set.
     */
    u32 probe_resp_offload;
    const u8 *extended_capabilities, *extended_capabilities_mask;
    u8 extended_capabilities_len;
    /* If multiple wiphys are registered and you're handed e.g.
     * a regular netdev with assigned ieee80211_ptr, you won't
     * know whether it points to a wiphy your driver has registered
     * or not. Assign this to something global to your driver to
     * help determine whether you own this wiphy or not. */
    const void *privid;
    struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
    /* Lets us get back the wiphy on the callback */
    void (*reg_notifier)(struct wiphy *wiphy,
                 struct regulatory_request *request);
    /* fields below are read-only, assigned by cfg80211 */
    const struct ieee80211_regdomain __rcu *regd;
    /* the item in /sys/class/ieee80211/ points to this,
     * you need use set_wiphy_dev() (see below) */
    struct device dev;
    /* protects ->resume, ->suspend sysfs callbacks against unregister hw */
    bool registered;
    /* dir in debugfs: ieee80211/<wiphyname> */
    struct dentry *debugfsdir;
    const struct ieee80211_ht_cap *ht_capa_mod_mask;
#ifdef CONFIG_NET_NS
    /* the network namespace this phy lives in currently */
    struct net *_net;
#endif
#ifdef CONFIG_CFG80211_WEXT
    const struct iw_handler_def *wext;
#endif
    char priv[0] __aligned(NETDEV_ALIGN);
};

​```

cfg80211_registered_device

cfg80211_registered_device结构在wiphy_new中分配,由驱动负责申请,并初始化wiphy部分,cfg80211负责初始化剩余部分,cfg80211_registered_device结构主要成员如下所示。

struct cfg80211_registered_device {
    const struct cfg80211_ops *ops;
    struct list_head list;
    /* we hold this mutex during any call so that
     * we cannot do multiple calls at once, and also
     * to avoid the deregister call to proceed while
     * any call is in progress */
    struct mutex mtx;
    /* rfkill support */
    struct rfkill_ops rfkill_ops;
    struct rfkill *rfkill;
    struct work_struct rfkill_sync;
    /* ISO / IEC 3166 alpha2 for which this device is receiving
     * country IEs on, this can help disregard country IEs from APs
     * on the same alpha2 quickly. The alpha2 may differ from
     * cfg80211_regdomain's alpha2 when an intersection has occurred.
     * If the AP is reconfigured this can also be used to tell us if
     * the country on the country IE changed. */
    char country_ie_alpha2[2];
    /* If a Country IE has been received this tells us the environment
     * which its telling us its in. This defaults to ENVIRON_ANY */
    enum environment_cap env;
    /* wiphy index, internal only */
    int wiphy_idx;
    /* associated wireless interfaces */
    struct mutex devlist_mtx;
    /* protected by devlist_mtx or RCU */
    struct list_head wdev_list;
    int devlist_generation, wdev_id;
    int opencount; /* also protected by devlist_mtx */
    wait_queue_head_t dev_wait;
    struct list_head beacon_registrations;
    spinlock_t beacon_registrations_lock;
    /* protected by RTNL only */
    int num_running_ifaces;
    int num_running_monitor_ifaces;
    /* BSSes/scanning */
    spinlock_t bss_lock;
    struct list_head bss_list;
    struct rb_root bss_tree;
    u32 bss_generation;
    struct cfg80211_scan_request *scan_req; /* protected by RTNL */
    struct cfg80211_sched_scan_request *sched_scan_req;
    unsigned long suspend_at;
    struct work_struct scan_done_wk;
    struct work_struct sched_scan_results_wk;
    struct mutex sched_scan_mtx;
#ifdef CONFIG_NL80211_TESTMODE
    struct genl_info *testmode_info;
#endif
    struct work_struct conn_work;
    struct work_struct event_work;
    struct cfg80211_wowlan *wowlan;
    struct delayed_work dfs_update_channels_wk;
    /* must be last because of the way we do wiphy_priv(),
     * and it should at least be aligned to NETDEV_ALIGN */
    struct wiphy wiphy __aligned(NETDEV_ALIGN);
};

主要包括bss管理和完成一些特定工作的工作函数(work_struct),这些work都会在一个特定的wq(在cfg80211_init中分配的)上完成。

cfg80211_registered_device的另外一个功能是将由driver注册的回调函数组cfg80211_opswiphy绑定在一起,从而完成网络管理的操作。这也是cfg80211Driver通信的主要手段。

由于有可能有多个物理设备,因此也有可能有多个rdevcfg80211使用一个双向链表管理它们。

wireless_dev

还有一个重要的数据结构是wireless_dev,是用来描述wlan状态的。主要包括当前bsskeysetpower save等相关连接信息。wdev有一个wiphy指针,用于交叉引用,wiphy本身不能直接引用wdev,通常驱动在注册vendor_spec结构中会关联wdev的指针,wiphy通过wiphy→priv间接引用wdev。他们之间的联系如下图所示

/**
 * struct wireless_dev - wireless device state
 *
 * For netdevs, this structure must be allocated by the driver
 * that uses the ieee80211_ptr field in struct net_device (this
 * is intentional so it can be allocated along with the netdev.)
 * It need not be registered then as netdev registration will
 * be intercepted by cfg80211 to see the new wireless device.
 *
 * For non-netdev uses, it must also be allocated by the driver
 * in response to the cfg80211 callbacks that require it, as
 * there's no netdev registration in that case it may not be
 * allocated outside of callback operations that return it.
 *
 * @wiphy: pointer to hardware description
 * @iftype: interface type
 * @list: (private) Used to collect the interfaces
 * @netdev: (private) Used to reference back to the netdev, may be %NULL
 * @identifier: (private) Identifier used in nl80211 to identify this
 *  wireless device if it has no netdev
 * @current_bss: (private) Used by the internal configuration code
 * @channel: (private) Used by the internal configuration code to track
 *  the user-set AP, monitor and WDS channel
 * @preset_chan: (private) Used by the internal configuration code to
 *  track the channel to be used for AP later
 * @bssid: (private) Used by the internal configuration code
 * @ssid: (private) Used by the internal configuration code
 * @ssid_len: (private) Used by the internal configuration code
 * @mesh_id_len: (private) Used by the internal configuration code
 * @mesh_id_up_len: (private) Used by the internal configuration code
 * @wext: (private) Used by the internal wireless extensions compat code
 * @use_4addr: indicates 4addr mode is used on this interface, must be
 *  set by driver (if supported) on add_interface BEFORE registering the
 *  netdev and may otherwise be used by driver read-only, will be update
 *  by cfg80211 on change_interface
 * @mgmt_registrations: list of registrations for management frames
 * @mgmt_registrations_lock: lock for the list
 * @mtx: mutex used to lock data in this struct
 * @cleanup_work: work struct used for cleanup that can't be done directly
 * @beacon_interval: beacon interval used on this device for transmitting
 *  beacons, 0 when not valid
 * @address: The address for this device, valid only if @netdev is %NULL
 * @p2p_started: true if this is a P2P Device that has been started
 * @cac_started: true if DFS channel availability check has been started
 * @cac_start_time: timestamp (jiffies) when the dfs state was entered.
 */
struct wireless_dev {
    struct wiphy *wiphy;
    enum nl80211_iftype iftype;
    /* the remainder of this struct should be private to cfg80211 */
    struct list_head list;
    struct net_device *netdev;
    u32 identifier;
    struct list_head mgmt_registrations;
    spinlock_t mgmt_registrations_lock;
    struct mutex mtx;
    struct work_struct cleanup_work;
    bool use_4addr, p2p_started;
    u8 address[ETH_ALEN] __aligned(sizeof(u16));
    /* currently used for IBSS and SME - might be rearranged later */
    u8 ssid[IEEE80211_MAX_SSID_LEN];
    u8 ssid_len, mesh_id_len, mesh_id_up_len;
    enum {
        CFG80211_SME_IDLE,
        CFG80211_SME_CONNECTING,
        CFG80211_SME_CONNECTED,
    } sme_state;
    struct cfg80211_conn *conn;
    struct cfg80211_cached_keys *connect_keys;
    struct list_head event_list;
    spinlock_t event_lock;
    struct cfg80211_internal_bss *current_bss; /* associated / joined */
    struct cfg80211_chan_def preset_chandef;
    /* for AP and mesh channel tracking */
    struct ieee80211_channel *channel;
    bool ibss_fixed;
    bool ps;
    int ps_timeout;
    int beacon_interval;
    u32 ap_unexpected_nlportid;
    bool cac_started;
    unsigned long cac_start_time;
#ifdef CONFIG_CFG80211_WEXT
    /* wext data */
    struct {
        struct cfg80211_ibss_params ibss;
        struct cfg80211_connect_params connect;
        struct cfg80211_cached_keys *keys;
        u8 *ie;
        size_t ie_len;
        u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
        u8 ssid[IEEE80211_MAX_SSID_LEN];
        s8 default_key, default_mgmt_key;
        bool prev_bssid_valid;
    } wext;
#endif
};

cfg80211_init

static int __init cfg80211_init(void)
{
    int err;

    err = register_pernet_device(&cfg80211_pernet_ops);
    if (err)
        goto out_fail_pernet;

    err = wiphy_sysfs_init();
    if (err)
        goto out_fail_sysfs;

    err = register_netdevice_notifier(&cfg80211_netdev_notifier);
    if (err)
        goto out_fail_notifier;

    err = nl80211_init();
    if (err)
        goto out_fail_nl80211;

    ieee80211_debugfs_dir = debugfs_create_dir("ieee80211", NULL);

    err = regulatory_init();
    if (err)
        goto out_fail_reg;

    cfg80211_wq = create_singlethread_workqueue("cfg80211");
    if (!cfg80211_wq)
        goto out_fail_wq;

    return 0;

out_fail_wq:
    regulatory_exit();
out_fail_reg:
    debugfs_remove(ieee80211_debugfs_dir);
out_fail_nl80211:
    unregister_netdevice_notifier(&cfg80211_netdev_notifier);
out_fail_notifier:
    wiphy_sysfs_exit();
out_fail_sysfs:
    unregister_pernet_device(&cfg80211_pernet_ops);
out_fail_pernet:
    return err;
}

从代码结构上看做的事情并不复杂,包括:注册parrnet_device, wiphy_sysfs初始化,注册netdevice消息通知,初始化nl80211和regulatory,最后创建一个工作队列。其中

  1. register_pernet_device和register_netdevice_notifiier算是注册一个网络协议的标准流程了(当然,更多是使用register_pernet_subsys),在此不展开讲。
  2. sysfs是按照Linux驱动模型提供的新的和应用层交互的接口,cfg80211在此注册了ieee80211/$(wiphy_name)的一个class,关于sysfs的细节可以参考linux驱动模型。
  3. debugfs本质上和/sys和/proc是一样的,但是/sys和/proc都有特定目的和要求,如果调试需要应用层与驱动交互,使用debugfs比较好,cfg80211在debugfs的根目录下建立了一个文件夹,WiFi驱动可以在这下面建立文件节点,方便与应用层交互。
  4. 最后创建的工作队列主要用于扫描等辅助性工作使用。初始化最核心的部分就是注册一个genl_famlily来和wpa_supplicant通信,这部分是通过nl80211_init完成的。

cfg80211_init只是在系统启动或者加载cfg80211模块时候做了一些准备工作,更多的初始化工作是由driver发起的,一个典型的流程是由driver的probe函数中通过wiphy_new函数申请wiphy结构(实际分配的结构包括了cfg80211_registered_devicevendor_spec部分),由cfg80211初始化rdev部分,由驱动初始化wiphy部分,最后driver调用wiphy_register完成注册。我们接下来看一看这两个函数:

wiphy_new

struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
{
    static int wiphy_counter;
    struct cfg80211_registered_device *rdev;
    int alloc_size;
    WARN_ON(ops->add_key && (!ops->del_key || !ops->set_default_key));
    WARN_ON(ops->auth && (!ops->assoc || !ops->deauth || !ops->disassoc));
    WARN_ON(ops->connect && !ops->disconnect);
    WARN_ON(ops->join_ibss && !ops->leave_ibss);
    WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf);
    WARN_ON(ops->add_station && !ops->del_station);
    WARN_ON(ops->add_mpath && !ops->del_mpath);
    WARN_ON(ops->join_mesh && !ops->leave_mesh);
    alloc_size = sizeof(*rdev) + sizeof_priv;
    rdev = kzalloc(alloc_size, GFP_KERNEL);
    if (!rdev)
        return NULL;
    rdev->ops = ops;
    mutex_lock(&cfg80211_mutex);
    rdev->wiphy_idx = wiphy_counter++;
    if (unlikely(rdev->wiphy_idx < 0)) {
        wiphy_counter--;
        mutex_unlock(&cfg80211_mutex);
        /* ugh, wrapped! */
        kfree(rdev);
        return NULL;
    }
    mutex_unlock(&cfg80211_mutex);
    /* give it a proper name */
    dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
    mutex_init(&rdev->mtx);
    mutex_init(&rdev->devlist_mtx);
    mutex_init(&rdev->sched_scan_mtx);
    INIT_LIST_HEAD(&rdev->wdev_list);
    INIT_LIST_HEAD(&rdev->beacon_registrations);
    spin_lock_init(&rdev->beacon_registrations_lock);
    spin_lock_init(&rdev->bss_lock);
    INIT_LIST_HEAD(&rdev->bss_list);
    INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
    INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results);
    INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk,
              cfg80211_dfs_channels_update_work);
#ifdef CONFIG_CFG80211_WEXT
    rdev->wiphy.wext = &cfg80211_wext_handler;
#endif
    device_initialize(&rdev->wiphy.dev);
    rdev->wiphy.dev.class = &ieee80211_class;
    rdev->wiphy.dev.platform_data = rdev;
#ifdef CONFIG_CFG80211_DEFAULT_PS
    rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
#endif
    wiphy_net_set(&rdev->wiphy, &init_net);
    rdev->rfkill_ops.set_block = cfg80211_rfkill_set_block;
    rdev->rfkill = rfkill_alloc(dev_name(&rdev->wiphy.dev),
                   &rdev->wiphy.dev, RFKILL_TYPE_WLAN,
                   &rdev->rfkill_ops, rdev);
    if (!rdev->rfkill) {
        kfree(rdev);
        return NULL;
    }
    INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work);
    INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
    INIT_WORK(&rdev->event_work, cfg80211_event_work);
    init_waitqueue_head(&rdev->dev_wait);
    /*
     * Initialize wiphy parameters to IEEE 802.11 MIB default values.
     * Fragmentation and RTS threshold are disabled by default with the
     * special -1 value.
     */
    rdev->wiphy.retry_short = 7;
    rdev->wiphy.retry_long = 4;
    rdev->wiphy.frag_threshold = (u32) -1;
    rdev->wiphy.rts_threshold = (u32) -1;
    rdev->wiphy.coverage_class = 0;
    rdev->wiphy.features = NL80211_FEATURE_SCAN_FLUSH;
    return &rdev->wiphy;
}

wiphy_register

int wiphy_register(struct wiphy *wiphy)
{
    struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
    int res;
    enum ieee80211_band band;
    struct ieee80211_supported_band *sband;
    bool have_band = false;
    int i;
    u16 ifmodes = wiphy->interface_modes;
#ifdef CONFIG_PM
    if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) &&
            !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
        return -EINVAL;
#endif
    if (WARN_ON(wiphy->ap_sme_capa &&
            !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
        return -EINVAL;
    if (WARN_ON(wiphy->addresses && !wiphy->n_addresses))
        return -EINVAL;
    if (WARN_ON(wiphy->addresses &&
            !is_zero_ether_addr(wiphy->perm_addr) &&
            memcmp(wiphy->perm_addr, wiphy->addresses[0].addr,
               ETH_ALEN)))
        return -EINVAL;
    if (WARN_ON(wiphy->max_acl_mac_addrs &&
            (!(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME) ||
             !rdev->ops->set_mac_acl)))
        return -EINVAL;
    if (wiphy->addresses)
        memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);
    /* sanity check ifmodes */
    WARN_ON(!ifmodes);
    ifmodes &= ((1 << NUM_NL80211_IFTYPES) - 1) & ~1;
    if (WARN_ON(ifmodes != wiphy->interface_modes))
        wiphy->interface_modes = ifmodes;
    res = wiphy_verify_combinations(wiphy);
    if (res)
        return res;
    /* sanity check supported bands/channels */
    for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
        sband = wiphy->bands[band];
        if (!sband)
            continue;
        sband->band = band;
        if (WARN_ON(!sband->n_channels))
            return -EINVAL;
        /*
        request.wiphy_idx = get_wiphy_idx(wiphy);
        request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
        request.alpha2[0] = '9';
        request.alpha2[1] = '9';
        nl80211_send_reg_change_event(&request);
    }
    cfg80211_debugfs_rdev_add(rdev);
    mutex_unlock(&cfg80211_mutex);
    /*
     * due to a locking dependency this has to be outside of the
     * cfg80211_mutex lock
     */
    res = rfkill_register(rdev->rfkill);
    if (res)
        goto out_rm_dev;
    rtnl_lock();
    rdev->wiphy.registered = true;
    rtnl_unlock();
    return 0;
out_rm_dev:
    device_del(&rdev->wiphy.dev);
    return res;
}

整个代码并不复杂,wiphy_new分配rdev结构(包括wiphy和driver需要的私有结构的空间),初始化了相关rdev中维护相关资源,剩下的就交给driver去完成。而wiphy_register中首先检查了driver是否完成了必要的设置,接着向系统注册设备,最终针对regulatory和rfkill做了一些默认配置。

高通的wlan驱动里也是这么干的,我们可以看一下:

这也是我一个倒查的过程。在驱动注册开始一步步的调用,最后会调用wiphy_register函数。

nl80211

nl80211是基于generic netlink的,netlink是基于socket的一个协议族,常常用于应用层和linux内核的通信,也可以用于IPC,使用netlink的协议有netfilter等等,generic netlink是为了方便使用netlink而定义的一个协议,generic netlink定义了familycmd的概念。

nl80211使用genl,定义了一组特定的cmd以及对应的attr组,在wpa_supplicant端和cfg80211端维护相同的一组接口,用于传输对wifi的控制命令。

/**
 * enum nl80211_commands - supported nl80211 commands
 *
 * @NL80211_CMD_UNSPEC: unspecified command to catch errors
 *
 * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
 *  to get a list of all present wiphys.
 * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
 *  %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
 *  %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the
 *  attributes determining the channel width; this is used for setting
 *  monitor mode channel),  %NL80211_ATTR_WIPHY_RETRY_SHORT,
 *  %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
 *  and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
 *  However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
 *  instead, the support here is for backward compatibility only.
 * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
 *  or rename notification. Has attributes %NL80211_ATTR_WIPHY and
 *  %NL80211_ATTR_WIPHY_NAME.
 * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes
 *  %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
 *
 * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
 *  either a dump request on a %NL80211_ATTR_WIPHY or a specific get
 *  on an %NL80211_ATTR_IFINDEX is supported.
 * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
 *  %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
 * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
 *  to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
 *  %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
 *  be sent from userspace to request creation of a new virtual interface,
 *  then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and
 *  %NL80211_ATTR_IFNAME.
 * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
 *  %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
 *  userspace to request deletion of a virtual interface, then requires
 *  attribute %NL80211_ATTR_IFINDEX.
 *
 * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
 *  by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
 * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
 *  %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
 * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
 *  %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER,
 *  and %NL80211_ATTR_KEY_SEQ attributes.
 * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
 *  or %NL80211_ATTR_MAC.
 *
 * @NL80211_CMD_GET_BEACON: (not used)
 * @NL80211_CMD_SET_BEACON: change the beacon on an access point interface
 *  using the %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL
 *  attributes. For drivers that generate the beacon and probe responses
 *  internally, the following attributes must be provided: %NL80211_ATTR_IE,
 *  %NL80211_ATTR_IE_PROBE_RESP and %NL80211_ATTR_IE_ASSOC_RESP.
 * @NL80211_CMD_START_AP: Start AP operation on an AP interface, parameters
 *  are like for %NL80211_CMD_SET_BEACON, and additionally parameters that
 *  do not change are used, these include %NL80211_ATTR_BEACON_INTERVAL,
 *  %NL80211_ATTR_DTIM_PERIOD, %NL80211_ATTR_SSID,
 *  %NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
 *  %NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
 *  %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
 *  %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT,
 *  %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS.
 *  The channel to use can be set on the interface or be given using the
 *  %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
 * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
 * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
 * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
 *
 * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
 *  %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
 * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
 *  %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
 * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
 *  the interface identified by %NL80211_ATTR_IFINDEX.
 * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
 *  or, if no MAC address given, all stations, on the interface identified
 *  by %NL80211_ATTR_IFINDEX.
 *
 * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
 *  destination %NL80211_ATTR_MAC on the interface identified by
 *  %NL80211_ATTR_IFINDEX.
 * @NL80211_CMD_SET_MPATH:  Set mesh path attributes for mesh path to
 *  destination %NL80211_ATTR_MAC on the interface identified by
 *  %NL80211_ATTR_IFINDEX.
 * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by
 *  %NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP.
 * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by
 *  %NL80211_ATTR_MAC.
 * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
 *  the interface identified by %NL80211_ATTR_IFINDEX.
 * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
 *  or, if no MAC address given, all mesh paths, on the interface identified
 *  by %NL80211_ATTR_IFINDEX.
 * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
 *  %NL80211_ATTR_IFINDEX.
 *
 * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
 *  regulatory domain.
 * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
 *  after being queried by the kernel. CRDA replies by sending a regulatory
 *  domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
 *  current alpha2 if it found a match. It also provides
 *  NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
 *  regulatory rule is a nested set of attributes  given by
 *  %NL80211_ATTR_REG_RULE_FREQ_[START|END] and
 *  %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
 *  %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
 *  %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
 * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
 *  to the specified ISO/IEC 3166-1 alpha2 country code. The core will
 *  store this as a valid request and then query userspace for it.
 *
 * @NL80211_CMD_GET_MESH_CONFIG: Get mesh networking properties for the
 *  interface identified by %NL80211_ATTR_IFINDEX
 *
 * @NL80211_CMD_SET_MESH_CONFIG: Set mesh networking properties for the
 *      interface identified by %NL80211_ATTR_IFINDEX
 *
 * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
 *  interface is identified with %NL80211_ATTR_IFINDEX and the management
 *  frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be
 *  added to the end of the specified management frame is specified with
 *  %NL80211_ATTR_IE. If the command succeeds, the requested data will be
 *  added to all specified management frames generated by
 *  kernel/firmware/driver.
 *  Note: This command has been removed and it is only reserved at this
 *  point to avoid re-using existing command number. The functionality this
 *  command was planned for has been provided with cleaner design with the
 *  option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN,
 *  NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE,
 *  NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE.
 *
 * @NL80211_CMD_GET_SCAN: get scan results
 * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
 *  %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
 *  probe requests at CCK rate or not.
 * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
 *  NL80211_CMD_GET_SCAN and on the "scan" multicast group)
 * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
 *  partial scan results may be available
 *
 * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain
 *  intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL.
 *  Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS)
 *  are passed, they are used in the probe requests.  For
 *  broadcast, a broadcast SSID must be passed (ie. an empty
 *  string).  If no SSID is passed, no probe requests are sent and
 *  a passive scan is performed.  %NL80211_ATTR_SCAN_FREQUENCIES,
 *  if passed, define which channels should be scanned; if not
 *  passed, all channels allowed for the current regulatory domain
 *  are used.  Extra IEs can also be passed from the userspace by
 *  using the %NL80211_ATTR_IE attribute.
 * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan.  Returns -ENOENT
 *  if scheduled scan is not running.
 * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan
 *  results available.
 * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has
 *  stopped.  The driver may issue this event at any time during a
 *  scheduled scan.  One reason for stopping the scan is if the hardware
 *  does not support starting an association or a normal scan while running
 *  a scheduled scan.  This event is also sent when the
 *  %NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface
 *  is brought down while a scheduled scan was running.
 *
 * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
 *      or noise level
 * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
 *  NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
 *
 * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC
 *  (for the BSSID) and %NL80211_ATTR_PMKID.
 * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC
 *  (for the BSSID) and %NL80211_ATTR_PMKID.
 * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries.
 *
 * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
 *  has been changed and provides details of the request information
 *  that caused the change such as who initiated the regulatory request
 *  (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx
 *  (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if
 *  the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or
 *  %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain
 *  set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
 *  %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
 *  to (%NL80211_ATTR_REG_ALPHA2).
 * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon
 *  has been found while world roaming thus enabling active scan or
 *  any mode of operation that initiates TX (beacons) on a channel
 *  where we would not have been able to do either before. As an example
 *  if you are world roaming (regulatory domain set to world or if your
 *  driver is using a custom world roaming regulatory domain) and while
 *  doing a passive scan on the 5 GHz band you find an AP there (if not
 *  on a DFS channel) you will now be able to actively scan for that AP
 *  or use AP mode on your card on that same channel. Note that this will
 *  never be used for channels 1-11 on the 2 GHz band as they are always
 *  enabled world wide. This beacon hint is only sent if your device had
 *  either disabled active scanning or beaconing on a channel. We send to
 *  userspace the wiphy on which we removed a restriction from
 *  (%NL80211_ATTR_WIPHY) and the channel on which this occurred
 *  before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER)
 *  the beacon hint was processed.
 *
 * @NL80211_CMD_AUTHENTICATE: authentication request and notification.
 *  This command is used both as a command (request to authenticate) and
 *  as an event on the "mlme" multicast group indicating completion of the
 *  authentication process.
 *  When used as a command, %NL80211_ATTR_IFINDEX is used to identify the
 *  interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
 *  BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
 *  the SSID (mainly for association, but is included in authentication
 *  request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
 *  to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
 *  is used to specify the authentication type. %NL80211_ATTR_IE is used to
 *  define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
 *  to be added to the frame.
 *  When used as an event, this reports reception of an Authentication
 *  frame in station and IBSS modes when the local MLME processed the
 *  frame, i.e., it was for the local STA and was received in correct
 *  state. This is similar to MLME-AUTHENTICATE.confirm primitive in the
 *  MLME SAP interface (kernel providing MLME, userspace SME). The
 *  included %NL80211_ATTR_FRAME attribute contains the management frame
 *  (including both the header and frame body, but not FCS). This event is
 *  also used to indicate if the authentication attempt timed out. In that
 *  case the %NL80211_ATTR_FRAME attribute is replaced with a
 *  %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which
 *  pending authentication timed out).
 * @NL80211_CMD_ASSOCIATE: association request and notification; like
 *  NL80211_CMD_AUTHENTICATE but for Association and Reassociation
 *  (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request,
 *  MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives).
 * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
 *  NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
 *  MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
 *  primitives).
 * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like
 *  NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
 *  MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives).
 *
 * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael
 *  MIC (part of TKIP) failure; sent on the "mlme" multicast group; the
 *  event includes %NL80211_ATTR_MAC to describe the source MAC address of
 *  the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key
 *  type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and
 *  %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this
 *  event matches with MLME-MICHAELMICFAILURE.indication() primitive
 *
 * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a
 *  FREQ attribute (for the initial frequency if no peer can be found)
 *  and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those
 *  should be fixed rather than automatically determined. Can only be
 *  executed on a network interface that is UP, and fixed BSSID/FREQ
 *  may be rejected. Another optional parameter is the beacon interval,
 *  given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not
 *  given defaults to 100 TU (102.4ms).
 * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
 *  determined by the network interface.
 *
 * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute
 *  to identify the device, and the TESTDATA blob attribute to pass through
 *  to the driver.
 *
 * @NL80211_CMD_CONNECT: connection request and notification; this command
 *  requests to connect to a specified network but without separating
 *  auth and assoc steps. For this, you need to specify the SSID in a
 *  %NL80211_ATTR_SSID attribute, and can optionally specify the association
 *  IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP,
 *  %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT,
 *  %NL80211_ATTR_CONTROL_PORT_ETHERTYPE and
 *  %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT.
 *  Background scan period can optionally be
 *  specified in %NL80211_ATTR_BG_SCAN_PERIOD,
 *  if not specified default background scan configuration
 *  in driver is used and if period value is 0, bg scan will be disabled.
 *  This attribute is ignored if driver does not support roam scan.
 *  It is also sent as an event, with the BSSID and response IEs when the
 *  connection is established or failed to be established. This can be
 *  determined by the STATUS_CODE attribute.
 * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
 *  sent as an event when the card/driver roamed by itself.
 * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
 *  userspace that a connection was dropped by the AP or due to other
 *  reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
 *  %NL80211_ATTR_REASON_CODE attributes are used.
 *
 * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
 *  associated with this wiphy must be down and will follow.
 *
 * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified
 *  channel for the specified amount of time. This can be used to do
 *  off-channel operations like transmit a Public Action frame and wait for
 *  a response while being associated to an AP on another channel.
 *  %NL80211_ATTR_IFINDEX is used to specify which interface (and thus
 *  radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
 *  frequency for the operation.
 *  %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
 *  to remain on the channel. This command is also used as an event to
 *  notify when the requested duration starts (it may take a while for the
 *  driver to schedule this time due to other concurrent needs for the
 *  radio).
 *  When called, this operation returns a cookie (%NL80211_ATTR_COOKIE)
 *  that will be included with any events pertaining to this request;
 *  the cookie is also used to cancel the request.
 * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a
 *  pending remain-on-channel duration if the desired operation has been
 *  completed prior to expiration of the originally requested duration.
 *  %NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the
 *  radio. The %NL80211_ATTR_COOKIE attribute must be given as well to
 *  uniquely identify the request.
 *  This command is also used as an event to notify when a requested
 *  remain-on-channel duration has expired.
 *
 * @NL80211_CMD_SET_TX_BITRATE_MASK: Set the mask of rates to be used in TX
 *  rate selection. %NL80211_ATTR_IFINDEX is used to specify the interface
 *  and @NL80211_ATTR_TX_RATES the set of allowed rates.
 *
 * @NL80211_CMD_REGISTER_FRAME: Register for receiving certain mgmt frames
 *  (via @NL80211_CMD_FRAME) for processing in userspace. This command
 *  requires an interface index, a frame type attribute (optional for
 *  backward compatibility reasons, if not given assumes action frames)
 *  and a match attribute containing the first few bytes of the frame
 *  that should match, e.g. a single byte for only a category match or
 *  four bytes for vendor frames including the OUI. The registration
 *  cannot be dropped, but is removed automatically when the netlink
 *  socket is closed. Multiple registrations can be made.
 * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for
 *  backward compatibility
 * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This
 *  command is used both as a request to transmit a management frame and
 *  as an event indicating reception of a frame that was not processed in
 *  kernel code, but is for us (i.e., which may need to be processed in a
 *  user space application). %NL80211_ATTR_FRAME is used to specify the
 *  frame contents (including header). %NL80211_ATTR_WIPHY_FREQ is used
 *  to indicate on which channel the frame is to be transmitted or was
 *  received. If this channel is not the current channel (remain-on-channel
 *  or the operational channel) the device will switch to the given channel
 *  and transmit the frame, optionally waiting for a response for the time
 *  specified using %NL80211_ATTR_DURATION. When called, this operation
 *  returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
 *  TX status event pertaining to the TX request.
 *  %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
 *  management frames at CCK rate or not in 2GHz band.
 * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
 *  command may be used with the corresponding cookie to cancel the wait
 *  time if it is known that it is no longer necessary.
 * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
 * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
 *  transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
 *  the TX command and %NL80211_ATTR_FRAME includes the contents of the
 *  frame. %NL80211_ATTR_ACK flag is included if the recipient acknowledged
 *  the frame.
 * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for
 *  backward compatibility.
 *
 * @NL80211_CMD_SET_POWER_SAVE: Set powersave, using %NL80211_ATTR_PS_STATE
 * @NL80211_CMD_GET_POWER_SAVE: Get powersave status in %NL80211_ATTR_PS_STATE
 *
 * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command
 *  is used to configure connection quality monitoring notification trigger
 *  levels.
 * @NL80211_CMD_NOTIFY_CQM: Connection quality monitor notification. This
 *  command is used as an event to indicate the that a trigger level was
 *  reached.
 * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
 *  and the attributes determining channel width) the given interface
 *  (identifed by %NL80211_ATTR_IFINDEX) shall operate on.
 *  In case multiple channels are supported by the device, the mechanism
 *  with which it switches channels is implementation-defined.
 *  When a monitor interface is given, it can only switch channel while
 *  no other interfaces are operating to avoid disturbing the operation
 *  of any other interfaces, and other interfaces will again take
 *  precedence when they are used.
 *
 * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
 *
 * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
 *  mesh config parameters may be given.
 * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
 *  network is determined by the network interface.
 *
 * @NL80211_CMD_UNPROT_DEAUTHENTICATE: Unprotected deauthentication frame
 *  notification. This event is used to indicate that an unprotected
 *  deauthentication frame was dropped when MFP is in use.
 * @NL80211_CMD_UNPROT_DISASSOCIATE: Unprotected disassociation frame
 *  notification. This event is used to indicate that an unprotected
 *  disassociation frame was dropped when MFP is in use.
 *
 * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
 *      beacon or probe response from a compatible mesh peer.  This is only
 *      sent while no station information (sta_info) exists for the new peer
 *      candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set.  On
 *      reception of this notification, userspace may decide to create a new
 *      station (@NL80211_CMD_NEW_STATION).  To stop this notification from
 *      reoccurring, the userspace authentication daemon may want to create the
 *      new station with the AUTHENTICATED flag unset and maybe change it later
 *      depending on the authentication result.
 *
 * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings.
 * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings.
 *  Since wireless is more complex than wired ethernet, it supports
 *  various triggers. These triggers can be configured through this
 *  command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
 *  more background information, see
 *  http://wireless.kernel.org/en/users/Documentation/WoWLAN.
 *  The @NL80211_CMD_SET_WOWLAN command can also be used as a notification
 *  from the driver reporting the wakeup reason. In this case, the
 *  @NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason
 *  for the wakeup, if it was caused by wireless. If it is not present
 *  in the wakeup notification, the wireless device didn't cause the
 *  wakeup but reports that it was woken up.
 *
 * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
 *  the necessary information for supporting GTK rekey offload. This
 *  feature is typically used during WoWLAN. The configuration data
 *  is contained in %NL80211_ATTR_REKEY_DATA (which is nested and
 *  contains the data in sub-attributes). After rekeying happened,
 *  this command may also be sent by the driver as an MLME event to
 *  inform userspace of the new replay counter.
 *
 * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
 *  of PMKSA caching dandidates.
 *
 * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
 *  In addition, this can be used as an event to request userspace to take
 *  actions on TDLS links (set up a new link or tear down an existing one).
 *  In such events, %NL80211_ATTR_TDLS_OPERATION indicates the requested
 *  operation, %NL80211_ATTR_MAC contains the peer MAC address, and
 *  %NL80211_ATTR_REASON_CODE the reason code to be used (only with
 *  %NL80211_TDLS_TEARDOWN).
 * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
 *
 * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
 *  (or GO) interface (i.e. hostapd) to ask for unexpected frames to
 *  implement sending deauth to stations that send unexpected class 3
 *  frames. Also used as the event sent by the kernel when such a frame
 *  is received.
 *  For the event, the %NL80211_ATTR_MAC attribute carries the TA and
 *  other attributes like the interface index are present.
 *  If used as the command it must have an interface index and you can
 *  only unsubscribe from the event by closing the socket. Subscription
 *  is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events.
 *
 * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the
 *  associated station identified by %NL80211_ATTR_MAC sent a 4addr frame
 *  and wasn't already in a 4-addr VLAN. The event will be sent similarly
 *  to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener.
 *
 * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
 *  by sending a null data frame to it and reporting when the frame is
 *  acknowleged. This is used to allow timing out inactive clients. Uses
 *  %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
 *  direct reply with an %NL80211_ATTR_COOKIE that is later used to match
 *  up the event with the request. The event includes the same data and
 *  has %NL80211_ATTR_ACK set if the frame was ACKed.
 *
 * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
 *  other BSSes when any interfaces are in AP mode. This helps implement
 *  OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
 *  messages. Note that per PHY only one application may register.
 *
 * @NL80211_CMD_SET_NOACK_MAP: sets a bitmap for the individual TIDs whether
 *      No Acknowledgement Policy should be applied.
 *
 * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
 *  independently of the userspace SME, send this event indicating
 *  %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the
 *  attributes determining channel width.
 *
 * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
 *  its %NL80211_ATTR_WDEV identifier. It must have been created with
 *  %NL80211_CMD_NEW_INTERFACE previously. After it has been started, the
 *  P2P Device can be used for P2P operations, e.g. remain-on-channel and
 *  public action frame TX.
 * @NL80211_CMD_STOP_P2P_DEVICE: Stop the given P2P Device, identified by
 *  its %NL80211_ATTR_WDEV identifier.
 *
 * @NL80211_CMD_CONN_FAILED: connection request to an AP failed; used to
 *  notify userspace that AP has rejected the connection request from a
 *  station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON
 *  is used for this.
 *
 * @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames
 *  for IBSS or MESH vif.
 *
 * @NL80211_CMD_SET_MAC_ACL: sets ACL for MAC address based access control.
 *  This is to be used with the drivers advertising the support of MAC
 *  address based access control. List of MAC addresses is passed in
 *  %NL80211_ATTR_MAC_ADDRS and ACL policy is passed in
 *  %NL80211_ATTR_ACL_POLICY. Driver will enable ACL with this list, if it
 *  is not already done. The new list will replace any existing list. Driver
 *  will clear its ACL when the list of MAC addresses passed is empty. This
 *  command is used in AP/P2P GO mode. Driver has to make sure to clear its
 *  ACL list during %NL80211_CMD_STOP_AP.
 *
 * @NL80211_CMD_RADAR_DETECT: Start a Channel availability check (CAC). Once
 *  a radar is detected or the channel availability scan (CAC) has finished
 *  or was aborted, or a radar was detected, usermode will be notified with
 *  this event. This command is also used to notify userspace about radars
 *  while operating on this channel.
 *  %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the
 *  event.
 *
 * @NL80211_CMD_MAX: highest used command number
 * @__NL80211_CMD_AFTER_LAST: internal use
 */
enum nl80211_commands {
/* don't change the order or add anything between, this is ABI! */
    NL80211_CMD_UNSPEC,

    NL80211_CMD_GET_WIPHY,      /* can dump */
    NL80211_CMD_SET_WIPHY,
    NL80211_CMD_NEW_WIPHY,
    NL80211_CMD_DEL_WIPHY,

    NL80211_CMD_GET_INTERFACE,  /* can dump */
    NL80211_CMD_SET_INTERFACE,
    NL80211_CMD_NEW_INTERFACE,
    NL80211_CMD_DEL_INTERFACE,

    NL80211_CMD_GET_KEY,
    NL80211_CMD_SET_KEY,
    NL80211_CMD_NEW_KEY,
    NL80211_CMD_DEL_KEY,

    NL80211_CMD_GET_BEACON,
    NL80211_CMD_SET_BEACON,
    NL80211_CMD_START_AP,
    NL80211_CMD_NEW_BEACON = NL80211_CMD_START_AP,
    NL80211_CMD_STOP_AP,
    NL80211_CMD_DEL_BEACON = NL80211_CMD_STOP_AP,

    NL80211_CMD_GET_STATION,
    NL80211_CMD_SET_STATION,
    NL80211_CMD_NEW_STATION,
    NL80211_CMD_DEL_STATION,

    NL80211_CMD_GET_MPATH,
    NL80211_CMD_SET_MPATH,
    NL80211_CMD_NEW_MPATH,
    NL80211_CMD_DEL_MPATH,

    NL80211_CMD_SET_BSS,

    NL80211_CMD_SET_REG,
    NL80211_CMD_REQ_SET_REG,

    NL80211_CMD_GET_MESH_CONFIG,
    NL80211_CMD_SET_MESH_CONFIG,

    NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,

    NL80211_CMD_GET_REG,

    NL80211_CMD_GET_SCAN,
    NL80211_CMD_TRIGGER_SCAN,
    NL80211_CMD_NEW_SCAN_RESULTS,
    NL80211_CMD_SCAN_ABORTED,

    NL80211_CMD_REG_CHANGE,

    NL80211_CMD_AUTHENTICATE,
    NL80211_CMD_ASSOCIATE,
    NL80211_CMD_DEAUTHENTICATE,
    NL80211_CMD_DISASSOCIATE,

    NL80211_CMD_MICHAEL_MIC_FAILURE,

    NL80211_CMD_REG_BEACON_HINT,

    NL80211_CMD_JOIN_IBSS,
    NL80211_CMD_LEAVE_IBSS,

    NL80211_CMD_TESTMODE,

    NL80211_CMD_CONNECT,
    NL80211_CMD_ROAM,
    NL80211_CMD_DISCONNECT,

    NL80211_CMD_SET_WIPHY_NETNS,

    NL80211_CMD_GET_SURVEY,
    NL80211_CMD_NEW_SURVEY_RESULTS,

    NL80211_CMD_SET_PMKSA,
    NL80211_CMD_DEL_PMKSA,
    NL80211_CMD_FLUSH_PMKSA,

    NL80211_CMD_REMAIN_ON_CHANNEL,
    NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,

    NL80211_CMD_SET_TX_BITRATE_MASK,

    NL80211_CMD_REGISTER_FRAME,
    NL80211_CMD_REGISTER_ACTION = NL80211_CMD_REGISTER_FRAME,
    NL80211_CMD_FRAME,
    NL80211_CMD_ACTION = NL80211_CMD_FRAME,
    NL80211_CMD_FRAME_TX_STATUS,
    NL80211_CMD_ACTION_TX_STATUS = NL80211_CMD_FRAME_TX_STATUS,

    NL80211_CMD_SET_POWER_SAVE,
    NL80211_CMD_GET_POWER_SAVE,

    NL80211_CMD_SET_CQM,
    NL80211_CMD_NOTIFY_CQM,

    NL80211_CMD_SET_CHANNEL,
    NL80211_CMD_SET_WDS_PEER,

    NL80211_CMD_FRAME_WAIT_CANCEL,

    NL80211_CMD_JOIN_MESH,
    NL80211_CMD_LEAVE_MESH,

    NL80211_CMD_UNPROT_DEAUTHENTICATE,
    NL80211_CMD_UNPROT_DISASSOCIATE,

    NL80211_CMD_NEW_PEER_CANDIDATE,

    NL80211_CMD_GET_WOWLAN,
    NL80211_CMD_SET_WOWLAN,

    NL80211_CMD_START_SCHED_SCAN,
    NL80211_CMD_STOP_SCHED_SCAN,
    NL80211_CMD_SCHED_SCAN_RESULTS,
    NL80211_CMD_SCHED_SCAN_STOPPED,

    NL80211_CMD_SET_REKEY_OFFLOAD,

    NL80211_CMD_PMKSA_CANDIDATE,

    NL80211_CMD_TDLS_OPER,
    NL80211_CMD_TDLS_MGMT,

    NL80211_CMD_UNEXPECTED_FRAME,

    NL80211_CMD_PROBE_CLIENT,

    NL80211_CMD_REGISTER_BEACONS,

    NL80211_CMD_UNEXPECTED_4ADDR_FRAME,

    NL80211_CMD_SET_NOACK_MAP,

    NL80211_CMD_CH_SWITCH_NOTIFY,

    NL80211_CMD_START_P2P_DEVICE,
    NL80211_CMD_STOP_P2P_DEVICE,

    NL80211_CMD_CONN_FAILED,

    NL80211_CMD_SET_MCAST_RATE,

    NL80211_CMD_SET_MAC_ACL,

    NL80211_CMD_RADAR_DETECT,

    /* add new commands above here */

    /* used to define NL80211_CMD_MAX below */
    __NL80211_CMD_AFTER_LAST,
    NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
};

cfg80211_ops

cfg80211_ops是由驱动或者mac80211cfg80211注册的一组操作函数,它实现了管理WiFi链路的操作。cfg80211不要求实现其中的全部功能,驱动可以根据硬件的实际情况决定实现哪些功能。

/**
 * struct cfg80211_ops - backend description for wireless configuration
 *
 * This struct is registered by fullmac card drivers and/or wireless stacks
 * in order to handle configuration requests on their interfaces.
 *
 * All callbacks except where otherwise noted should return 0
 * on success or a negative error code.
 *
 * All operations are currently invoked under rtnl for consistency with the
 * wireless extensions but this is subject to reevaluation as soon as this
 * code is used more widely and we have a first user without wext.
 *
 * @suspend: wiphy device needs to be suspended. The variable @wow will
 *  be %NULL or contain the enabled Wake-on-Wireless triggers that are
 *  configured for the device.
 * @resume: wiphy device needs to be resumed
 * @set_wakeup: Called when WoWLAN is enabled/disabled, use this callback
 *  to call device_set_wakeup_enable() to enable/disable wakeup from
 *  the device.
 *
 * @add_virtual_intf: create a new virtual interface with the given name,
 *  must set the struct wireless_dev's iftype. Beware: You must create
 *  the new netdev in the wiphy's network namespace! Returns the struct
 *  wireless_dev, or an ERR_PTR. For P2P device wdevs, the driver must
 *  also set the address member in the wdev.
 *
 * @del_virtual_intf: remove the virtual interface
 *
 * @change_virtual_intf: change type/configuration of virtual interface,
 *  keep the struct wireless_dev's iftype updated.
 *
 * @add_key: add a key with the given parameters. @mac_addr will be %NULL
 *  when adding a group key.
 *
 * @get_key: get information about the key with the given parameters.
 *  @mac_addr will be %NULL when requesting information for a group
 *  key. All pointers given to the @callback function need not be valid
 *  after it returns. This function should return an error if it is
 *  not possible to retrieve the key, -ENOENT if it doesn't exist.
 *
 * @del_key: remove a key given the @mac_addr (%NULL for a group key)
 *  and @key_index, return -ENOENT if the key doesn't exist.
 *
 * @set_default_key: set the default key on an interface
 *
 * @set_default_mgmt_key: set the default management frame key on an interface
 *
 * @set_rekey_data: give the data necessary for GTK rekeying to the driver
 *
 * @start_ap: Start acting in AP mode defined by the parameters.
 * @change_beacon: Change the beacon parameters for an access point mode
 *  interface. This should reject the call when AP mode wasn't started.
 * @stop_ap: Stop being an AP, including stopping beaconing.
 *
 * @add_station: Add a new station.
 * @del_station: Remove a station; @mac may be NULL to remove all stations.
 * @change_station: Modify a given station. Note that flags changes are not much
 *  validated in cfg80211, in particular the auth/assoc/authorized flags
 *  might come to the driver in invalid combinations -- make sure to check
 *  them, also against the existing state! Also, supported_rates changes are
 *  not checked in station mode -- drivers need to reject (or ignore) them
 *  for anything but TDLS peers.
 * @get_station: get station information for the station identified by @mac
 * @dump_station: dump station callback -- resume dump at index @idx
 *
 * @add_mpath: add a fixed mesh path
 * @del_mpath: delete a given mesh path
 * @change_mpath: change a given mesh path
 * @get_mpath: get a mesh path for the given parameters
 * @dump_mpath: dump mesh path callback -- resume dump at index @idx
 * @join_mesh: join the mesh network with the specified parameters
 * @leave_mesh: leave the current mesh network
 *
 * @get_mesh_config: Get the current mesh configuration
 *
 * @update_mesh_config: Update mesh parameters on a running mesh.
 *  The mask is a bitfield which tells us which parameters to
 *  set, and which to leave alone.
 *
 * @change_bss: Modify parameters for a given BSS.
 *
 * @set_txq_params: Set TX queue parameters
 *
 * @libertas_set_mesh_channel: Only for backward compatibility for libertas,
 *  as it doesn't implement join_mesh and needs to set the channel to
 *  join the mesh instead.
 *
 * @set_monitor_channel: Set the monitor mode channel for the device. If other
 *  interfaces are active this callback should reject the configuration.
 *  If no interfaces are active or the device is down, the channel should
 *  be stored for when a monitor interface becomes active.
 *
 * @scan: Request to do a scan. If returning zero, the scan request is given
 *  the driver, and will be valid until passed to cfg80211_scan_done().
 *  For scan results, call cfg80211_inform_bss(); you can call this outside
 *  the scan/scan_done bracket too.
 *
 * @auth: Request to authenticate with the specified peer
 * @assoc: Request to (re)associate with the specified peer
 * @deauth: Request to deauthenticate from the specified peer
 * @disassoc: Request to disassociate from the specified peer
 *
 * @connect: Connect to the ESS with the specified parameters. When connected,
 *  call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS.
 *  If the connection fails for some reason, call cfg80211_connect_result()
 *  with the status from the AP.
 * @disconnect: Disconnect from the BSS/ESS.
 *
 * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call
 *  cfg80211_ibss_joined(), also call that function when changing BSSID due
 *  to a merge.
 * @leave_ibss: Leave the IBSS.
 *
 * @set_mcast_rate: Set the specified multicast rate (only if vif is in ADHOC or
 *  MESH mode)
 *
 * @set_wiphy_params: Notify that wiphy parameters have changed;
 *  @changed bitfield (see &enum wiphy_params_flags) describes which values
 *  have changed. The actual parameter values are available in
 *  struct wiphy. If returning an error, no value should be changed.
 *
 * @set_tx_power: set the transmit power according to the parameters,
 *  the power passed is in mBm, to get dBm use MBM_TO_DBM(). The
 *  wdev may be %NULL if power was set for the wiphy, and will
 *  always be %NULL unless the driver supports per-vif TX power
 *  (as advertised by the nl80211 feature flag.)
 * @get_tx_power: store the current TX power into the dbm variable;
 *  return 0 if successful
 *
 * @set_wds_peer: set the WDS peer for a WDS interface
 *
 * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
 *  functions to adjust rfkill hw state
 *
 * @dump_survey: get site survey information.
 *
 * @remain_on_channel: Request the driver to remain awake on the specified
 *  channel for the specified duration to complete an off-channel
 *  operation (e.g., public action frame exchange). When the driver is
 *  ready on the requested channel, it must indicate this with an event
 *  notification by calling cfg80211_ready_on_channel().
 * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation.
 *  This allows the operation to be terminated prior to timeout based on
 *  the duration value.
 * @mgmt_tx: Transmit a management frame.
 * @mgmt_tx_cancel_wait: Cancel the wait time from transmitting a management
 *  frame on another channel
 *
 * @testmode_cmd: run a test mode command
 * @testmode_dump: Implement a test mode dump. The cb->args[2] and up may be
 *  used by the function, but 0 and 1 must not be touched. Additionally,
 *  return error codes other than -ENOBUFS and -ENOENT will terminate the
 *  dump and return to userspace with an error, so be careful. If any data
 *  was passed in from userspace then the data/len arguments will be present
 *  and point to the data contained in %NL80211_ATTR_TESTDATA.
 *
 * @set_bitrate_mask: set the bitrate mask configuration
 *
 * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac
 *  devices running firmwares capable of generating the (re) association
 *  RSN IE. It allows for faster roaming between WPA2 BSSIDs.
 * @del_pmksa: Delete a cached PMKID.
 * @flush_pmksa: Flush all cached PMKIDs.
 * @set_power_mgmt: Configure WLAN power management. A timeout value of -1
 *  allows the driver to adjust the dynamic ps timeout value.
 * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold.
 * @set_cqm_txe_config: Configure connection quality monitor TX error
 *  thresholds.
 * @sched_scan_start: Tell the driver to start a scheduled scan.
 * @sched_scan_stop: Tell the driver to stop an ongoing scheduled scan.
 *
 * @mgmt_frame_register: Notify driver that a management frame type was
 *  registered. Note that this callback may not sleep, and cannot run
 *  concurrently with itself.
 *
 * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device.
 *  Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may
 *  reject TX/RX mask combinations they cannot support by returning -EINVAL
 *  (also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX).
 *
 * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant).
 *
 * @set_ringparam: Set tx and rx ring sizes.
 *
 * @get_ringparam: Get tx and rx ring current and maximum sizes.
 *
 * @tdls_mgmt: Transmit a TDLS management frame.
 * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
 *
 * @probe_client: probe an associated client, must return a cookie that it
 *  later passes to cfg80211_probe_status().
 *
 * @set_noack_map: Set the NoAck Map for the TIDs.
 *
 * @get_et_sset_count:  Ethtool API to get string-set count.
 *  See @ethtool_ops.get_sset_count
 *
 * @get_et_stats:  Ethtool API to get a set of u64 stats.
 *  See @ethtool_ops.get_ethtool_stats
 *
 * @get_et_strings:  Ethtool API to get a set of strings to describe stats
 *  and perhaps other supported types of ethtool data-sets.
 *  See @ethtool_ops.get_strings
 *
 * @get_channel: Get the current operating channel for the virtual interface.
 *  For monitor interfaces, it should return %NULL unless there's a single
 *  current monitoring channel.
 *
 * @start_p2p_device: Start the given P2P device.
 * @stop_p2p_device: Stop the given P2P device.
 *
 * @set_mac_acl: Sets MAC address control list in AP and P2P GO mode.
 *  Parameters include ACL policy, an array of MAC address of stations
 *  and the number of MAC addresses. If there is already a list in driver
 *  this new list replaces the existing one. Driver has to clear its ACL
 *  when number of MAC addresses entries is passed as 0. Drivers which
 *  advertise the support for MAC based ACL have to implement this callback.
 *
 * @start_radar_detection: Start radar detection in the driver.
 */
struct cfg80211_ops {
    int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
    int (*resume)(struct wiphy *wiphy);
    void    (*set_wakeup)(struct wiphy *wiphy, bool enabled);

    struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy,
                          const char *name,
                          enum nl80211_iftype type,
                          u32 *flags,
                          struct vif_params *params);
    int (*del_virtual_intf)(struct wiphy *wiphy,
                    struct wireless_dev *wdev);
    int (*change_virtual_intf)(struct wiphy *wiphy,
                       struct net_device *dev,
                       enum nl80211_iftype type, u32 *flags,
                       struct vif_params *params);

    int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
               u8 key_index, bool pairwise, const u8 *mac_addr,
               struct key_params *params);
    int (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
               u8 key_index, bool pairwise, const u8 *mac_addr,
               void *cookie,
               void (*callback)(void *cookie, struct key_params*));
    int (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
               u8 key_index, bool pairwise, const u8 *mac_addr);
    int (*set_default_key)(struct wiphy *wiphy,
                   struct net_device *netdev,
                   u8 key_index, bool unicast, bool multicast);
    int (*set_default_mgmt_key)(struct wiphy *wiphy,
                    struct net_device *netdev,
                    u8 key_index);

    int (*start_ap)(struct wiphy *wiphy, struct net_device *dev,
                struct cfg80211_ap_settings *settings);
    int (*change_beacon)(struct wiphy *wiphy, struct net_device *dev,
                 struct cfg80211_beacon_data *info);
    int (*stop_ap)(struct wiphy *wiphy, struct net_device *dev);


    int (*add_station)(struct wiphy *wiphy, struct net_device *dev,
                   u8 *mac, struct station_parameters *params);
    int (*del_station)(struct wiphy *wiphy, struct net_device *dev,
                   u8 *mac);
    int (*change_station)(struct wiphy *wiphy, struct net_device *dev,
                  u8 *mac, struct station_parameters *params);
    int (*get_station)(struct wiphy *wiphy, struct net_device *dev,
                   u8 *mac, struct station_info *sinfo);
    int (*dump_station)(struct wiphy *wiphy, struct net_device *dev,
                   int idx, u8 *mac, struct station_info *sinfo);

    int (*add_mpath)(struct wiphy *wiphy, struct net_device *dev,
                   u8 *dst, u8 *next_hop);
    int (*del_mpath)(struct wiphy *wiphy, struct net_device *dev,
                   u8 *dst);
    int (*change_mpath)(struct wiphy *wiphy, struct net_device *dev,
                  u8 *dst, u8 *next_hop);
    int (*get_mpath)(struct wiphy *wiphy, struct net_device *dev,
                   u8 *dst, u8 *next_hop,
                   struct mpath_info *pinfo);
    int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev,
                   int idx, u8 *dst, u8 *next_hop,
                   struct mpath_info *pinfo);
    int (*get_mesh_config)(struct wiphy *wiphy,
                struct net_device *dev,
                struct mesh_config *conf);
    int (*update_mesh_config)(struct wiphy *wiphy,
                      struct net_device *dev, u32 mask,
                      const struct mesh_config *nconf);
    int (*join_mesh)(struct wiphy *wiphy, struct net_device *dev,
                 const struct mesh_config *conf,
                 const struct mesh_setup *setup);
    int (*leave_mesh)(struct wiphy *wiphy, struct net_device *dev);

    int (*change_bss)(struct wiphy *wiphy, struct net_device *dev,
                  struct bss_parameters *params);

    int (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
                  struct ieee80211_txq_params *params);

    int (*libertas_set_mesh_channel)(struct wiphy *wiphy,
                         struct net_device *dev,
                         struct ieee80211_channel *chan);

    int (*set_monitor_channel)(struct wiphy *wiphy,
                       struct cfg80211_chan_def *chandef);

    int (*scan)(struct wiphy *wiphy,
            struct cfg80211_scan_request *request);

    int (*auth)(struct wiphy *wiphy, struct net_device *dev,
            struct cfg80211_auth_request *req);
    int (*assoc)(struct wiphy *wiphy, struct net_device *dev,
             struct cfg80211_assoc_request *req);
    int (*deauth)(struct wiphy *wiphy, struct net_device *dev,
              struct cfg80211_deauth_request *req);
    int (*disassoc)(struct wiphy *wiphy, struct net_device *dev,
                struct cfg80211_disassoc_request *req);

    int (*connect)(struct wiphy *wiphy, struct net_device *dev,
               struct cfg80211_connect_params *sme);
    int (*disconnect)(struct wiphy *wiphy, struct net_device *dev,
                  u16 reason_code);

    int (*join_ibss)(struct wiphy *wiphy, struct net_device *dev,
                 struct cfg80211_ibss_params *params);
    int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev);

    int (*set_mcast_rate)(struct wiphy *wiphy, struct net_device *dev,
                  int rate[IEEE80211_NUM_BANDS]);

    int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed);

    int (*set_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
                enum nl80211_tx_power_setting type, int mbm);
    int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
                int *dbm);

    int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
                const u8 *addr);

    void    (*rfkill_poll)(struct wiphy *wiphy);

#ifdef CONFIG_NL80211_TESTMODE
    int (*testmode_cmd)(struct wiphy *wiphy, void *data, int len);
    int (*testmode_dump)(struct wiphy *wiphy, struct sk_buff *skb,
                 struct netlink_callback *cb,
                 void *data, int len);
#endif

    int (*set_bitrate_mask)(struct wiphy *wiphy,
                    struct net_device *dev,
                    const u8 *peer,
                    const struct cfg80211_bitrate_mask *mask);

    int (*dump_survey)(struct wiphy *wiphy, struct net_device *netdev,
            int idx, struct survey_info *info);

    int (*set_pmksa)(struct wiphy *wiphy, struct net_device *netdev,
                 struct cfg80211_pmksa *pmksa);
    int (*del_pmksa)(struct wiphy *wiphy, struct net_device *netdev,
                 struct cfg80211_pmksa *pmksa);
    int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev);

    int (*remain_on_channel)(struct wiphy *wiphy,
                     struct wireless_dev *wdev,
                     struct ieee80211_channel *chan,
                     unsigned int duration,
                     u64 *cookie);
    int (*cancel_remain_on_channel)(struct wiphy *wiphy,
                        struct wireless_dev *wdev,
                        u64 cookie);

    int (*mgmt_tx)(struct wiphy *wiphy, struct wireless_dev *wdev,
              struct ieee80211_channel *chan, bool offchan,
              unsigned int wait, const u8 *buf, size_t len,
              bool no_cck, bool dont_wait_for_ack, u64 *cookie);
    int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
                       struct wireless_dev *wdev,
                       u64 cookie);

    int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
                  bool enabled, int timeout);

    int (*set_cqm_rssi_config)(struct wiphy *wiphy,
                       struct net_device *dev,
                       s32 rssi_thold, u32 rssi_hyst);

    int (*set_cqm_txe_config)(struct wiphy *wiphy,
                      struct net_device *dev,
                      u32 rate, u32 pkts, u32 intvl);

    void    (*mgmt_frame_register)(struct wiphy *wiphy,
                       struct wireless_dev *wdev,
                       u16 frame_type, bool reg);

    int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant);
    int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant);

    int (*set_ringparam)(struct wiphy *wiphy, u32 tx, u32 rx);
    void    (*get_ringparam)(struct wiphy *wiphy,
                 u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);

    int (*sched_scan_start)(struct wiphy *wiphy,
                struct net_device *dev,
                struct cfg80211_sched_scan_request *request);
    int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev);

    int (*set_rekey_data)(struct wiphy *wiphy, struct net_device *dev,
                  struct cfg80211_gtk_rekey_data *data);

    int (*tdls_mgmt)(struct wiphy *wiphy, struct net_device *dev,
                 u8 *peer, u8 action_code,  u8 dialog_token,
                 u16 status_code, const u8 *buf, size_t len);
    int (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
                 u8 *peer, enum nl80211_tdls_operation oper);

    int (*probe_client)(struct wiphy *wiphy, struct net_device *dev,
                const u8 *peer, u64 *cookie);

    int (*set_noack_map)(struct wiphy *wiphy,
                  struct net_device *dev,
                  u16 noack_map);

    int (*get_et_sset_count)(struct wiphy *wiphy,
                     struct net_device *dev, int sset);
    void    (*get_et_stats)(struct wiphy *wiphy, struct net_device *dev,
                struct ethtool_stats *stats, u64 *data);
    void    (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev,
                  u32 sset, u8 *data);

    int (*get_channel)(struct wiphy *wiphy,
                   struct wireless_dev *wdev,
                   struct cfg80211_chan_def *chandef);

    int (*start_p2p_device)(struct wiphy *wiphy,
                    struct wireless_dev *wdev);
    void    (*stop_p2p_device)(struct wiphy *wiphy,
                   struct wireless_dev *wdev);

    int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
                   const struct cfg80211_acl_data *params);

    int (*start_radar_detection)(struct wiphy *wiphy,
                     struct net_device *dev,
                     struct cfg80211_chan_def *chandef);
};

cfg80211_ops则是由具体的驱动去注册的,比如高通,在driver_nl80211.c中就有如下的:

MLME

cfg80211本身不负责MLME的处理,管理帧的收发都是由driver或者mac80211处理的。cfg80211提供的mlme功能主要是为了通过nl80211和上层同步mlme状态,比如收到一个deauth帧,driver或者mac80211处理完毕后要通知wpa_supplicant更新状态为disassociacated。此外cfg80211也提供了一些辅助函数用于管理帧的解析。cfg80211针对MLME提供的另一个功能是将完整的管理帧上报给应用层,因为应用层的一些程序可以处理MLME,比如wpa_supplicant已经实现了MLME的处理,如果有类似需求,cfg80211提供了这样的接口。

总结

一个fullmac wifi driver(直接使用cfg80211)通常是fw/hw实现很多WiFi的功能,为了减少控制层级和冗余度而跳过mac80211,而尽快直接调用vendor specific的控制接口,同时也提供更大的灵活性。

下一章我会介绍以扫描为例从android上层一直到驱动这一连串的函数调用以及分析过程。

剑气纵横三万里

“为什么要努力?” “想去的地方很远,想要的东西很贵,喜欢的人很优秀,父母的白发,朋友的约定,周围人的嘲笑,以及,天生傲骨。”

留下你的评论

*评论支持代码高亮<pre class="prettyprint linenums">代码</pre>

相关推荐

暂无内容!