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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
/* Note : this particular snipset of code is available under
* the LGPL, MPL or BSD license (at your choice).
* Jean II
*/
// Require Wireless Tools 25 for sub-ioctl and addr support
/* --------------------------- INCLUDE --------------------------- */
#if WIRELESS_EXT <= 12
/* Wireless extensions backward compatibility */
/* We need the full definition for private ioctls */
struct iw_request_info
{
__u16 cmd; /* Wireless Extension command */
__u16 flags; /* More to come ;-) */
};
#endif /* WIRELESS_EXT <= 12 */
#ifndef IW_PRIV_TYPE_ADDR
#define IW_PRIV_TYPE_ADDR 0x6000
#endif /* IW_PRIV_TYPE_ADDR */
/* --------------------------- HANDLERS --------------------------- */
/* First method : using sub-ioctls.
* Note that sizeof(int + struct sockaddr) = 20 > 16, therefore the
* data is passed in (char *) extra, and sub-ioctl in data->flags. */
static int sample_ioctl_set_mac(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data,
struct sockaddr *mac_addr)
{
unsigned char * addr = (char *) &mac_addr->sa_data;
switch(data->flags) {
case 0:
printk(KERN_DEBUG "%s: mac_add %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
break;
case 1:
printk(KERN_DEBUG "%s: mac_del %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
break;
case 2:
printk(KERN_DEBUG "%s: mac_kick %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
break;
default:
printk(KERN_DEBUG "%s: mac_undefined %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
break;
}
return 0;
}
/* Second method : bind single handler to multiple ioctls.
* Note that sizeof(struct sockaddr) = 16 <= 16, therefore the
* data is passed in (struct iwreq) (and also mapped in extra).
*/
static int sample_ioctl_set_addr(struct net_device *dev,
struct iw_request_info *info,
struct sockaddr *mac_addr, char *extra)
{
unsigned char * addr = (char *) &mac_addr->sa_data;
switch(info->cmd) {
case SIOCIWFIRSTPRIV + 28:
printk(KERN_DEBUG "%s: addr_add %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
break;
case SIOCIWFIRSTPRIV + 30:
printk(KERN_DEBUG "%s: addr_del %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
break;
default:
printk(KERN_DEBUG "%s: mac_undefined %02X:%02X:%02X:%02X:%02X:%02X\n", dev->name, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
break;
}
return 0;
}
// Extra fun for testing
static int sample_ioctl_get_mac(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data,
struct sockaddr *mac_addr)
{
unsigned char fake_addr[6];
int i;
int j;
for(i = 0; i < 16; i++) {
/* Create a fake address */
for(j = 0; j < 6; j++)
fake_addr[j] = (unsigned char) ((j << 4) + i);
/* Put in in the table */
memcpy(&(mac_addr[i]).sa_data, fake_addr, ETH_ALEN);
mac_addr[i].sa_family = ARPHRD_ETHER;
}
data->length = 16;
return 0;
}
static int sample_ioctl_set_float(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *freq, char *extra)
{
printk(KERN_DEBUG "%s: set_float %d;%d\n",
dev->name, freq->m, freq->e);
return 0;
}
/* --------------------------- BINDING --------------------------- */
static const struct iw_priv_args sample_priv[] = {
// *** Method 1 : using sub-ioctls ***
/* --- sub-ioctls handler --- */
{ SIOCIWFIRSTPRIV + 0,
IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "" },
/* --- sub-ioctls definitions --- */
{ 0,
IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "macadd" },
{ 1,
IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "macdel" },
{ 2,
IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "mackick" },
// *** Method 2 : binding one handler to multiple ioctls ***
{ SIOCIWFIRSTPRIV + 2,
IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addradd" },
{ SIOCIWFIRSTPRIV + 4,
IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addrdel" },
// *** Extra fun ***
{ SIOCIWFIRSTPRIV + 1,
0, IW_PRIV_TYPE_ADDR | 16, "macget" },
{ SIOCIWFIRSTPRIV + 6,
IW_PRIV_TYPE_FLOAT | IW_PRIV_SIZE_FIXED | 1, 0, "setfloat" },
};
static const iw_handler sample_private_handler[] =
{ /* SIOCIWFIRSTPRIV + */
#if WIRELESS_EXT >= 15
/* Various little annoying bugs in the new API before
* version 15 make it difficult to use the new API for those ioctls.
* For example, it doesn't know about the new data type.
* Rather than littering the code with workarounds,
* let's use the regular ioctl handler. - Jean II */
(iw_handler) sample_ioctl_set_mac, /* 0 */
(iw_handler) sample_ioctl_get_mac, /* 1 */
(iw_handler) sample_ioctl_set_addr, /* 2 */
(iw_handler) NULL, /* 3 */
(iw_handler) sample_ioctl_set_addr, /* 4 */
(iw_handler) NULL, /* 5 */
(iw_handler) sample_ioctl_set_float, /* 6 */
#endif /* WIRELESS_EXT >= 15 */
};
#if WIRELESS_EXT < 15
/* Various little annoying bugs in the new API before
* version 15 make it difficult to use those ioctls.
* For example, it doesn't know about the new data type.
* Rather than littering the code with workarounds,
* let's use this code that just works. - Jean II */
case SIOCIWFIRSTPRIV + 0:
if (wrq->u.data.length > 1)
ret = -E2BIG;
else if (wrq->u.data.pointer) {
struct sockaddr mac_addr;
if (copy_from_user(&mac_addr, wrq->u.data.pointer,
sizeof(struct sockaddr))) {
ret = -EFAULT;
break;
}
ret = sample_ioctl_set_mac(dev, NULL, &wrq->u.data,
&mac_addr);
}
break;
case SIOCIWFIRSTPRIV + 2:
case SIOCIWFIRSTPRIV + 4:
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else {
struct iw_request_info info;
info.cmd = cmd;
ret = sample_ioctl_set_addr(dev, &info,
&wrq->u.ap_addr,
NULL);
}
break;
case SIOCIWFIRSTPRIV + 1:
if (wrq->u.essid.pointer) {
struct sockaddr mac_addr[16];
char nickbuf[IW_ESSID_MAX_SIZE + 1];
ret = sample_ioctl_get_mac(dev, NULL, &wrq->u.data,
mac_addr);
if (copy_to_user(wrq->u.data.pointer, nickbuf,
wrq->u.data.length *
sizeof(struct sockaddr)))
ret = -EFAULT;
}
break;
case SIOCIWFIRSTPRIV + 6:
if (!capable(CAP_NET_ADMIN))
ret = -EPERM;
else {
ret = sample_ioctl_set_float(dev, NULL,
&wrq->u.freq,
NULL);
}
break;
#endif /* WIRELESS_EXT < 15 */
|