diff options
-rw-r--r-- | Documentation/feature-removal-schedule.txt | 12 | ||||
-rw-r--r-- | include/net/iw_handler.h | 10 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 31 | ||||
-rw-r--r-- | net/core/wireless.c | 735 | ||||
-rw-r--r-- | net/wireless/Kconfig | 10 |
5 files changed, 0 insertions, 798 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 9817b60e70a3..976c8a1bd7cd 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -285,18 +285,6 @@ Who: Richard Purdie <rpurdie@rpsys.net> | |||
285 | 285 | ||
286 | --------------------------- | 286 | --------------------------- |
287 | 287 | ||
288 | What: Wireless extensions over netlink (CONFIG_NET_WIRELESS_RTNETLINK) | ||
289 | When: with the merge of wireless-dev, 2.6.22 or later | ||
290 | Why: The option/code is | ||
291 | * not enabled on most kernels | ||
292 | * not required by any userspace tools (except an experimental one, | ||
293 | and even there only for some parts, others use ioctl) | ||
294 | * pointless since wext is no longer evolving and the ioctl | ||
295 | interface needs to be kept | ||
296 | Who: Johannes Berg <johannes@sipsolutions.net> | ||
297 | |||
298 | --------------------------- | ||
299 | |||
300 | What: i8xx_tco watchdog driver | 288 | What: i8xx_tco watchdog driver |
301 | When: in 2.6.22 | 289 | When: in 2.6.22 |
302 | Why: the i8xx_tco watchdog driver has been replaced by the iTCO_wdt | 290 | Why: the i8xx_tco watchdog driver has been replaced by the iTCO_wdt |
diff --git a/include/net/iw_handler.h b/include/net/iw_handler.h index 8a830188354d..909ca87d13b7 100644 --- a/include/net/iw_handler.h +++ b/include/net/iw_handler.h | |||
@@ -440,16 +440,6 @@ extern int dev_get_wireless_info(char * buffer, char **start, off_t offset, | |||
440 | /* Handle IOCTLs, called in net/core/dev.c */ | 440 | /* Handle IOCTLs, called in net/core/dev.c */ |
441 | extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); | 441 | extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd); |
442 | 442 | ||
443 | /* Handle RtNetlink requests, called in net/core/rtnetlink.c */ | ||
444 | extern int wireless_rtnetlink_set(struct net_device * dev, | ||
445 | char * data, | ||
446 | int len); | ||
447 | extern int wireless_rtnetlink_get(struct net_device * dev, | ||
448 | char * data, | ||
449 | int len, | ||
450 | char ** p_buf, | ||
451 | int * p_len); | ||
452 | |||
453 | /* Second : functions that may be called by driver modules */ | 443 | /* Second : functions that may be called by driver modules */ |
454 | 444 | ||
455 | /* Send a single event to user space */ | 445 | /* Send a single event to user space */ |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 75cea8ea4cf3..4fe0f4b3a345 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -51,10 +51,6 @@ | |||
51 | #include <net/pkt_sched.h> | 51 | #include <net/pkt_sched.h> |
52 | #include <net/fib_rules.h> | 52 | #include <net/fib_rules.h> |
53 | #include <net/rtnetlink.h> | 53 | #include <net/rtnetlink.h> |
54 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
55 | #include <linux/wireless.h> | ||
56 | #include <net/iw_handler.h> | ||
57 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
58 | 54 | ||
59 | struct rtnl_link | 55 | struct rtnl_link |
60 | { | 56 | { |
@@ -684,17 +680,6 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
684 | modified = 1; | 680 | modified = 1; |
685 | } | 681 | } |
686 | 682 | ||
687 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
688 | if (tb[IFLA_WIRELESS]) { | ||
689 | /* Call Wireless Extensions. | ||
690 | * Various stuff checked in there... */ | ||
691 | err = wireless_rtnetlink_set(dev, nla_data(tb[IFLA_WIRELESS]), | ||
692 | nla_len(tb[IFLA_WIRELESS])); | ||
693 | if (err < 0) | ||
694 | goto errout_dev; | ||
695 | } | ||
696 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
697 | |||
698 | if (tb[IFLA_BROADCAST]) { | 683 | if (tb[IFLA_BROADCAST]) { |
699 | nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len); | 684 | nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len); |
700 | send_addr_notify = 1; | 685 | send_addr_notify = 1; |
@@ -758,22 +743,6 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | |||
758 | } else | 743 | } else |
759 | return -EINVAL; | 744 | return -EINVAL; |
760 | 745 | ||
761 | |||
762 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
763 | if (tb[IFLA_WIRELESS]) { | ||
764 | /* Call Wireless Extensions. We need to know the size before | ||
765 | * we can alloc. Various stuff checked in there... */ | ||
766 | err = wireless_rtnetlink_get(dev, nla_data(tb[IFLA_WIRELESS]), | ||
767 | nla_len(tb[IFLA_WIRELESS]), | ||
768 | &iw_buf, &iw_buf_len); | ||
769 | if (err < 0) | ||
770 | goto errout; | ||
771 | |||
772 | /* Payload is at an offset in buffer */ | ||
773 | iw = iw_buf + IW_EV_POINT_OFF; | ||
774 | } | ||
775 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
776 | |||
777 | nskb = nlmsg_new(if_nlmsg_size(iw_buf_len), GFP_KERNEL); | 746 | nskb = nlmsg_new(if_nlmsg_size(iw_buf_len), GFP_KERNEL); |
778 | if (nskb == NULL) { | 747 | if (nskb == NULL) { |
779 | err = -ENOBUFS; | 748 | err = -ENOBUFS; |
diff --git a/net/core/wireless.c b/net/core/wireless.c index 86db63d7f760..fba295e05e7a 100644 --- a/net/core/wireless.c +++ b/net/core/wireless.c | |||
@@ -104,12 +104,10 @@ | |||
104 | 104 | ||
105 | /* Debugging stuff */ | 105 | /* Debugging stuff */ |
106 | #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ | 106 | #undef WE_IOCTL_DEBUG /* Debug IOCTL API */ |
107 | #undef WE_RTNETLINK_DEBUG /* Debug RtNetlink API */ | ||
108 | #undef WE_EVENT_DEBUG /* Debug Event dispatcher */ | 107 | #undef WE_EVENT_DEBUG /* Debug Event dispatcher */ |
109 | #undef WE_SPY_DEBUG /* Debug enhanced spy support */ | 108 | #undef WE_SPY_DEBUG /* Debug enhanced spy support */ |
110 | 109 | ||
111 | /* Options */ | 110 | /* Options */ |
112 | //CONFIG_NET_WIRELESS_RTNETLINK /* Wireless requests over RtNetlink */ | ||
113 | #define WE_EVENT_RTNETLINK /* Propagate events using RtNetlink */ | 111 | #define WE_EVENT_RTNETLINK /* Propagate events using RtNetlink */ |
114 | #define WE_SET_EVENT /* Generate an event on some set commands */ | 112 | #define WE_SET_EVENT /* Generate an event on some set commands */ |
115 | 113 | ||
@@ -1145,739 +1143,6 @@ int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) | |||
1145 | return -EINVAL; | 1143 | return -EINVAL; |
1146 | } | 1144 | } |
1147 | 1145 | ||
1148 | /********************** RTNETLINK REQUEST API **********************/ | ||
1149 | /* | ||
1150 | * The alternate user space API to configure all those Wireless Extensions | ||
1151 | * is through RtNetlink. | ||
1152 | * This API support only the new driver API (iw_handler). | ||
1153 | * | ||
1154 | * This RtNetlink API use the same query/reply model as the ioctl API. | ||
1155 | * Maximum effort has been done to fit in the RtNetlink model, and | ||
1156 | * we support both RtNetlink Set and RtNelink Get operations. | ||
1157 | * On the other hand, we don't offer Dump operations because of the | ||
1158 | * following reasons : | ||
1159 | * o Large number of parameters, most optional | ||
1160 | * o Large size of some parameters (> 100 bytes) | ||
1161 | * o Each parameters need to be extracted from hardware | ||
1162 | * o Scan requests can take seconds and disable network activity. | ||
1163 | * Because of this high cost/overhead, we want to return only the | ||
1164 | * parameters the user application is really interested in. | ||
1165 | * We could offer partial Dump using the IW_DESCR_FLAG_DUMP flag. | ||
1166 | * | ||
1167 | * The API uses the standard RtNetlink socket. When the RtNetlink code | ||
1168 | * find a IFLA_WIRELESS field in a RtNetlink SET_LINK request, | ||
1169 | * it calls here. | ||
1170 | */ | ||
1171 | |||
1172 | #ifdef CONFIG_NET_WIRELESS_RTNETLINK | ||
1173 | /* ---------------------------------------------------------------- */ | ||
1174 | /* | ||
1175 | * Wrapper to call a standard Wireless Extension GET handler. | ||
1176 | * We do various checks and call the handler with the proper args. | ||
1177 | */ | ||
1178 | static int rtnetlink_standard_get(struct net_device * dev, | ||
1179 | struct iw_event * request, | ||
1180 | int request_len, | ||
1181 | iw_handler handler, | ||
1182 | char ** p_buf, | ||
1183 | int * p_len) | ||
1184 | { | ||
1185 | const struct iw_ioctl_description * descr = NULL; | ||
1186 | unsigned int cmd; | ||
1187 | union iwreq_data * wrqu; | ||
1188 | int hdr_len; | ||
1189 | struct iw_request_info info; | ||
1190 | char * buffer = NULL; | ||
1191 | int buffer_size = 0; | ||
1192 | int ret = -EINVAL; | ||
1193 | |||
1194 | /* Get the description of the Request */ | ||
1195 | cmd = request->cmd; | ||
1196 | if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) | ||
1197 | return -EOPNOTSUPP; | ||
1198 | descr = &(standard_ioctl[cmd - SIOCIWFIRST]); | ||
1199 | |||
1200 | #ifdef WE_RTNETLINK_DEBUG | ||
1201 | printk(KERN_DEBUG "%s (WE.r) : Found standard handler for 0x%04X\n", | ||
1202 | dev->name, cmd); | ||
1203 | printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); | ||
1204 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1205 | |||
1206 | /* Check if wrqu is complete */ | ||
1207 | hdr_len = event_type_size[descr->header_type]; | ||
1208 | if (request_len < hdr_len) { | ||
1209 | #ifdef WE_RTNETLINK_DEBUG | ||
1210 | printk(KERN_DEBUG | ||
1211 | "%s (WE.r) : Wireless request too short (%d)\n", | ||
1212 | dev->name, request_len); | ||
1213 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1214 | return -EINVAL; | ||
1215 | } | ||
1216 | |||
1217 | /* Prepare the call */ | ||
1218 | info.cmd = cmd; | ||
1219 | info.flags = 0; | ||
1220 | |||
1221 | /* Check if we have extra data in the reply or not */ | ||
1222 | if (descr->header_type != IW_HEADER_TYPE_POINT) { | ||
1223 | |||
1224 | /* Create the kernel buffer that we will return. | ||
1225 | * It's at an offset to match the TYPE_POINT case... */ | ||
1226 | buffer_size = request_len + IW_EV_POINT_OFF; | ||
1227 | buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
1228 | if (buffer == NULL) { | ||
1229 | return -ENOMEM; | ||
1230 | } | ||
1231 | /* Copy event data */ | ||
1232 | memcpy(buffer + IW_EV_POINT_OFF, request, request_len); | ||
1233 | /* Use our own copy of wrqu */ | ||
1234 | wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF | ||
1235 | + IW_EV_LCP_PK_LEN); | ||
1236 | |||
1237 | /* No extra arguments. Trivial to handle */ | ||
1238 | ret = handler(dev, &info, wrqu, NULL); | ||
1239 | |||
1240 | } else { | ||
1241 | union iwreq_data wrqu_point; | ||
1242 | char * extra = NULL; | ||
1243 | int extra_size = 0; | ||
1244 | |||
1245 | /* Get a temp copy of wrqu (skip pointer) */ | ||
1246 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, | ||
1247 | ((char *) request) + IW_EV_LCP_PK_LEN, | ||
1248 | IW_EV_POINT_LEN - IW_EV_LCP_PK_LEN); | ||
1249 | |||
1250 | /* Calculate space needed by arguments. Always allocate | ||
1251 | * for max space. Easier, and won't last long... */ | ||
1252 | extra_size = descr->max_tokens * descr->token_size; | ||
1253 | /* Support for very large requests */ | ||
1254 | if ((descr->flags & IW_DESCR_FLAG_NOMAX) && | ||
1255 | (wrqu_point.data.length > descr->max_tokens)) | ||
1256 | extra_size = (wrqu_point.data.length | ||
1257 | * descr->token_size); | ||
1258 | buffer_size = extra_size + IW_EV_POINT_PK_LEN + IW_EV_POINT_OFF; | ||
1259 | #ifdef WE_RTNETLINK_DEBUG | ||
1260 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", | ||
1261 | dev->name, extra_size, buffer_size); | ||
1262 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1263 | |||
1264 | /* Create the kernel buffer that we will return */ | ||
1265 | buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
1266 | if (buffer == NULL) { | ||
1267 | return -ENOMEM; | ||
1268 | } | ||
1269 | |||
1270 | /* Put wrqu in the right place (just before extra). | ||
1271 | * Leave space for IWE header and dummy pointer... | ||
1272 | * Note that IW_EV_LCP_PK_LEN==4 bytes, so it's still aligned. | ||
1273 | */ | ||
1274 | memcpy(buffer + IW_EV_LCP_PK_LEN + IW_EV_POINT_OFF, | ||
1275 | ((char *) &wrqu_point) + IW_EV_POINT_OFF, | ||
1276 | IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); | ||
1277 | wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_PK_LEN); | ||
1278 | |||
1279 | /* Extra comes logically after that. Offset +12 bytes. */ | ||
1280 | extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_PK_LEN; | ||
1281 | |||
1282 | /* Call the handler */ | ||
1283 | ret = handler(dev, &info, wrqu, extra); | ||
1284 | |||
1285 | /* Calculate real returned length */ | ||
1286 | extra_size = (wrqu->data.length * descr->token_size); | ||
1287 | /* Re-adjust reply size */ | ||
1288 | request->len = extra_size + IW_EV_POINT_PK_LEN; | ||
1289 | |||
1290 | /* Put the iwe header where it should, i.e. scrap the | ||
1291 | * dummy pointer. */ | ||
1292 | memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_PK_LEN); | ||
1293 | |||
1294 | #ifdef WE_RTNETLINK_DEBUG | ||
1295 | printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size); | ||
1296 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1297 | |||
1298 | /* Check if there is enough buffer up there */ | ||
1299 | if (wrqu_point.data.length < wrqu->data.length) | ||
1300 | ret = -E2BIG; | ||
1301 | } | ||
1302 | |||
1303 | /* Return the buffer to the caller */ | ||
1304 | if (!ret) { | ||
1305 | *p_buf = buffer; | ||
1306 | *p_len = request->len; | ||
1307 | } else { | ||
1308 | /* Cleanup */ | ||
1309 | if (buffer) | ||
1310 | kfree(buffer); | ||
1311 | } | ||
1312 | |||
1313 | return ret; | ||
1314 | } | ||
1315 | |||
1316 | /* ---------------------------------------------------------------- */ | ||
1317 | /* | ||
1318 | * Wrapper to call a standard Wireless Extension SET handler. | ||
1319 | * We do various checks and call the handler with the proper args. | ||
1320 | */ | ||
1321 | static inline int rtnetlink_standard_set(struct net_device * dev, | ||
1322 | struct iw_event * request, | ||
1323 | int request_len, | ||
1324 | iw_handler handler) | ||
1325 | { | ||
1326 | const struct iw_ioctl_description * descr = NULL; | ||
1327 | unsigned int cmd; | ||
1328 | union iwreq_data * wrqu; | ||
1329 | union iwreq_data wrqu_point; | ||
1330 | int hdr_len; | ||
1331 | char * extra = NULL; | ||
1332 | int extra_size = 0; | ||
1333 | struct iw_request_info info; | ||
1334 | int ret = -EINVAL; | ||
1335 | |||
1336 | /* Get the description of the Request */ | ||
1337 | cmd = request->cmd; | ||
1338 | if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) | ||
1339 | return -EOPNOTSUPP; | ||
1340 | descr = &(standard_ioctl[cmd - SIOCIWFIRST]); | ||
1341 | |||
1342 | #ifdef WE_RTNETLINK_DEBUG | ||
1343 | printk(KERN_DEBUG "%s (WE.r) : Found standard SET handler for 0x%04X\n", | ||
1344 | dev->name, cmd); | ||
1345 | printk(KERN_DEBUG "%s (WE.r) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); | ||
1346 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1347 | |||
1348 | /* Extract fixed header from request. This is properly aligned. */ | ||
1349 | wrqu = (union iwreq_data *) (((char *) request) + IW_EV_LCP_PK_LEN); | ||
1350 | |||
1351 | /* Check if wrqu is complete */ | ||
1352 | hdr_len = event_type_pk_size[descr->header_type]; | ||
1353 | if (request_len < hdr_len) { | ||
1354 | #ifdef WE_RTNETLINK_DEBUG | ||
1355 | printk(KERN_DEBUG | ||
1356 | "%s (WE.r) : Wireless request too short (%d)\n", | ||
1357 | dev->name, request_len); | ||
1358 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1359 | return -EINVAL; | ||
1360 | } | ||
1361 | |||
1362 | /* Prepare the call */ | ||
1363 | info.cmd = cmd; | ||
1364 | info.flags = 0; | ||
1365 | |||
1366 | /* Check if we have extra data in the request or not */ | ||
1367 | if (descr->header_type != IW_HEADER_TYPE_POINT) { | ||
1368 | |||
1369 | /* No extra arguments. Trivial to handle */ | ||
1370 | ret = handler(dev, &info, wrqu, NULL); | ||
1371 | |||
1372 | } else { | ||
1373 | int extra_len; | ||
1374 | |||
1375 | /* Put wrqu in the right place (skip pointer) */ | ||
1376 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, | ||
1377 | wrqu, IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); | ||
1378 | /* Don't forget about the event code... */ | ||
1379 | wrqu = &wrqu_point; | ||
1380 | |||
1381 | /* Check if number of token fits within bounds */ | ||
1382 | if (wrqu_point.data.length > descr->max_tokens) | ||
1383 | return -E2BIG; | ||
1384 | if (wrqu_point.data.length < descr->min_tokens) | ||
1385 | return -EINVAL; | ||
1386 | |||
1387 | /* Real length of payload */ | ||
1388 | extra_len = wrqu_point.data.length * descr->token_size; | ||
1389 | |||
1390 | /* Check if request is self consistent */ | ||
1391 | if ((request_len - hdr_len) < extra_len) { | ||
1392 | #ifdef WE_RTNETLINK_DEBUG | ||
1393 | printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n", | ||
1394 | dev->name, extra_size); | ||
1395 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1396 | return -EINVAL; | ||
1397 | } | ||
1398 | |||
1399 | #ifdef WE_RTNETLINK_DEBUG | ||
1400 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n", | ||
1401 | dev->name, extra_size); | ||
1402 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1403 | |||
1404 | /* Always allocate for max space. Easier, and won't last | ||
1405 | * long... */ | ||
1406 | extra_size = descr->max_tokens * descr->token_size; | ||
1407 | extra = kmalloc(extra_size, GFP_KERNEL); | ||
1408 | if (extra == NULL) | ||
1409 | return -ENOMEM; | ||
1410 | |||
1411 | /* Copy extra in aligned buffer */ | ||
1412 | memcpy(extra, ((char *) request) + hdr_len, extra_len); | ||
1413 | |||
1414 | /* Call the handler */ | ||
1415 | ret = handler(dev, &info, &wrqu_point, extra); | ||
1416 | } | ||
1417 | |||
1418 | #ifdef WE_SET_EVENT | ||
1419 | /* Generate an event to notify listeners of the change */ | ||
1420 | if ((descr->flags & IW_DESCR_FLAG_EVENT) && | ||
1421 | ((ret == 0) || (ret == -EIWCOMMIT))) { | ||
1422 | if (descr->flags & IW_DESCR_FLAG_RESTRICT) | ||
1423 | /* If the event is restricted, don't | ||
1424 | * export the payload */ | ||
1425 | wireless_send_event(dev, cmd, wrqu, NULL); | ||
1426 | else | ||
1427 | wireless_send_event(dev, cmd, wrqu, extra); | ||
1428 | } | ||
1429 | #endif /* WE_SET_EVENT */ | ||
1430 | |||
1431 | /* Cleanup - I told you it wasn't that long ;-) */ | ||
1432 | if (extra) | ||
1433 | kfree(extra); | ||
1434 | |||
1435 | /* Call commit handler if needed and defined */ | ||
1436 | if (ret == -EIWCOMMIT) | ||
1437 | ret = call_commit_handler(dev); | ||
1438 | |||
1439 | return ret; | ||
1440 | } | ||
1441 | |||
1442 | /* ---------------------------------------------------------------- */ | ||
1443 | /* | ||
1444 | * Wrapper to call a private Wireless Extension GET handler. | ||
1445 | * Same as above... | ||
1446 | * It's not as nice and slimline as the standard wrapper. The cause | ||
1447 | * is struct iw_priv_args, which was not really designed for the | ||
1448 | * job we are going here. | ||
1449 | * | ||
1450 | * IMPORTANT : This function prevent to set and get data on the same | ||
1451 | * IOCTL and enforce the SET/GET convention. Not doing it would be | ||
1452 | * far too hairy... | ||
1453 | * If you need to set and get data at the same time, please don't use | ||
1454 | * a iw_handler but process it in your ioctl handler (i.e. use the | ||
1455 | * old driver API). | ||
1456 | */ | ||
1457 | static inline int rtnetlink_private_get(struct net_device * dev, | ||
1458 | struct iw_event * request, | ||
1459 | int request_len, | ||
1460 | iw_handler handler, | ||
1461 | char ** p_buf, | ||
1462 | int * p_len) | ||
1463 | { | ||
1464 | const struct iw_priv_args * descr = NULL; | ||
1465 | unsigned int cmd; | ||
1466 | union iwreq_data * wrqu; | ||
1467 | int hdr_len; | ||
1468 | struct iw_request_info info; | ||
1469 | int extra_size = 0; | ||
1470 | int i; | ||
1471 | char * buffer = NULL; | ||
1472 | int buffer_size = 0; | ||
1473 | int ret = -EINVAL; | ||
1474 | |||
1475 | /* Get the description of the Request */ | ||
1476 | cmd = request->cmd; | ||
1477 | for (i = 0; i < dev->wireless_handlers->num_private_args; i++) | ||
1478 | if (cmd == dev->wireless_handlers->private_args[i].cmd) { | ||
1479 | descr = &(dev->wireless_handlers->private_args[i]); | ||
1480 | break; | ||
1481 | } | ||
1482 | if (descr == NULL) | ||
1483 | return -EOPNOTSUPP; | ||
1484 | |||
1485 | #ifdef WE_RTNETLINK_DEBUG | ||
1486 | printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n", | ||
1487 | dev->name, cmd); | ||
1488 | printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n", | ||
1489 | dev->name, descr->name, descr->set_args, descr->get_args); | ||
1490 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1491 | |||
1492 | /* Compute the max size of the get arguments */ | ||
1493 | extra_size = get_priv_size(descr->get_args); | ||
1494 | |||
1495 | /* Does it fits in wrqu ? */ | ||
1496 | if ((descr->get_args & IW_PRIV_SIZE_FIXED) && | ||
1497 | (extra_size <= IFNAMSIZ)) { | ||
1498 | hdr_len = extra_size; | ||
1499 | extra_size = 0; | ||
1500 | } else { | ||
1501 | hdr_len = IW_EV_POINT_PK_LEN; | ||
1502 | } | ||
1503 | |||
1504 | /* Check if wrqu is complete */ | ||
1505 | if (request_len < hdr_len) { | ||
1506 | #ifdef WE_RTNETLINK_DEBUG | ||
1507 | printk(KERN_DEBUG | ||
1508 | "%s (WE.r) : Wireless request too short (%d)\n", | ||
1509 | dev->name, request_len); | ||
1510 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1511 | return -EINVAL; | ||
1512 | } | ||
1513 | |||
1514 | /* Prepare the call */ | ||
1515 | info.cmd = cmd; | ||
1516 | info.flags = 0; | ||
1517 | |||
1518 | /* Check if we have a pointer to user space data or not. */ | ||
1519 | if (extra_size == 0) { | ||
1520 | |||
1521 | /* Create the kernel buffer that we will return. | ||
1522 | * It's at an offset to match the TYPE_POINT case... */ | ||
1523 | buffer_size = request_len + IW_EV_POINT_OFF; | ||
1524 | buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
1525 | if (buffer == NULL) { | ||
1526 | return -ENOMEM; | ||
1527 | } | ||
1528 | /* Copy event data */ | ||
1529 | memcpy(buffer + IW_EV_POINT_OFF, request, request_len); | ||
1530 | /* Use our own copy of wrqu */ | ||
1531 | wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF | ||
1532 | + IW_EV_LCP_PK_LEN); | ||
1533 | |||
1534 | /* No extra arguments. Trivial to handle */ | ||
1535 | ret = handler(dev, &info, wrqu, (char *) wrqu); | ||
1536 | |||
1537 | } else { | ||
1538 | char * extra; | ||
1539 | |||
1540 | /* Buffer for full reply */ | ||
1541 | buffer_size = extra_size + IW_EV_POINT_PK_LEN + IW_EV_POINT_OFF; | ||
1542 | |||
1543 | #ifdef WE_RTNETLINK_DEBUG | ||
1544 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", | ||
1545 | dev->name, extra_size, buffer_size); | ||
1546 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1547 | |||
1548 | /* Create the kernel buffer that we will return */ | ||
1549 | buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
1550 | if (buffer == NULL) { | ||
1551 | return -ENOMEM; | ||
1552 | } | ||
1553 | |||
1554 | /* Put wrqu in the right place (just before extra). | ||
1555 | * Leave space for IWE header and dummy pointer... | ||
1556 | * Note that IW_EV_LCP_PK_LEN==4 bytes, so it's still aligned. | ||
1557 | */ | ||
1558 | memcpy(buffer + IW_EV_LCP_PK_LEN + IW_EV_POINT_OFF, | ||
1559 | ((char *) request) + IW_EV_LCP_PK_LEN, | ||
1560 | IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); | ||
1561 | wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_PK_LEN); | ||
1562 | |||
1563 | /* Extra comes logically after that. Offset +12 bytes. */ | ||
1564 | extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_PK_LEN; | ||
1565 | |||
1566 | /* Call the handler */ | ||
1567 | ret = handler(dev, &info, wrqu, extra); | ||
1568 | |||
1569 | /* Adjust for the actual length if it's variable, | ||
1570 | * avoid leaking kernel bits outside. */ | ||
1571 | if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) | ||
1572 | extra_size = adjust_priv_size(descr->get_args, wrqu); | ||
1573 | /* Re-adjust reply size */ | ||
1574 | request->len = extra_size + IW_EV_POINT_PK_LEN; | ||
1575 | |||
1576 | /* Put the iwe header where it should, i.e. scrap the | ||
1577 | * dummy pointer. */ | ||
1578 | memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_PK_LEN); | ||
1579 | |||
1580 | #ifdef WE_RTNETLINK_DEBUG | ||
1581 | printk(KERN_DEBUG "%s (WE.r) : Reply 0x%04X, hdr_len %d, tokens %d, extra_size %d, buffer_size %d\n", dev->name, cmd, hdr_len, wrqu->data.length, extra_size, buffer_size); | ||
1582 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1583 | } | ||
1584 | |||
1585 | /* Return the buffer to the caller */ | ||
1586 | if (!ret) { | ||
1587 | *p_buf = buffer; | ||
1588 | *p_len = request->len; | ||
1589 | } else { | ||
1590 | /* Cleanup */ | ||
1591 | if (buffer) | ||
1592 | kfree(buffer); | ||
1593 | } | ||
1594 | |||
1595 | return ret; | ||
1596 | } | ||
1597 | |||
1598 | /* ---------------------------------------------------------------- */ | ||
1599 | /* | ||
1600 | * Wrapper to call a private Wireless Extension SET handler. | ||
1601 | * Same as above... | ||
1602 | * It's not as nice and slimline as the standard wrapper. The cause | ||
1603 | * is struct iw_priv_args, which was not really designed for the | ||
1604 | * job we are going here. | ||
1605 | * | ||
1606 | * IMPORTANT : This function prevent to set and get data on the same | ||
1607 | * IOCTL and enforce the SET/GET convention. Not doing it would be | ||
1608 | * far too hairy... | ||
1609 | * If you need to set and get data at the same time, please don't use | ||
1610 | * a iw_handler but process it in your ioctl handler (i.e. use the | ||
1611 | * old driver API). | ||
1612 | */ | ||
1613 | static inline int rtnetlink_private_set(struct net_device * dev, | ||
1614 | struct iw_event * request, | ||
1615 | int request_len, | ||
1616 | iw_handler handler) | ||
1617 | { | ||
1618 | const struct iw_priv_args * descr = NULL; | ||
1619 | unsigned int cmd; | ||
1620 | union iwreq_data * wrqu; | ||
1621 | union iwreq_data wrqu_point; | ||
1622 | int hdr_len; | ||
1623 | char * extra = NULL; | ||
1624 | int extra_size = 0; | ||
1625 | int offset = 0; /* For sub-ioctls */ | ||
1626 | struct iw_request_info info; | ||
1627 | int i; | ||
1628 | int ret = -EINVAL; | ||
1629 | |||
1630 | /* Get the description of the Request */ | ||
1631 | cmd = request->cmd; | ||
1632 | for (i = 0; i < dev->wireless_handlers->num_private_args; i++) | ||
1633 | if (cmd == dev->wireless_handlers->private_args[i].cmd) { | ||
1634 | descr = &(dev->wireless_handlers->private_args[i]); | ||
1635 | break; | ||
1636 | } | ||
1637 | if (descr == NULL) | ||
1638 | return -EOPNOTSUPP; | ||
1639 | |||
1640 | #ifdef WE_RTNETLINK_DEBUG | ||
1641 | printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n", | ||
1642 | ifr->ifr_name, cmd); | ||
1643 | printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n", | ||
1644 | dev->name, descr->name, descr->set_args, descr->get_args); | ||
1645 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1646 | |||
1647 | /* Compute the size of the set arguments */ | ||
1648 | /* Check for sub-ioctl handler */ | ||
1649 | if (descr->name[0] == '\0') | ||
1650 | /* Reserve one int for sub-ioctl index */ | ||
1651 | offset = sizeof(__u32); | ||
1652 | |||
1653 | /* Size of set arguments */ | ||
1654 | extra_size = get_priv_size(descr->set_args); | ||
1655 | |||
1656 | /* Does it fits in wrqu ? */ | ||
1657 | if ((descr->set_args & IW_PRIV_SIZE_FIXED) && | ||
1658 | (extra_size <= IFNAMSIZ)) { | ||
1659 | hdr_len = IW_EV_LCP_PK_LEN + extra_size; | ||
1660 | extra_size = 0; | ||
1661 | } else { | ||
1662 | hdr_len = IW_EV_POINT_PK_LEN; | ||
1663 | } | ||
1664 | |||
1665 | /* Extract fixed header from request. This is properly aligned. */ | ||
1666 | wrqu = (union iwreq_data *) (((char *) request) + IW_EV_LCP_PK_LEN); | ||
1667 | |||
1668 | /* Check if wrqu is complete */ | ||
1669 | if (request_len < hdr_len) { | ||
1670 | #ifdef WE_RTNETLINK_DEBUG | ||
1671 | printk(KERN_DEBUG | ||
1672 | "%s (WE.r) : Wireless request too short (%d)\n", | ||
1673 | dev->name, request_len); | ||
1674 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1675 | return -EINVAL; | ||
1676 | } | ||
1677 | |||
1678 | /* Prepare the call */ | ||
1679 | info.cmd = cmd; | ||
1680 | info.flags = 0; | ||
1681 | |||
1682 | /* Check if we have a pointer to user space data or not. */ | ||
1683 | if (extra_size == 0) { | ||
1684 | |||
1685 | /* No extra arguments. Trivial to handle */ | ||
1686 | ret = handler(dev, &info, wrqu, (char *) wrqu); | ||
1687 | |||
1688 | } else { | ||
1689 | int extra_len; | ||
1690 | |||
1691 | /* Put wrqu in the right place (skip pointer) */ | ||
1692 | memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, | ||
1693 | wrqu, IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); | ||
1694 | |||
1695 | /* Does it fits within bounds ? */ | ||
1696 | if (wrqu_point.data.length > (descr->set_args & | ||
1697 | IW_PRIV_SIZE_MASK)) | ||
1698 | return -E2BIG; | ||
1699 | |||
1700 | /* Real length of payload */ | ||
1701 | extra_len = adjust_priv_size(descr->set_args, &wrqu_point); | ||
1702 | |||
1703 | /* Check if request is self consistent */ | ||
1704 | if ((request_len - hdr_len) < extra_len) { | ||
1705 | #ifdef WE_RTNETLINK_DEBUG | ||
1706 | printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n", | ||
1707 | dev->name, extra_size); | ||
1708 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1709 | return -EINVAL; | ||
1710 | } | ||
1711 | |||
1712 | #ifdef WE_RTNETLINK_DEBUG | ||
1713 | printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n", | ||
1714 | dev->name, extra_size); | ||
1715 | #endif /* WE_RTNETLINK_DEBUG */ | ||
1716 | |||
1717 | /* Always allocate for max space. Easier, and won't last | ||
1718 | * long... */ | ||
1719 | extra = kmalloc(extra_size, GFP_KERNEL); | ||
1720 | if (extra == NULL) | ||
1721 | return -ENOMEM; | ||
1722 | |||
1723 | /* Copy extra in aligned buffer */ | ||
1724 | memcpy(extra, ((char *) request) + hdr_len, extra_len); | ||
1725 | |||
1726 | /* Call the handler */ | ||
1727 | ret = handler(dev, &info, &wrqu_point, extra); | ||
1728 | |||
1729 | /* Cleanup - I told you it wasn't that long ;-) */ | ||
1730 | kfree(extra); | ||
1731 | } | ||
1732 | |||
1733 | /* Call commit handler if needed and defined */ | ||
1734 | if (ret == -EIWCOMMIT) | ||
1735 | ret = call_commit_handler(dev); | ||
1736 | |||
1737 | return ret; | ||
1738 | } | ||
1739 | |||
1740 | /* ---------------------------------------------------------------- */ | ||
1741 | /* | ||
1742 | * Main RtNetlink dispatcher. Called from the main networking code | ||
1743 | * (do_getlink() in net/core/rtnetlink.c). | ||
1744 | * Check the type of Request and call the appropriate wrapper... | ||
1745 | */ | ||
1746 | int wireless_rtnetlink_get(struct net_device * dev, | ||
1747 | char * data, | ||
1748 | int len, | ||
1749 | char ** p_buf, | ||
1750 | int * p_len) | ||
1751 | { | ||
1752 | struct iw_event * request = (struct iw_event *) data; | ||
1753 | iw_handler handler; | ||
1754 | |||
1755 | /* Check length */ | ||
1756 | if (len < IW_EV_LCP_PK_LEN) { | ||
1757 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", | ||
1758 | dev->name, len); | ||
1759 | return -EINVAL; | ||
1760 | } | ||
1761 | |||
1762 | /* ReCheck length (len may have padding) */ | ||
1763 | if (request->len > len) { | ||
1764 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n", | ||
1765 | dev->name, request->len, len); | ||
1766 | return -EINVAL; | ||
1767 | } | ||
1768 | |||
1769 | /* Only accept GET requests in here */ | ||
1770 | if (!IW_IS_GET(request->cmd)) | ||
1771 | return -EOPNOTSUPP; | ||
1772 | |||
1773 | /* If command is `get the encoding parameters', check if | ||
1774 | * the user has the right to do it */ | ||
1775 | if (request->cmd == SIOCGIWENCODE || | ||
1776 | request->cmd == SIOCGIWENCODEEXT) { | ||
1777 | if (!capable(CAP_NET_ADMIN)) | ||
1778 | return -EPERM; | ||
1779 | } | ||
1780 | |||
1781 | /* Special cases */ | ||
1782 | if (request->cmd == SIOCGIWSTATS) | ||
1783 | /* Get Wireless Stats */ | ||
1784 | return rtnetlink_standard_get(dev, | ||
1785 | request, | ||
1786 | request->len, | ||
1787 | &iw_handler_get_iwstats, | ||
1788 | p_buf, p_len); | ||
1789 | if (request->cmd == SIOCGIWPRIV) { | ||
1790 | /* Check if we have some wireless handlers defined */ | ||
1791 | if (dev->wireless_handlers == NULL) | ||
1792 | return -EOPNOTSUPP; | ||
1793 | /* Get Wireless Stats */ | ||
1794 | return rtnetlink_standard_get(dev, | ||
1795 | request, | ||
1796 | request->len, | ||
1797 | &iw_handler_get_private, | ||
1798 | p_buf, p_len); | ||
1799 | } | ||
1800 | |||
1801 | /* Basic check */ | ||
1802 | if (!netif_device_present(dev)) | ||
1803 | return -ENODEV; | ||
1804 | |||
1805 | /* Try to find the handler */ | ||
1806 | handler = get_handler(dev, request->cmd); | ||
1807 | if (handler != NULL) { | ||
1808 | /* Standard and private are not the same */ | ||
1809 | if (request->cmd < SIOCIWFIRSTPRIV) | ||
1810 | return rtnetlink_standard_get(dev, | ||
1811 | request, | ||
1812 | request->len, | ||
1813 | handler, | ||
1814 | p_buf, p_len); | ||
1815 | else | ||
1816 | return rtnetlink_private_get(dev, | ||
1817 | request, | ||
1818 | request->len, | ||
1819 | handler, | ||
1820 | p_buf, p_len); | ||
1821 | } | ||
1822 | |||
1823 | return -EOPNOTSUPP; | ||
1824 | } | ||
1825 | |||
1826 | /* ---------------------------------------------------------------- */ | ||
1827 | /* | ||
1828 | * Main RtNetlink dispatcher. Called from the main networking code | ||
1829 | * (do_setlink() in net/core/rtnetlink.c). | ||
1830 | * Check the type of Request and call the appropriate wrapper... | ||
1831 | */ | ||
1832 | int wireless_rtnetlink_set(struct net_device * dev, | ||
1833 | char * data, | ||
1834 | int len) | ||
1835 | { | ||
1836 | struct iw_event * request = (struct iw_event *) data; | ||
1837 | iw_handler handler; | ||
1838 | |||
1839 | /* Check length */ | ||
1840 | if (len < IW_EV_LCP_PK_LEN) { | ||
1841 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", | ||
1842 | dev->name, len); | ||
1843 | return -EINVAL; | ||
1844 | } | ||
1845 | |||
1846 | /* ReCheck length (len may have padding) */ | ||
1847 | if (request->len > len) { | ||
1848 | printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n", | ||
1849 | dev->name, request->len, len); | ||
1850 | return -EINVAL; | ||
1851 | } | ||
1852 | |||
1853 | /* Only accept SET requests in here */ | ||
1854 | if (!IW_IS_SET(request->cmd)) | ||
1855 | return -EOPNOTSUPP; | ||
1856 | |||
1857 | /* Basic check */ | ||
1858 | if (!netif_device_present(dev)) | ||
1859 | return -ENODEV; | ||
1860 | |||
1861 | /* New driver API : try to find the handler */ | ||
1862 | handler = get_handler(dev, request->cmd); | ||
1863 | if (handler != NULL) { | ||
1864 | /* Standard and private are not the same */ | ||
1865 | if (request->cmd < SIOCIWFIRSTPRIV) | ||
1866 | return rtnetlink_standard_set(dev, | ||
1867 | request, | ||
1868 | request->len, | ||
1869 | handler); | ||
1870 | else | ||
1871 | return rtnetlink_private_set(dev, | ||
1872 | request, | ||
1873 | request->len, | ||
1874 | handler); | ||
1875 | } | ||
1876 | |||
1877 | return -EOPNOTSUPP; | ||
1878 | } | ||
1879 | #endif /* CONFIG_NET_WIRELESS_RTNETLINK */ | ||
1880 | |||
1881 | 1146 | ||
1882 | /************************* EVENT PROCESSING *************************/ | 1147 | /************************* EVENT PROCESSING *************************/ |
1883 | /* | 1148 | /* |
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 1863c0b07d45..a228d56a91b8 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig | |||
@@ -14,13 +14,3 @@ config WIRELESS_EXT | |||
14 | 14 | ||
15 | Say N (if you can) unless you know you need wireless | 15 | Say N (if you can) unless you know you need wireless |
16 | extensions for external modules. | 16 | extensions for external modules. |
17 | |||
18 | config NET_WIRELESS_RTNETLINK | ||
19 | bool "Wireless Extension API over RtNetlink" | ||
20 | depends on WIRELESS_EXT | ||
21 | ---help--- | ||
22 | Support the Wireless Extension API over the RtNetlink socket | ||
23 | in addition to the traditional ioctl interface (selected above). | ||
24 | |||
25 | For now, few tools use this facility, but it might grow in the | ||
26 | future. The only downside is that it adds 4.5 kB to your kernel. | ||