wlanconfig简介
wlanconfig是madwifi无线网卡驱动中方便用户对VAP进行控制的工具。
madwifi无线网卡驱动可以基于一块物理无线网卡实现多AP或者AP/Station共存,每个Station实例或者AP实例都可以称作一个VAP,但是由于这些VAP共用了一块物理网卡,所以必须工作在同一个channel上,并且使用相同的物理层参数。用户可以通过wlanconfig工具来创建、销毁以及控制VAP。
wlanconfig命令使用
wlanconfig工具的命令使用十分简单,只有以下三种1
2
3wlanconfig athX create [nounit] wlandev wifiY wlanmode [sta|adhoc|ap|monitor|wds|ahdemo] [bssid | -bssid] [nosbeacon]
wlanconfig athX destroy
wlanconfig athX list [active|ap|caps|chan|freq|keys|scan|sta|wme]
第一条命令用来创建VAP,athX是VAP名称,可以是一个设备名全称(例如ath0),也可以只是一个前缀(例如ath),后者在未使用nounit选项时内核会自动将前缀补全成一个完整设备名,否则直接使用该字符串作为VAP名。wifiX是真实的物理网卡名,通过iwconfig可以看到,bssid选项是指使用一个与wifiX不同的mac地址来创建athX,-bssid选项表示使用一个与wifiX相同的mac地址来创建athX,最后的nosbeacon选项是在已有AP存在时建立STA时需要加上的。
VAP模式可以是以下几种模式中的一种:1
2
3
4
5
6ahdemo Create the station in ad-hoc demo (aka pseudo IBSS) mode.
adhoc Create the station in ad-hoc mode.
ap Create the VAP in AP mode.
monitor Create the station in monitor mode.
sta Create the VAP in station mode.
wds Create the station in WDS mode.
下面用几个实例来说明create命令的使用
使用以下命令可以创建一个名为athN的station(N位网络接口中未使用的athX中的最小X)1
wlanconfig ath create wlandev wifi0 wlanmode sta
使用以下命令可以创建一个名为ath0的AP1
wlanconfig ath0 create wlandev wifi0 wlanmode ap
使用以下命令可以创建AP+station共存1
2wlanconfig ath0 create wlandev wifi0 wlanmode ap
wlanconfig ath1 create wlandev wifi0 wlanmode sta nosbeacon
使用以下命令创建一个WDS网桥1
2
3
4
5
6
7
8
9
10
11wlanconfig ath0 create wlandev wifi0 wlanmode ap
wlanconfig ath1 create wlandev wifi0 wlanmode wds
iwconfig ath0 essid "madwifi" channel 1
iwpriv ath1 wds_add <mac of the peer wds ap>
iwpriv ath1 wds 1
ifconfig ath1 up
ifconfig ath0 up
brctl addbr br0
brctl addif br0 ath1
brctl addif br0 ath0
ifconfig br0 up
第二条命令用来销毁VAP,必须使用设备全名。
第三条命令用来显示VAP的一些相关信息,注意如果参数和VAP类型不符合,是不会显示任何结果的。1
2
3
4
5
6
7
8
9
10
11
12
13
14sta or no parameters.
Show information on associated stations.
scan or ap
List all visible stations.
chan or freq
List all channels and frequencies.
active
List all available channels and frequencies.
keys
List all of the keys associated with the VAP
caps
List the capabilities of the given VAP.
wme
List WME (Wireless multimedia extensions, aka WMM) parameters.
wlanconfig源码简析
wlanconfig工具的源码只有1000行左右,基本就是配置参数然后调用ioctl。
以下先给出wlanconfig中可能用到的IOCTL宏,定义在ieee80211_ioctl.h
中:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
```
对于`SIOCDEVPRIVATE`到`SIOCDEVPRIVATE+15`之间的宏,内核会调用dev->do_ioctl函数,而`do_ioctl`是由驱动来实现的,在madwifi中,如果调用设备是物理设备,则`dev->do_ioctl = ath_ioctl`,而如果调用设备是VAP,则`dev->do_ioctl = ieee80211_ioctl`。
对于`SIOCIWFIRSTPRIV`到`SIOCIWFIRSTPRIV+31`之间的宏,madwifi在`ieee80211_priv_handlers`数组中定义了每个宏对应的处理函数,这里就不深入去说了。
根据以上这些,我们基本上可以根据一个在wlanconfig中出现的ioctl操作,找到它在madwifi驱动中的处理函数了。
### **create**
首先看create操作,create操作主要填充了两个结构体:`struct ifreq req`和`struct ieee80211_clone_params cp`,`ifreq`由`ifr_name`和`ifr_data`两部分组成,其中`ifr_name`存的是物理设备的名字,比如`wifi0`,而`ifr_data`中放的就是结构体cp,该结构体定义在ieee80211_ioctl.h中,如下:
```c
struct ieee80211_clone_params {
char icp_name[IFNAMSIZ]; /* device name */
u_int16_t icp_opmode; /* operating mode */
u_int16_t icp_flags; /* see below */
};
icp_name是VAP名,如果未设定nounit选项并且最后一位不是数字,会先打开/proc/net/dev
文件,找到一个最小的可用数字构成VAP名,icp_opmode和icp_flags分别是VAP模式和输入选项标志。
最后程序调用ioctl(s, SIOC80211IFCREATE, ifr)
创建VAP,这里顺便简单提一下创建VAP的过程。
对于宏SIOC80211IFCREATE
,驱动会进入ath_ioctl
函数,我们可以在该函数中找到创建VAP的代码。1
2
3case SIOC80211IFCREATE:
error = ieee80211_ioctl_create_vap(ic, ifr, dev);
break;
在ath_ioctl
中调用了ieee80211_ioctl_create_vap
函数,该函数对参数进行解析并最终调用ic->ic_vap_create
函数来创建VAP。在该函数中可以看到,ifr_name
被设置为最终建立的VAP名后返回,wlanconfig程序调用完ioctl之后将使用ifr_name
打印VAP名。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27int
ieee80211_ioctl_create_vap(struct ieee80211com *ic, struct ifreq *ifr, struct net_device *mdev)
{
struct ieee80211_clone_params cp;
struct ieee80211vap *vap;
char name[IFNAMSIZ];
int unit;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&cp, ifr->ifr_data, sizeof(cp)))
return -EFAULT;
unit = ieee80211_new_wlanunit();
if (unit == -1)
return -EIO; /* XXX */
strncpy(name, cp.icp_name, sizeof(name));
vap = ic->ic_vap_create(ic, name, unit, cp.icp_opmode, cp.icp_flags, mdev);
if (vap == NULL) {
ieee80211_delete_wlanunit(unit);
return -EIO;
}
/* return final device name */
strncpy(ifr->ifr_name, vap->iv_dev->name, IFNAMSIZ);
return 0;
}
destroy
destroy操作几乎就是直接调用了ioctl(s, SIOC80211IFDESTROY, &ifr)
函数,但它调用的并不是ath_ioctl
函数,因为create操作中的ifr_name的是wifiX,也就是真实物理设备,而destroy操作中的ifr_name是athX,是VAP设备,也就是说destroy的具体过程在ieee80211_ioctl
函数中。
在ieee80211_ioctl.c
中停用并删除VAP的代码如下1
2
3
4
5
6case SIOC80211IFDESTROY:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
ieee80211_stop(vap->iv_dev); /* force state before cleanup */
vap->iv_ic->ic_vap_delete(vap);
return 0;
list
首先看list sta,该操作最终调用了ioctl(s, IEEE80211_IOCTL_STA_INFO, &iwr)
,这里的ioctl传的是iwreq
结构体,其实它和ifreq
结构体是一样的,只是在ifi_data部分进行了细化,定义在wireless_copy.h
中:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41struct iwreq
{
union
{
char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */
} 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 */
};
对于宏IEEE80211_IOCTL_STA_INFO
的处理,可以在ieee80211_ioctl
函数中可以找到1
2case IEEE80211_IOCTL_STA_INFO:
return ieee80211_ioctl_getstainfo(dev, (struct iwreq *) ifr);
具体获得站点信息的过程可以去看ieee80211_ioctl_getstainfo
函数,该函数将站点信息填充在ifr->u.data中后返回给ioctl调用。
以下几个list操作不再详细介绍,只给出对应的IOCTL宏,对应的处理函数可以根据一开始说的方法以在madwifi驱动中找到1
2
3
4
5scan or ap IEEE80211_IOCTL_SCAN_RESULTS
chan or freq IEEE80211_IOCTL_GETCHANINFO
active IEEE80211_IOCTL_GETCHANINFO + IEEE80211_IOCTL_GETCHANLIST
wme IEEE80211_IOCTL_GETWMMPARAMS
caps IEEE80211_IOCTL_GETPARAM
最后剩下的list keys操作实际上是调用了iwlist athX key
命令