本文为《深入理解Android Wi-Fi、NFC和GPS卷》读书笔记,Android源码为Android 5.1

Linux平台上目前常用的专门针对无线网络设备编程的API有两套

最早的一套API由HP公司员工 Jean Tourrilhes于1997年开发,全称为 Linux Wireless Extensions。一般缩写为 wex 或 wext。 这套API使得用户空间的程序能通过 ioctl 函数来控制无线网卡驱动。
由于利用ioctl开展编程的方式不太符合 Linux 驱动开发的要求,后来 Linux 又提供了 cfg80211 和 nl80211 两套编程接口用于替代 wext。 其中, cfg80211 用于驱动开发,而 nl80211 API 供用户控件进程使用以操作那些利用 cfg80211 API 开发的无线网卡驱动。

Linux Wireless Extensions 介绍
所有用户空间发起的请求都统一包括在 struct iwreq 中:
android-5.1/external/kernel-headers/original/uapi/linux/wireless.h

//该结构体专门用于往socket句柄传递 ioctrl 控制参数
struct  iwreq
{union{char ifrn_name[IFNAMSIZ];    /* if name, e.g. "eth0" 用于指定要操作的网卡设备名,如 wlan0*/} ifr_ifrn;/* Data part (defined just above) */union    iwreq_data  u;  //用于存储具体的参数信息
};
union    iwreq_data
{/* Config - generic */char     name[IFNAMSIZ];/* Name : used to verify the presence of  wireless extensions.* Name of the protocol/provider... */struct iw_point   essid;      /* Extended network name */struct iw_param  nwid;       /* network id (or domain - the cell) */struct iw_freq   freq;       /* frequency or channel :* 0-1000 = channel* > 1000 = frequency in Hz */struct iw_param    sens;       /* signal level threshold */struct iw_param bitrate;    /* default bit rate */struct iw_param   txpower;    /* default transmit power */struct iw_param rts;        /* RTS threshold threshold */struct iw_param    frag;       /* Fragmentation threshold */__u32      mode;       /* Operation mode */struct iw_param retry;      /* Retry limits & lifetime */struct iw_point    encoding;   /* Encoding stuff : tokens */struct iw_param    power;      /* PM duration/timeout */struct iw_quality qual;        /* Quality part of statistics */struct sockaddr ap_addr;    /* Access point address */struct sockaddr   addr;       /* Destination address (hw/mac) */struct iw_param   param;      /* Other small parameters */struct iw_point data;       /* Other large parameters */
};

当参数信息的长度超过16字节时,就只能通过 iw_point 指向另外一块内存区域,而参数就存储在那个区域中。这就是我们常用的指针方式。

struct   iw_point
{void __user    *pointer;   /* Pointer to the data  (in user space) */__u16     length;     /* number of fields or size in bytes */__u16        flags;      /* Optional params */
};

当参数信息不超过16字节时,可以把信息存储在 iw_param 中。

struct   iw_param
{__s32      value;      /* The value of the parameter itself */__u8     fixed;      /* Hardware should not use auto select */__u8       disabled;   /* Disable the feature */__u16      flags;      /* Various specifc flags (if any) */
};

用于存储频率或信道值。
当频率小于109, m 直接等于频率。否则 m=f/(10e)

struct   iw_freq
{__s32      m;      /* Mantissa */__s16     e;      /* Exponent */__u8      i;      /* List index (when in range struct) 该值表示此频率对象在 channel_list 数组中的索引 */__u8      flags;      /* Flags (fixed/auto) 固定/自动 */
};

当参数字节超过16的时候, wext 还定义了和功能相关的参数类型:
数据结构 iw_scan_req 用于触发无线网卡发起扫描请求:

struct   iw_scan_req
{__u8       scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} 主动/被动扫描*/__u8       essid_len;__u8      num_channels; /* num entries in channel_list; 信道个数* 0 = scan all allowed channels  0 扫描所有可允许的信道 */__u8     flags; /* reserved as padding; use zero, this may* be used in the future for adding flags* to request different scan behavior */struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or* individual address of a specific BSS * bssid用于指明 BSS的地址。 如果全为 FF 则为广播 BSSID,即 wildcard bssid *//** Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using* the current ESSID. This allows scan requests for specific ESSID* without having to change the current ESSID and potentially breaking* the current association.*/__u8      essid[IW_ESSID_MAX_SIZE];/** Optional parameters for changing the default scanning behavior.* These are based on the MLME-SCAN.request from IEEE Std 802.11.* TU is 1.024 ms. If these are set to 0, driver is expected to use* reasonable default values. min_channel_time defines the time that* will be used to wait for the first reply on each channel. If no* replies are received, next channel will be scanned after this. If* replies are received, total time waited on the channel is defined by* max_channel_time.*/__u32       min_channel_time; /* in TU 表示扫描过程中在每个信道等待到第一个回复的时间。如果在此时间内没有等到回复,跳到下一个信道等待。如果等到一个回复,则一共在该信道等待的最大时间为 max_channel_time 。所有时间单位均为TU(Time Units),即1024ms。*/__u32       max_channel_time; /* in TU */struct iw_freq channel_list[IW_MAX_FREQUENCIES];//IW_MAX_FREQUENCIES = 32
};

wext API使用实例
本例来源于 wpa_supplicant ,它是一个运行于用户空间的专门和无线网卡进行交互的程序。 下面来看 wpa_supplicant 如何利用 wext API 和无线网卡交互。
android-5.1/external/wpa_supplicant_8/src/drivers/driver_wext.c

int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
{struct wpa_driver_wext_data *drv = priv;struct iwreq iwr; //定义一个 iwreq 对象int ret = 0, timeout;struct iw_scan_req req;    //定义一个 iw_scan_req 对象const u8 *ssid = params->ssids[0].ssid;size_t ssid_len = params->ssids[0].ssid_len;if (ssid_len > IW_ESSID_MAX_SIZE) {wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",__FUNCTION__, (unsigned long) ssid_len);return -1;}os_memset(&iwr, 0, sizeof(iwr));//为 iwr 的 ifr_name 传递需操作的网卡设备名os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);if (ssid && ssid_len) {os_memset(&req, 0, sizeof(req));//设置 iw_scan_req 的信息req.essid_len = ssid_len;req.bssid.sa_family = ARPHRD_ETHER;//设置 bssid 的 MAC 地址全为 0XFF, 代表这是一个 wildcard BSSID搜索os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);os_memcpy(req.essid, ssid, ssid_len);//通过 data 域指向这个 iw_scan_req 对象iwr.u.data.pointer = (caddr_t) &req;iwr.u.data.length = sizeof(req);//IW_SCAN_THIS_ESSID 表示只扫描指定ESSID的无线网络iwr.u.data.flags = IW_SCAN_THIS_ESSID;}//ioctl_sock指向一个 socket 句柄//SIOCSIWSCAN 用于通知驱动进行无线网络扫描if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {perror("ioctl[SIOCSIWSCAN]");ret = -1;}/* Not all drivers generate "scan completed" wireless event, so try to* read results after a timeout. */timeout = 10;if (drv->scan_complete_events) {/** The driver seems to deliver SIOCGIWSCAN events to notify* when scan is complete, so use longer timeout to avoid race* conditions with scanning and following association request.*/timeout = 30;}wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d ""seconds", ret, timeout);eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,drv->ctx);return ret;
}

netlink 编程
external/libnl/include/netlink/netlink.h

struct sockaddr_nl {//nl_family 取值必须为 AF_NETLINK 或 PF_NETLINK__kernel_sa_family_t nl_family;unsigned short nl_pad;   //必须为0,无用__u32 nl_pid; //看起来是存储进程pid的,但实际上它只是用于标示一个 netlink socket。所以用户空间只要保证进程内该值的唯一性即可。如果该值为0,表示通信的目标是 kernel。//每一个 netlink 协议都支持最多32个多播组,加入多播组的成员都能接收到对应的多播消息。//采用多播的方式能减少消息发送/接收的次数//nl_groups 为 0,表示只处理单播消息__u32 nl_groups;
};

nl80211 的核心就是通过 netlink 机制向 Kernel 中的无线网卡驱动发送特定的消息:
下面是通过 nl80211 触发网卡进行无线网络扫描:
android-5.1/external/wpa_supplicant_8/src/drivers/driver_nl80211.c

static int wpa_driver_nl80211_scan(struct i802_bss *bss,struct wpa_driver_scan_params *params)
{struct wpa_driver_nl80211_data *drv = bss->drv;int ret = -1, timeout;struct nl_msg *msg = NULL;wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");drv->scan_for_auth = 0;//创建 nl80211 消息,其中 NL80211_CMD_TRIGGER_SCAN 是 nl80211 定义的命令,用于触发网络扫描msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,bss->wdev_id_set ? &bss->wdev_id : NULL);if (!msg)return -1;if (params->p2p_probe) {struct nlattr *rates;wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);if (rates == NULL)goto nla_put_failure;/** Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates* by masking out everything else apart from the OFDM rates 6,* 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz* rates are left enabled.*/NLA_PUT(msg, NL80211_BAND_2GHZ, 8,"\x0c\x12\x18\x24\x30\x48\x60\x6c");nla_nest_end(msg, rates);NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);}//发送 netlink 消息ret = send_and_recv_msgs(drv, msg, NULL, NULL);msg = NULL;if (ret) {wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d ""(%s)", ret, strerror(-ret));if (drv->hostapd && is_ap_interface(drv->nlmode)) {enum nl80211_iftype old_mode = drv->nlmode;/** mac80211 does not allow scan requests in AP mode, so* try to do this in station mode.*/if (wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION))goto nla_put_failure;if (wpa_driver_nl80211_scan(bss, params)) {wpa_driver_nl80211_set_mode(bss, drv->nlmode);goto nla_put_failure;}/* Restore AP mode when processing scan results */drv->ap_scan_as_station = old_mode;ret = 0;} elsegoto nla_put_failure;}drv->scan_state = SCAN_REQUESTED;/* Not all drivers generate "scan completed" wireless event, so try to* read results after a timeout. */timeout = 10;if (drv->scan_complete_events) {/** The driver seems to deliver events to notify when scan is* complete, so use longer timeout to avoid race conditions* with scanning and following association request.*/timeout = 30;}wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d ""seconds", ret, timeout);eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,drv, drv->ctx);nla_put_failure:nlmsg_free(msg);return ret;
}

上面代码中的nl80211_scan_common
android-5.1/external/wpa_supplicant_8/src/drivers/driver_nl80211.c

static struct nl_msg *
nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,struct wpa_driver_scan_params *params, u64 *wdev_id)
{struct nl_msg *msg;size_t i;u32 scan_flags = 0;//分配一个 nl_msg 对象msg = nlmsg_alloc();if (!msg)return NULL;//nl80211_cmd 函数填充 nl_msg 信息nl80211_cmd(drv, msg, 0, cmd);if (!wdev_id)//NL80211_ATTR_IFINDEX 代表此次操作所指定的网络设备编号。NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);elseNLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);if (params->num_ssids) {struct nlattr *ssids;ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);if (ssids == NULL)goto fail;for (i = 0; i < params->num_ssids; i++) {wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",params->ssids[i].ssid,params->ssids[i].ssid_len);if (nla_put(msg, i + 1, params->ssids[i].ssid_len,params->ssids[i].ssid) < 0)goto fail;}nla_nest_end(msg, ssids);}if (params->extra_ies) {wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",params->extra_ies, params->extra_ies_len);if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,params->extra_ies) < 0)goto fail;}if (params->freqs) {struct nlattr *freqs;freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);if (freqs == NULL)goto fail;for (i = 0; params->freqs[i]; i++) {wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u ""MHz", params->freqs[i]);if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)goto fail;}nla_nest_end(msg, freqs);}os_free(drv->filter_ssids);drv->filter_ssids = params->filter_ssids;params->filter_ssids = NULL;drv->num_filter_ssids = params->num_filter_ssids;if (params->only_new_results) {wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");scan_flags |= NL80211_SCAN_FLAG_FLUSH;}if (params->low_priority && drv->have_low_prio_scan) {wpa_printf(MSG_DEBUG,"nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;}if (scan_flags)NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags);return msg;fail:
nla_put_failure:nlmsg_free(msg);return NULL;
}

nl80211_copy.h定义了 802.11 相关的命令:
android-5.1/external/wpa_supplicant_8/src/drivers/nl80211_copy.h

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,NL80211_CMD_GET_PROTOCOL_FEATURES,NL80211_CMD_UPDATE_FT_IES,NL80211_CMD_FT_EVENT,NL80211_CMD_CRIT_PROTOCOL_START,NL80211_CMD_CRIT_PROTOCOL_STOP,NL80211_CMD_GET_COALESCE,NL80211_CMD_SET_COALESCE,NL80211_CMD_CHANNEL_SWITCH,NL80211_CMD_VENDOR,NL80211_CMD_SET_QOS_MAP,NL80211_CMD_ADD_TX_TS,NL80211_CMD_DEL_TX_TS,/* add new commands above here *//* used to define NL80211_CMD_MAX below */__NL80211_CMD_AFTER_LAST,NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
};

属性的取值:

enum nl80211_attrs {
/* don't change the order or add anything inbetween, this is ABI! */NL80211_ATTR_UNSPEC,NL80211_ATTR_WIPHY,NL80211_ATTR_WIPHY_NAME,NL80211_ATTR_IFINDEX,NL80211_ATTR_IFNAME,NL80211_ATTR_IFTYPE,NL80211_ATTR_MAC,NL80211_ATTR_KEY_DATA,NL80211_ATTR_KEY_IDX,NL80211_ATTR_KEY_CIPHER,NL80211_ATTR_KEY_SEQ,NL80211_ATTR_KEY_DEFAULT,NL80211_ATTR_BEACON_INTERVAL,NL80211_ATTR_DTIM_PERIOD,NL80211_ATTR_BEACON_HEAD,NL80211_ATTR_BEACON_TAIL,NL80211_ATTR_STA_AID,NL80211_ATTR_STA_FLAGS,NL80211_ATTR_STA_LISTEN_INTERVAL,NL80211_ATTR_STA_SUPPORTED_RATES,NL80211_ATTR_STA_VLAN,NL80211_ATTR_STA_INFO,NL80211_ATTR_WIPHY_BANDS,NL80211_ATTR_MNTR_FLAGS,NL80211_ATTR_MESH_ID,NL80211_ATTR_STA_PLINK_ACTION,NL80211_ATTR_MPATH_NEXT_HOP,NL80211_ATTR_MPATH_INFO,NL80211_ATTR_BSS_CTS_PROT,NL80211_ATTR_BSS_SHORT_PREAMBLE,NL80211_ATTR_BSS_SHORT_SLOT_TIME,NL80211_ATTR_HT_CAPABILITY,NL80211_ATTR_SUPPORTED_IFTYPES,NL80211_ATTR_REG_ALPHA2,NL80211_ATTR_REG_RULES,NL80211_ATTR_MESH_PARAMS,NL80211_ATTR_BSS_BASIC_RATES,NL80211_ATTR_WIPHY_TXQ_PARAMS,NL80211_ATTR_WIPHY_FREQ,NL80211_ATTR_WIPHY_CHANNEL_TYPE,NL80211_ATTR_KEY_DEFAULT_MGMT,NL80211_ATTR_MGMT_SUBTYPE,NL80211_ATTR_IE,NL80211_ATTR_MAX_NUM_SCAN_SSIDS,NL80211_ATTR_SCAN_FREQUENCIES,NL80211_ATTR_SCAN_SSIDS,NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */NL80211_ATTR_BSS,NL80211_ATTR_REG_INITIATOR,NL80211_ATTR_REG_TYPE,NL80211_ATTR_SUPPORTED_COMMANDS,NL80211_ATTR_FRAME,NL80211_ATTR_SSID,NL80211_ATTR_AUTH_TYPE,NL80211_ATTR_REASON_CODE,NL80211_ATTR_KEY_TYPE,NL80211_ATTR_MAX_SCAN_IE_LEN,NL80211_ATTR_CIPHER_SUITES,NL80211_ATTR_FREQ_BEFORE,NL80211_ATTR_FREQ_AFTER,NL80211_ATTR_FREQ_FIXED,NL80211_ATTR_WIPHY_RETRY_SHORT,NL80211_ATTR_WIPHY_RETRY_LONG,NL80211_ATTR_WIPHY_FRAG_THRESHOLD,NL80211_ATTR_WIPHY_RTS_THRESHOLD,NL80211_ATTR_TIMED_OUT,NL80211_ATTR_USE_MFP,NL80211_ATTR_STA_FLAGS2,NL80211_ATTR_CONTROL_PORT,NL80211_ATTR_TESTDATA,NL80211_ATTR_PRIVACY,NL80211_ATTR_DISCONNECTED_BY_AP,NL80211_ATTR_STATUS_CODE,NL80211_ATTR_CIPHER_SUITES_PAIRWISE,NL80211_ATTR_CIPHER_SUITE_GROUP,NL80211_ATTR_WPA_VERSIONS,NL80211_ATTR_AKM_SUITES,NL80211_ATTR_REQ_IE,NL80211_ATTR_RESP_IE,NL80211_ATTR_PREV_BSSID,NL80211_ATTR_KEY,NL80211_ATTR_KEYS,NL80211_ATTR_PID,NL80211_ATTR_4ADDR,NL80211_ATTR_SURVEY_INFO,/* add attributes here, update the policy in nl80211.c */__NL80211_ATTR_AFTER_LAST,NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
};

Linux Wi-Fi 编程API介绍相关推荐

  1. linux shell脚本编程技巧介绍(一)

    涉及 字体颜色控制:echo,tput Here Documents $x 获取参数.变量默认值:-a xx -p xx的形式获取参数 Shell并发控制:nohup.xargs.for waite. ...

  2. Linux C高级编程——网络编程之API(5)

    Linux C网络编程--API 宗旨:技术的学习是有限的,分享的精神的无限的.          一.基本socket函数 Linux系统是通过提供套接字(socket)来进行网络编程的.网络的so ...

  3. asp.core api 通过socket和服务器通信发送udp_详解Linux的SOCKET编程

    文章来自于 https://www.zhangshengrong.com/p/9Oabd95XdK/ PHP进阶学习交流QQ群:983229225 本篇文章对Linux的SOCKET编程进行了详细解释 ...

  4. 【Linux】网络编程三:TCP通信和UDP通信介绍及代码编写

    参考连接:https://www.nowcoder.com/study/live/504/2/16. [Linux]网络编程一:网络结构模式.MAC/IP/端口.网络模型.协议及网络通信过程简单介绍 ...

  5. Linux C编程--进程介绍4--errno

    当linux中的C api函数发生异常时,一般会将errno变量(需includeerrno.h)赋一个整数值,不同的值表示不同的含义,可以通过查看该值推测出错的原因,在实际编程中用这一招解决了不少原 ...

  6. Linux内核scatterlist API介绍 DMA SG搬移

    Linux内核scatterlist API介绍 1. 前言 我们在那些需要和用户空间交互大量数据的子系统(例如MMC[1].Video.Audio等)中,经常看到scatterlist的影子.对我们 ...

  7. Linux SDIO WIFI Marvell8801/Marvell88w8801(五) --- Linux SDIO API介绍

    代码工程的GITHUB连接:点进进入GITHUB仓库 https://github.com/sj15712795029/stm32f1_marvell88w8801_marvell8801_wifi ...

  8. [转]Linux 的多线程编程的高效开发经验

    Linux 平台上的多线程程序开发相对应其他平台(比如 Windows)的多线程 API 有一些细微和隐晦的差别.不注意这些 Linux 上的一些开发陷阱,常常会导致程序问题不穷,死锁不断.本文中我们 ...

  9. 什么是Linux的原生GUI API?

    本文翻译自:What is Linux's native GUI API? I hope this doesn't come across as a stupid question but it's ...

最新文章

  1. mysql从当前月向前推12_JavaScript获取当前时间向前推三个月的方法示例
  2. 修复mysql数据库供应商_修复MYSQL数据库
  3. prometheus 基于文件的目标发现
  4. linux cp复制文件夹下的软连接,Linux培训:cp命令复制文件和目录
  5. 四种常见的MapReduce设计模式
  6. 【网址收藏】PowerShell因为在此系统中禁止执行脚本的解决方法
  7. 阅读替换净化规则_usmile电动牙刷头适配Y1/Y4/45度小白刷大理石一号刷P1替换激泡...
  8. hdu 1022 Train Problem I 解题报告
  9. android 分区修改工具_Android刷机包制作工具与教程-大神必备
  10. [.net 面向对象程序设计深入](4)MVC 6 —— 谈谈MVC的版本变迁及新版本6.0发展方向...
  11. pandas的to_csv()使用方法
  12. SVM 训练--在训练集上acc为94% 在测试集上为70%
  13. 写好规范 Java 代码去大厂!
  14. axure中怎么把图片变圆_怎么将图片中的文字提取出来?收下这份识别教程
  15. c# 拼接字符串换行_零基础小白学习:python之最详细字符串篇
  16. 前端练习-CSS布局
  17. python去除图片复杂背景_用Python去除图像的黑色或白色背景实例
  18. Mybatis001_JDBC
  19. 蘑菇街服务器信息,蘑菇街开放平台
  20. 2022-2028全球与中国紫外线点固化系统市场现状及未来发展趋势

热门文章

  1. C++ 如何获取数组的长度
  2. html style属性
  3. Unable to inject views for BcFragment{8d4c0 #1 id=0x7f0d00a1}
  4. 一些js代码,自己备用的。高手不要笑话我。。(跨浏览器基础事件,浏览器检测,判断浏览器的名称、版本号、操作系统)...
  5. 0x02 mysql 表格相关操作
  6. Spring 集成dubbo 找不到dubbo.xsd 文件的问题的想法概述
  7. Python 列表和迭代器区别
  8. 修改withdraw 方法
  9. 下一个亿万市场:企业级SaaS服务谁能独领风骚
  10. PS多形式的部分之间复制“笨办法”