at v2.6.18-rc6 2307 lines 70 kB view raw
1/* 2 * This file implement the Wireless Extensions APIs. 3 * 4 * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com> 5 * Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved. 6 * 7 * (As all part of the Linux kernel, this file is GPL) 8 */ 9 10/************************** DOCUMENTATION **************************/ 11/* 12 * API definition : 13 * -------------- 14 * See <linux/wireless.h> for details of the APIs and the rest. 15 * 16 * History : 17 * ------- 18 * 19 * v1 - 5.12.01 - Jean II 20 * o Created this file. 21 * 22 * v2 - 13.12.01 - Jean II 23 * o Move /proc/net/wireless stuff from net/core/dev.c to here 24 * o Make Wireless Extension IOCTLs go through here 25 * o Added iw_handler handling ;-) 26 * o Added standard ioctl description 27 * o Initial dumb commit strategy based on orinoco.c 28 * 29 * v3 - 19.12.01 - Jean II 30 * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call 31 * o Add event dispatcher function 32 * o Add event description 33 * o Propagate events as rtnetlink IFLA_WIRELESS option 34 * o Generate event on selected SET requests 35 * 36 * v4 - 18.04.02 - Jean II 37 * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1 38 * 39 * v5 - 21.06.02 - Jean II 40 * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup) 41 * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes 42 * o Add IWEVCUSTOM for driver specific event/scanning token 43 * o Turn on WE_STRICT_WRITE by default + kernel warning 44 * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num) 45 * o Fix off-by-one in test (extra_size <= IFNAMSIZ) 46 * 47 * v6 - 9.01.03 - Jean II 48 * o Add common spy support : iw_handler_set_spy(), wireless_spy_update() 49 * o Add enhanced spy support : iw_handler_set_thrspy() and event. 50 * o Add WIRELESS_EXT version display in /proc/net/wireless 51 * 52 * v6 - 18.06.04 - Jean II 53 * o Change get_spydata() method for added safety 54 * o Remove spy #ifdef, they are always on -> cleaner code 55 * o Allow any size GET request if user specifies length > max 56 * and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV 57 * o Start migrating get_wireless_stats to struct iw_handler_def 58 * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus 59 * Based on patch from Pavel Roskin <proski@gnu.org> : 60 * o Fix kernel data leak to user space in private handler handling 61 * 62 * v7 - 18.3.05 - Jean II 63 * o Remove (struct iw_point *)->pointer from events and streams 64 * o Remove spy_offset from struct iw_handler_def 65 * o Start deprecating dev->get_wireless_stats, output a warning 66 * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless 67 * o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats) 68 * 69 * v8 - 17.02.06 - Jean II 70 * o RtNetlink requests support (SET/GET) 71 */ 72 73/***************************** INCLUDES *****************************/ 74 75#include <linux/config.h> /* Not needed ??? */ 76#include <linux/module.h> 77#include <linux/types.h> /* off_t */ 78#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ 79#include <linux/proc_fs.h> 80#include <linux/rtnetlink.h> /* rtnetlink stuff */ 81#include <linux/seq_file.h> 82#include <linux/init.h> /* for __init */ 83#include <linux/if_arp.h> /* ARPHRD_ETHER */ 84#include <linux/etherdevice.h> /* compare_ether_addr */ 85#include <linux/interrupt.h> 86 87#include <linux/wireless.h> /* Pretty obvious */ 88#include <net/iw_handler.h> /* New driver API */ 89 90#include <asm/uaccess.h> /* copy_to_user() */ 91 92/**************************** CONSTANTS ****************************/ 93 94/* Debugging stuff */ 95#undef WE_IOCTL_DEBUG /* Debug IOCTL API */ 96#undef WE_RTNETLINK_DEBUG /* Debug RtNetlink API */ 97#undef WE_EVENT_DEBUG /* Debug Event dispatcher */ 98#undef WE_SPY_DEBUG /* Debug enhanced spy support */ 99 100/* Options */ 101//CONFIG_NET_WIRELESS_RTNETLINK /* Wireless requests over RtNetlink */ 102#define WE_EVENT_RTNETLINK /* Propagate events using RtNetlink */ 103#define WE_SET_EVENT /* Generate an event on some set commands */ 104 105/************************* GLOBAL VARIABLES *************************/ 106/* 107 * You should not use global variables, because of re-entrancy. 108 * On our case, it's only const, so it's OK... 109 */ 110/* 111 * Meta-data about all the standard Wireless Extension request we 112 * know about. 113 */ 114static const struct iw_ioctl_description standard_ioctl[] = { 115 [SIOCSIWCOMMIT - SIOCIWFIRST] = { 116 .header_type = IW_HEADER_TYPE_NULL, 117 }, 118 [SIOCGIWNAME - SIOCIWFIRST] = { 119 .header_type = IW_HEADER_TYPE_CHAR, 120 .flags = IW_DESCR_FLAG_DUMP, 121 }, 122 [SIOCSIWNWID - SIOCIWFIRST] = { 123 .header_type = IW_HEADER_TYPE_PARAM, 124 .flags = IW_DESCR_FLAG_EVENT, 125 }, 126 [SIOCGIWNWID - SIOCIWFIRST] = { 127 .header_type = IW_HEADER_TYPE_PARAM, 128 .flags = IW_DESCR_FLAG_DUMP, 129 }, 130 [SIOCSIWFREQ - SIOCIWFIRST] = { 131 .header_type = IW_HEADER_TYPE_FREQ, 132 .flags = IW_DESCR_FLAG_EVENT, 133 }, 134 [SIOCGIWFREQ - SIOCIWFIRST] = { 135 .header_type = IW_HEADER_TYPE_FREQ, 136 .flags = IW_DESCR_FLAG_DUMP, 137 }, 138 [SIOCSIWMODE - SIOCIWFIRST] = { 139 .header_type = IW_HEADER_TYPE_UINT, 140 .flags = IW_DESCR_FLAG_EVENT, 141 }, 142 [SIOCGIWMODE - SIOCIWFIRST] = { 143 .header_type = IW_HEADER_TYPE_UINT, 144 .flags = IW_DESCR_FLAG_DUMP, 145 }, 146 [SIOCSIWSENS - SIOCIWFIRST] = { 147 .header_type = IW_HEADER_TYPE_PARAM, 148 }, 149 [SIOCGIWSENS - SIOCIWFIRST] = { 150 .header_type = IW_HEADER_TYPE_PARAM, 151 }, 152 [SIOCSIWRANGE - SIOCIWFIRST] = { 153 .header_type = IW_HEADER_TYPE_NULL, 154 }, 155 [SIOCGIWRANGE - SIOCIWFIRST] = { 156 .header_type = IW_HEADER_TYPE_POINT, 157 .token_size = 1, 158 .max_tokens = sizeof(struct iw_range), 159 .flags = IW_DESCR_FLAG_DUMP, 160 }, 161 [SIOCSIWPRIV - SIOCIWFIRST] = { 162 .header_type = IW_HEADER_TYPE_NULL, 163 }, 164 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ 165 .header_type = IW_HEADER_TYPE_POINT, 166 .token_size = sizeof(struct iw_priv_args), 167 .max_tokens = 16, 168 .flags = IW_DESCR_FLAG_NOMAX, 169 }, 170 [SIOCSIWSTATS - SIOCIWFIRST] = { 171 .header_type = IW_HEADER_TYPE_NULL, 172 }, 173 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ 174 .header_type = IW_HEADER_TYPE_POINT, 175 .token_size = 1, 176 .max_tokens = sizeof(struct iw_statistics), 177 .flags = IW_DESCR_FLAG_DUMP, 178 }, 179 [SIOCSIWSPY - SIOCIWFIRST] = { 180 .header_type = IW_HEADER_TYPE_POINT, 181 .token_size = sizeof(struct sockaddr), 182 .max_tokens = IW_MAX_SPY, 183 }, 184 [SIOCGIWSPY - SIOCIWFIRST] = { 185 .header_type = IW_HEADER_TYPE_POINT, 186 .token_size = sizeof(struct sockaddr) + 187 sizeof(struct iw_quality), 188 .max_tokens = IW_MAX_SPY, 189 }, 190 [SIOCSIWTHRSPY - SIOCIWFIRST] = { 191 .header_type = IW_HEADER_TYPE_POINT, 192 .token_size = sizeof(struct iw_thrspy), 193 .min_tokens = 1, 194 .max_tokens = 1, 195 }, 196 [SIOCGIWTHRSPY - SIOCIWFIRST] = { 197 .header_type = IW_HEADER_TYPE_POINT, 198 .token_size = sizeof(struct iw_thrspy), 199 .min_tokens = 1, 200 .max_tokens = 1, 201 }, 202 [SIOCSIWAP - SIOCIWFIRST] = { 203 .header_type = IW_HEADER_TYPE_ADDR, 204 }, 205 [SIOCGIWAP - SIOCIWFIRST] = { 206 .header_type = IW_HEADER_TYPE_ADDR, 207 .flags = IW_DESCR_FLAG_DUMP, 208 }, 209 [SIOCSIWMLME - SIOCIWFIRST] = { 210 .header_type = IW_HEADER_TYPE_POINT, 211 .token_size = 1, 212 .min_tokens = sizeof(struct iw_mlme), 213 .max_tokens = sizeof(struct iw_mlme), 214 }, 215 [SIOCGIWAPLIST - SIOCIWFIRST] = { 216 .header_type = IW_HEADER_TYPE_POINT, 217 .token_size = sizeof(struct sockaddr) + 218 sizeof(struct iw_quality), 219 .max_tokens = IW_MAX_AP, 220 .flags = IW_DESCR_FLAG_NOMAX, 221 }, 222 [SIOCSIWSCAN - SIOCIWFIRST] = { 223 .header_type = IW_HEADER_TYPE_POINT, 224 .token_size = 1, 225 .min_tokens = 0, 226 .max_tokens = sizeof(struct iw_scan_req), 227 }, 228 [SIOCGIWSCAN - SIOCIWFIRST] = { 229 .header_type = IW_HEADER_TYPE_POINT, 230 .token_size = 1, 231 .max_tokens = IW_SCAN_MAX_DATA, 232 .flags = IW_DESCR_FLAG_NOMAX, 233 }, 234 [SIOCSIWESSID - SIOCIWFIRST] = { 235 .header_type = IW_HEADER_TYPE_POINT, 236 .token_size = 1, 237 .max_tokens = IW_ESSID_MAX_SIZE + 1, 238 .flags = IW_DESCR_FLAG_EVENT, 239 }, 240 [SIOCGIWESSID - SIOCIWFIRST] = { 241 .header_type = IW_HEADER_TYPE_POINT, 242 .token_size = 1, 243 .max_tokens = IW_ESSID_MAX_SIZE + 1, 244 .flags = IW_DESCR_FLAG_DUMP, 245 }, 246 [SIOCSIWNICKN - SIOCIWFIRST] = { 247 .header_type = IW_HEADER_TYPE_POINT, 248 .token_size = 1, 249 .max_tokens = IW_ESSID_MAX_SIZE + 1, 250 }, 251 [SIOCGIWNICKN - SIOCIWFIRST] = { 252 .header_type = IW_HEADER_TYPE_POINT, 253 .token_size = 1, 254 .max_tokens = IW_ESSID_MAX_SIZE + 1, 255 }, 256 [SIOCSIWRATE - SIOCIWFIRST] = { 257 .header_type = IW_HEADER_TYPE_PARAM, 258 }, 259 [SIOCGIWRATE - SIOCIWFIRST] = { 260 .header_type = IW_HEADER_TYPE_PARAM, 261 }, 262 [SIOCSIWRTS - SIOCIWFIRST] = { 263 .header_type = IW_HEADER_TYPE_PARAM, 264 }, 265 [SIOCGIWRTS - SIOCIWFIRST] = { 266 .header_type = IW_HEADER_TYPE_PARAM, 267 }, 268 [SIOCSIWFRAG - SIOCIWFIRST] = { 269 .header_type = IW_HEADER_TYPE_PARAM, 270 }, 271 [SIOCGIWFRAG - SIOCIWFIRST] = { 272 .header_type = IW_HEADER_TYPE_PARAM, 273 }, 274 [SIOCSIWTXPOW - SIOCIWFIRST] = { 275 .header_type = IW_HEADER_TYPE_PARAM, 276 }, 277 [SIOCGIWTXPOW - SIOCIWFIRST] = { 278 .header_type = IW_HEADER_TYPE_PARAM, 279 }, 280 [SIOCSIWRETRY - SIOCIWFIRST] = { 281 .header_type = IW_HEADER_TYPE_PARAM, 282 }, 283 [SIOCGIWRETRY - SIOCIWFIRST] = { 284 .header_type = IW_HEADER_TYPE_PARAM, 285 }, 286 [SIOCSIWENCODE - SIOCIWFIRST] = { 287 .header_type = IW_HEADER_TYPE_POINT, 288 .token_size = 1, 289 .max_tokens = IW_ENCODING_TOKEN_MAX, 290 .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, 291 }, 292 [SIOCGIWENCODE - SIOCIWFIRST] = { 293 .header_type = IW_HEADER_TYPE_POINT, 294 .token_size = 1, 295 .max_tokens = IW_ENCODING_TOKEN_MAX, 296 .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, 297 }, 298 [SIOCSIWPOWER - SIOCIWFIRST] = { 299 .header_type = IW_HEADER_TYPE_PARAM, 300 }, 301 [SIOCGIWPOWER - SIOCIWFIRST] = { 302 .header_type = IW_HEADER_TYPE_PARAM, 303 }, 304 [SIOCSIWGENIE - SIOCIWFIRST] = { 305 .header_type = IW_HEADER_TYPE_POINT, 306 .token_size = 1, 307 .max_tokens = IW_GENERIC_IE_MAX, 308 }, 309 [SIOCGIWGENIE - SIOCIWFIRST] = { 310 .header_type = IW_HEADER_TYPE_POINT, 311 .token_size = 1, 312 .max_tokens = IW_GENERIC_IE_MAX, 313 }, 314 [SIOCSIWAUTH - SIOCIWFIRST] = { 315 .header_type = IW_HEADER_TYPE_PARAM, 316 }, 317 [SIOCGIWAUTH - SIOCIWFIRST] = { 318 .header_type = IW_HEADER_TYPE_PARAM, 319 }, 320 [SIOCSIWENCODEEXT - SIOCIWFIRST] = { 321 .header_type = IW_HEADER_TYPE_POINT, 322 .token_size = 1, 323 .min_tokens = sizeof(struct iw_encode_ext), 324 .max_tokens = sizeof(struct iw_encode_ext) + 325 IW_ENCODING_TOKEN_MAX, 326 }, 327 [SIOCGIWENCODEEXT - SIOCIWFIRST] = { 328 .header_type = IW_HEADER_TYPE_POINT, 329 .token_size = 1, 330 .min_tokens = sizeof(struct iw_encode_ext), 331 .max_tokens = sizeof(struct iw_encode_ext) + 332 IW_ENCODING_TOKEN_MAX, 333 }, 334 [SIOCSIWPMKSA - SIOCIWFIRST] = { 335 .header_type = IW_HEADER_TYPE_POINT, 336 .token_size = 1, 337 .min_tokens = sizeof(struct iw_pmksa), 338 .max_tokens = sizeof(struct iw_pmksa), 339 }, 340}; 341static const int standard_ioctl_num = (sizeof(standard_ioctl) / 342 sizeof(struct iw_ioctl_description)); 343 344/* 345 * Meta-data about all the additional standard Wireless Extension events 346 * we know about. 347 */ 348static const struct iw_ioctl_description standard_event[] = { 349 [IWEVTXDROP - IWEVFIRST] = { 350 .header_type = IW_HEADER_TYPE_ADDR, 351 }, 352 [IWEVQUAL - IWEVFIRST] = { 353 .header_type = IW_HEADER_TYPE_QUAL, 354 }, 355 [IWEVCUSTOM - IWEVFIRST] = { 356 .header_type = IW_HEADER_TYPE_POINT, 357 .token_size = 1, 358 .max_tokens = IW_CUSTOM_MAX, 359 }, 360 [IWEVREGISTERED - IWEVFIRST] = { 361 .header_type = IW_HEADER_TYPE_ADDR, 362 }, 363 [IWEVEXPIRED - IWEVFIRST] = { 364 .header_type = IW_HEADER_TYPE_ADDR, 365 }, 366 [IWEVGENIE - IWEVFIRST] = { 367 .header_type = IW_HEADER_TYPE_POINT, 368 .token_size = 1, 369 .max_tokens = IW_GENERIC_IE_MAX, 370 }, 371 [IWEVMICHAELMICFAILURE - IWEVFIRST] = { 372 .header_type = IW_HEADER_TYPE_POINT, 373 .token_size = 1, 374 .max_tokens = sizeof(struct iw_michaelmicfailure), 375 }, 376 [IWEVASSOCREQIE - IWEVFIRST] = { 377 .header_type = IW_HEADER_TYPE_POINT, 378 .token_size = 1, 379 .max_tokens = IW_GENERIC_IE_MAX, 380 }, 381 [IWEVASSOCRESPIE - IWEVFIRST] = { 382 .header_type = IW_HEADER_TYPE_POINT, 383 .token_size = 1, 384 .max_tokens = IW_GENERIC_IE_MAX, 385 }, 386 [IWEVPMKIDCAND - IWEVFIRST] = { 387 .header_type = IW_HEADER_TYPE_POINT, 388 .token_size = 1, 389 .max_tokens = sizeof(struct iw_pmkid_cand), 390 }, 391}; 392static const int standard_event_num = (sizeof(standard_event) / 393 sizeof(struct iw_ioctl_description)); 394 395/* Size (in bytes) of the various private data types */ 396static const char iw_priv_type_size[] = { 397 0, /* IW_PRIV_TYPE_NONE */ 398 1, /* IW_PRIV_TYPE_BYTE */ 399 1, /* IW_PRIV_TYPE_CHAR */ 400 0, /* Not defined */ 401 sizeof(__u32), /* IW_PRIV_TYPE_INT */ 402 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ 403 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ 404 0, /* Not defined */ 405}; 406 407/* Size (in bytes) of various events */ 408static const int event_type_size[] = { 409 IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ 410 0, 411 IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ 412 0, 413 IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ 414 IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ 415 IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ 416 0, 417 IW_EV_POINT_LEN, /* Without variable payload */ 418 IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ 419 IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ 420}; 421 422/************************ COMMON SUBROUTINES ************************/ 423/* 424 * Stuff that may be used in various place or doesn't fit in one 425 * of the section below. 426 */ 427 428/* ---------------------------------------------------------------- */ 429/* 430 * Return the driver handler associated with a specific Wireless Extension. 431 * Called from various place, so make sure it remains efficient. 432 */ 433static inline iw_handler get_handler(struct net_device *dev, 434 unsigned int cmd) 435{ 436 /* Don't "optimise" the following variable, it will crash */ 437 unsigned int index; /* *MUST* be unsigned */ 438 439 /* Check if we have some wireless handlers defined */ 440 if(dev->wireless_handlers == NULL) 441 return NULL; 442 443 /* Try as a standard command */ 444 index = cmd - SIOCIWFIRST; 445 if(index < dev->wireless_handlers->num_standard) 446 return dev->wireless_handlers->standard[index]; 447 448 /* Try as a private command */ 449 index = cmd - SIOCIWFIRSTPRIV; 450 if(index < dev->wireless_handlers->num_private) 451 return dev->wireless_handlers->private[index]; 452 453 /* Not found */ 454 return NULL; 455} 456 457/* ---------------------------------------------------------------- */ 458/* 459 * Get statistics out of the driver 460 */ 461static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) 462{ 463 /* New location */ 464 if((dev->wireless_handlers != NULL) && 465 (dev->wireless_handlers->get_wireless_stats != NULL)) 466 return dev->wireless_handlers->get_wireless_stats(dev); 467 468 /* Old location, field to be removed in next WE */ 469 if(dev->get_wireless_stats) { 470 static int printed_message; 471 472 if (!printed_message++) 473 printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n", 474 dev->name); 475 476 return dev->get_wireless_stats(dev); 477 } 478 479 /* Not found */ 480 return (struct iw_statistics *) NULL; 481} 482 483/* ---------------------------------------------------------------- */ 484/* 485 * Call the commit handler in the driver 486 * (if exist and if conditions are right) 487 * 488 * Note : our current commit strategy is currently pretty dumb, 489 * but we will be able to improve on that... 490 * The goal is to try to agreagate as many changes as possible 491 * before doing the commit. Drivers that will define a commit handler 492 * are usually those that need a reset after changing parameters, so 493 * we want to minimise the number of reset. 494 * A cool idea is to use a timer : at each "set" command, we re-set the 495 * timer, when the timer eventually fires, we call the driver. 496 * Hopefully, more on that later. 497 * 498 * Also, I'm waiting to see how many people will complain about the 499 * netif_running(dev) test. I'm open on that one... 500 * Hopefully, the driver will remember to do a commit in "open()" ;-) 501 */ 502static inline int call_commit_handler(struct net_device * dev) 503{ 504 if((netif_running(dev)) && 505 (dev->wireless_handlers->standard[0] != NULL)) { 506 /* Call the commit handler on the driver */ 507 return dev->wireless_handlers->standard[0](dev, NULL, 508 NULL, NULL); 509 } else 510 return 0; /* Command completed successfully */ 511} 512 513/* ---------------------------------------------------------------- */ 514/* 515 * Calculate size of private arguments 516 */ 517static inline int get_priv_size(__u16 args) 518{ 519 int num = args & IW_PRIV_SIZE_MASK; 520 int type = (args & IW_PRIV_TYPE_MASK) >> 12; 521 522 return num * iw_priv_type_size[type]; 523} 524 525/* ---------------------------------------------------------------- */ 526/* 527 * Re-calculate the size of private arguments 528 */ 529static inline int adjust_priv_size(__u16 args, 530 union iwreq_data * wrqu) 531{ 532 int num = wrqu->data.length; 533 int max = args & IW_PRIV_SIZE_MASK; 534 int type = (args & IW_PRIV_TYPE_MASK) >> 12; 535 536 /* Make sure the driver doesn't goof up */ 537 if (max < num) 538 num = max; 539 540 return num * iw_priv_type_size[type]; 541} 542 543/* ---------------------------------------------------------------- */ 544/* 545 * Standard Wireless Handler : get wireless stats 546 * Allow programatic access to /proc/net/wireless even if /proc 547 * doesn't exist... Also more efficient... 548 */ 549static int iw_handler_get_iwstats(struct net_device * dev, 550 struct iw_request_info * info, 551 union iwreq_data * wrqu, 552 char * extra) 553{ 554 /* Get stats from the driver */ 555 struct iw_statistics *stats; 556 557 stats = get_wireless_stats(dev); 558 if (stats != (struct iw_statistics *) NULL) { 559 560 /* Copy statistics to extra */ 561 memcpy(extra, stats, sizeof(struct iw_statistics)); 562 wrqu->data.length = sizeof(struct iw_statistics); 563 564 /* Check if we need to clear the updated flag */ 565 if(wrqu->data.flags != 0) 566 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 567 return 0; 568 } else 569 return -EOPNOTSUPP; 570} 571 572/* ---------------------------------------------------------------- */ 573/* 574 * Standard Wireless Handler : get iwpriv definitions 575 * Export the driver private handler definition 576 * They will be picked up by tools like iwpriv... 577 */ 578static int iw_handler_get_private(struct net_device * dev, 579 struct iw_request_info * info, 580 union iwreq_data * wrqu, 581 char * extra) 582{ 583 /* Check if the driver has something to export */ 584 if((dev->wireless_handlers->num_private_args == 0) || 585 (dev->wireless_handlers->private_args == NULL)) 586 return -EOPNOTSUPP; 587 588 /* Check if there is enough buffer up there */ 589 if(wrqu->data.length < dev->wireless_handlers->num_private_args) { 590 /* User space can't know in advance how large the buffer 591 * needs to be. Give it a hint, so that we can support 592 * any size buffer we want somewhat efficiently... */ 593 wrqu->data.length = dev->wireless_handlers->num_private_args; 594 return -E2BIG; 595 } 596 597 /* Set the number of available ioctls. */ 598 wrqu->data.length = dev->wireless_handlers->num_private_args; 599 600 /* Copy structure to the user buffer. */ 601 memcpy(extra, dev->wireless_handlers->private_args, 602 sizeof(struct iw_priv_args) * wrqu->data.length); 603 604 return 0; 605} 606 607 608/******************** /proc/net/wireless SUPPORT ********************/ 609/* 610 * The /proc/net/wireless file is a human readable user-space interface 611 * exporting various wireless specific statistics from the wireless devices. 612 * This is the most popular part of the Wireless Extensions ;-) 613 * 614 * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). 615 * The content of the file is basically the content of "struct iw_statistics". 616 */ 617 618#ifdef CONFIG_PROC_FS 619 620/* ---------------------------------------------------------------- */ 621/* 622 * Print one entry (line) of /proc/net/wireless 623 */ 624static __inline__ void wireless_seq_printf_stats(struct seq_file *seq, 625 struct net_device *dev) 626{ 627 /* Get stats from the driver */ 628 struct iw_statistics *stats = get_wireless_stats(dev); 629 630 if (stats) { 631 seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " 632 "%6d %6d %6d\n", 633 dev->name, stats->status, stats->qual.qual, 634 stats->qual.updated & IW_QUAL_QUAL_UPDATED 635 ? '.' : ' ', 636 ((__s32) stats->qual.level) - 637 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), 638 stats->qual.updated & IW_QUAL_LEVEL_UPDATED 639 ? '.' : ' ', 640 ((__s32) stats->qual.noise) - 641 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), 642 stats->qual.updated & IW_QUAL_NOISE_UPDATED 643 ? '.' : ' ', 644 stats->discard.nwid, stats->discard.code, 645 stats->discard.fragment, stats->discard.retries, 646 stats->discard.misc, stats->miss.beacon); 647 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 648 } 649} 650 651/* ---------------------------------------------------------------- */ 652/* 653 * Print info for /proc/net/wireless (print all entries) 654 */ 655static int wireless_seq_show(struct seq_file *seq, void *v) 656{ 657 if (v == SEQ_START_TOKEN) 658 seq_printf(seq, "Inter-| sta-| Quality | Discarded " 659 "packets | Missed | WE\n" 660 " face | tus | link level noise | nwid " 661 "crypt frag retry misc | beacon | %d\n", 662 WIRELESS_EXT); 663 else 664 wireless_seq_printf_stats(seq, v); 665 return 0; 666} 667 668static struct seq_operations wireless_seq_ops = { 669 .start = dev_seq_start, 670 .next = dev_seq_next, 671 .stop = dev_seq_stop, 672 .show = wireless_seq_show, 673}; 674 675static int wireless_seq_open(struct inode *inode, struct file *file) 676{ 677 return seq_open(file, &wireless_seq_ops); 678} 679 680static struct file_operations wireless_seq_fops = { 681 .owner = THIS_MODULE, 682 .open = wireless_seq_open, 683 .read = seq_read, 684 .llseek = seq_lseek, 685 .release = seq_release, 686}; 687 688int __init wireless_proc_init(void) 689{ 690 /* Create /proc/net/wireless entry */ 691 if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops)) 692 return -ENOMEM; 693 694 return 0; 695} 696#endif /* CONFIG_PROC_FS */ 697 698/************************** IOCTL SUPPORT **************************/ 699/* 700 * The original user space API to configure all those Wireless Extensions 701 * is through IOCTLs. 702 * In there, we check if we need to call the new driver API (iw_handler) 703 * or just call the driver ioctl handler. 704 */ 705 706/* ---------------------------------------------------------------- */ 707/* 708 * Wrapper to call a standard Wireless Extension handler. 709 * We do various checks and also take care of moving data between 710 * user space and kernel space. 711 */ 712static int ioctl_standard_call(struct net_device * dev, 713 struct ifreq * ifr, 714 unsigned int cmd, 715 iw_handler handler) 716{ 717 struct iwreq * iwr = (struct iwreq *) ifr; 718 const struct iw_ioctl_description * descr; 719 struct iw_request_info info; 720 int ret = -EINVAL; 721 722 /* Get the description of the IOCTL */ 723 if((cmd - SIOCIWFIRST) >= standard_ioctl_num) 724 return -EOPNOTSUPP; 725 descr = &(standard_ioctl[cmd - SIOCIWFIRST]); 726 727#ifdef WE_IOCTL_DEBUG 728 printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n", 729 ifr->ifr_name, cmd); 730 printk(KERN_DEBUG "%s (WE) : 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); 731#endif /* WE_IOCTL_DEBUG */ 732 733 /* Prepare the call */ 734 info.cmd = cmd; 735 info.flags = 0; 736 737 /* Check if we have a pointer to user space data or not */ 738 if(descr->header_type != IW_HEADER_TYPE_POINT) { 739 740 /* No extra arguments. Trivial to handle */ 741 ret = handler(dev, &info, &(iwr->u), NULL); 742 743#ifdef WE_SET_EVENT 744 /* Generate an event to notify listeners of the change */ 745 if((descr->flags & IW_DESCR_FLAG_EVENT) && 746 ((ret == 0) || (ret == -EIWCOMMIT))) 747 wireless_send_event(dev, cmd, &(iwr->u), NULL); 748#endif /* WE_SET_EVENT */ 749 } else { 750 char * extra; 751 int extra_size; 752 int user_length = 0; 753 int err; 754 755 /* Calculate space needed by arguments. Always allocate 756 * for max space. Easier, and won't last long... */ 757 extra_size = descr->max_tokens * descr->token_size; 758 759 /* Check what user space is giving us */ 760 if(IW_IS_SET(cmd)) { 761 /* Check NULL pointer */ 762 if((iwr->u.data.pointer == NULL) && 763 (iwr->u.data.length != 0)) 764 return -EFAULT; 765 /* Check if number of token fits within bounds */ 766 if(iwr->u.data.length > descr->max_tokens) 767 return -E2BIG; 768 if(iwr->u.data.length < descr->min_tokens) 769 return -EINVAL; 770 } else { 771 /* Check NULL pointer */ 772 if(iwr->u.data.pointer == NULL) 773 return -EFAULT; 774 /* Save user space buffer size for checking */ 775 user_length = iwr->u.data.length; 776 777 /* Don't check if user_length > max to allow forward 778 * compatibility. The test user_length < min is 779 * implied by the test at the end. */ 780 781 /* Support for very large requests */ 782 if((descr->flags & IW_DESCR_FLAG_NOMAX) && 783 (user_length > descr->max_tokens)) { 784 /* Allow userspace to GET more than max so 785 * we can support any size GET requests. 786 * There is still a limit : -ENOMEM. */ 787 extra_size = user_length * descr->token_size; 788 /* Note : user_length is originally a __u16, 789 * and token_size is controlled by us, 790 * so extra_size won't get negative and 791 * won't overflow... */ 792 } 793 } 794 795#ifdef WE_IOCTL_DEBUG 796 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", 797 dev->name, extra_size); 798#endif /* WE_IOCTL_DEBUG */ 799 800 /* Create the kernel buffer */ 801 extra = kmalloc(extra_size, GFP_KERNEL); 802 if (extra == NULL) { 803 return -ENOMEM; 804 } 805 806 /* If it is a SET, get all the extra data in here */ 807 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { 808 err = copy_from_user(extra, iwr->u.data.pointer, 809 iwr->u.data.length * 810 descr->token_size); 811 if (err) { 812 kfree(extra); 813 return -EFAULT; 814 } 815#ifdef WE_IOCTL_DEBUG 816 printk(KERN_DEBUG "%s (WE) : Got %d bytes\n", 817 dev->name, 818 iwr->u.data.length * descr->token_size); 819#endif /* WE_IOCTL_DEBUG */ 820 } 821 822 /* Call the handler */ 823 ret = handler(dev, &info, &(iwr->u), extra); 824 825 /* If we have something to return to the user */ 826 if (!ret && IW_IS_GET(cmd)) { 827 /* Check if there is enough buffer up there */ 828 if(user_length < iwr->u.data.length) { 829 kfree(extra); 830 return -E2BIG; 831 } 832 833 err = copy_to_user(iwr->u.data.pointer, extra, 834 iwr->u.data.length * 835 descr->token_size); 836 if (err) 837 ret = -EFAULT; 838#ifdef WE_IOCTL_DEBUG 839 printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n", 840 dev->name, 841 iwr->u.data.length * descr->token_size); 842#endif /* WE_IOCTL_DEBUG */ 843 } 844 845#ifdef WE_SET_EVENT 846 /* Generate an event to notify listeners of the change */ 847 if((descr->flags & IW_DESCR_FLAG_EVENT) && 848 ((ret == 0) || (ret == -EIWCOMMIT))) { 849 if(descr->flags & IW_DESCR_FLAG_RESTRICT) 850 /* If the event is restricted, don't 851 * export the payload */ 852 wireless_send_event(dev, cmd, &(iwr->u), NULL); 853 else 854 wireless_send_event(dev, cmd, &(iwr->u), 855 extra); 856 } 857#endif /* WE_SET_EVENT */ 858 859 /* Cleanup - I told you it wasn't that long ;-) */ 860 kfree(extra); 861 } 862 863 /* Call commit handler if needed and defined */ 864 if(ret == -EIWCOMMIT) 865 ret = call_commit_handler(dev); 866 867 /* Here, we will generate the appropriate event if needed */ 868 869 return ret; 870} 871 872/* ---------------------------------------------------------------- */ 873/* 874 * Wrapper to call a private Wireless Extension handler. 875 * We do various checks and also take care of moving data between 876 * user space and kernel space. 877 * It's not as nice and slimline as the standard wrapper. The cause 878 * is struct iw_priv_args, which was not really designed for the 879 * job we are going here. 880 * 881 * IMPORTANT : This function prevent to set and get data on the same 882 * IOCTL and enforce the SET/GET convention. Not doing it would be 883 * far too hairy... 884 * If you need to set and get data at the same time, please don't use 885 * a iw_handler but process it in your ioctl handler (i.e. use the 886 * old driver API). 887 */ 888static inline int ioctl_private_call(struct net_device * dev, 889 struct ifreq * ifr, 890 unsigned int cmd, 891 iw_handler handler) 892{ 893 struct iwreq * iwr = (struct iwreq *) ifr; 894 const struct iw_priv_args * descr = NULL; 895 struct iw_request_info info; 896 int extra_size = 0; 897 int i; 898 int ret = -EINVAL; 899 900 /* Get the description of the IOCTL */ 901 for(i = 0; i < dev->wireless_handlers->num_private_args; i++) 902 if(cmd == dev->wireless_handlers->private_args[i].cmd) { 903 descr = &(dev->wireless_handlers->private_args[i]); 904 break; 905 } 906 907#ifdef WE_IOCTL_DEBUG 908 printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n", 909 ifr->ifr_name, cmd); 910 if(descr) { 911 printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n", 912 dev->name, descr->name, 913 descr->set_args, descr->get_args); 914 } 915#endif /* WE_IOCTL_DEBUG */ 916 917 /* Compute the size of the set/get arguments */ 918 if(descr != NULL) { 919 if(IW_IS_SET(cmd)) { 920 int offset = 0; /* For sub-ioctls */ 921 /* Check for sub-ioctl handler */ 922 if(descr->name[0] == '\0') 923 /* Reserve one int for sub-ioctl index */ 924 offset = sizeof(__u32); 925 926 /* Size of set arguments */ 927 extra_size = get_priv_size(descr->set_args); 928 929 /* Does it fits in iwr ? */ 930 if((descr->set_args & IW_PRIV_SIZE_FIXED) && 931 ((extra_size + offset) <= IFNAMSIZ)) 932 extra_size = 0; 933 } else { 934 /* Size of get arguments */ 935 extra_size = get_priv_size(descr->get_args); 936 937 /* Does it fits in iwr ? */ 938 if((descr->get_args & IW_PRIV_SIZE_FIXED) && 939 (extra_size <= IFNAMSIZ)) 940 extra_size = 0; 941 } 942 } 943 944 /* Prepare the call */ 945 info.cmd = cmd; 946 info.flags = 0; 947 948 /* Check if we have a pointer to user space data or not. */ 949 if(extra_size == 0) { 950 /* No extra arguments. Trivial to handle */ 951 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); 952 } else { 953 char * extra; 954 int err; 955 956 /* Check what user space is giving us */ 957 if(IW_IS_SET(cmd)) { 958 /* Check NULL pointer */ 959 if((iwr->u.data.pointer == NULL) && 960 (iwr->u.data.length != 0)) 961 return -EFAULT; 962 963 /* Does it fits within bounds ? */ 964 if(iwr->u.data.length > (descr->set_args & 965 IW_PRIV_SIZE_MASK)) 966 return -E2BIG; 967 } else { 968 /* Check NULL pointer */ 969 if(iwr->u.data.pointer == NULL) 970 return -EFAULT; 971 } 972 973#ifdef WE_IOCTL_DEBUG 974 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", 975 dev->name, extra_size); 976#endif /* WE_IOCTL_DEBUG */ 977 978 /* Always allocate for max space. Easier, and won't last 979 * long... */ 980 extra = kmalloc(extra_size, GFP_KERNEL); 981 if (extra == NULL) { 982 return -ENOMEM; 983 } 984 985 /* If it is a SET, get all the extra data in here */ 986 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { 987 err = copy_from_user(extra, iwr->u.data.pointer, 988 extra_size); 989 if (err) { 990 kfree(extra); 991 return -EFAULT; 992 } 993#ifdef WE_IOCTL_DEBUG 994 printk(KERN_DEBUG "%s (WE) : Got %d elem\n", 995 dev->name, iwr->u.data.length); 996#endif /* WE_IOCTL_DEBUG */ 997 } 998 999 /* Call the handler */ 1000 ret = handler(dev, &info, &(iwr->u), extra); 1001 1002 /* If we have something to return to the user */ 1003 if (!ret && IW_IS_GET(cmd)) { 1004 1005 /* Adjust for the actual length if it's variable, 1006 * avoid leaking kernel bits outside. */ 1007 if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) { 1008 extra_size = adjust_priv_size(descr->get_args, 1009 &(iwr->u)); 1010 } 1011 1012 err = copy_to_user(iwr->u.data.pointer, extra, 1013 extra_size); 1014 if (err) 1015 ret = -EFAULT; 1016#ifdef WE_IOCTL_DEBUG 1017 printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n", 1018 dev->name, iwr->u.data.length); 1019#endif /* WE_IOCTL_DEBUG */ 1020 } 1021 1022 /* Cleanup - I told you it wasn't that long ;-) */ 1023 kfree(extra); 1024 } 1025 1026 1027 /* Call commit handler if needed and defined */ 1028 if(ret == -EIWCOMMIT) 1029 ret = call_commit_handler(dev); 1030 1031 return ret; 1032} 1033 1034/* ---------------------------------------------------------------- */ 1035/* 1036 * Main IOCTl dispatcher. Called from the main networking code 1037 * (dev_ioctl() in net/core/dev.c). 1038 * Check the type of IOCTL and call the appropriate wrapper... 1039 */ 1040int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) 1041{ 1042 struct net_device *dev; 1043 iw_handler handler; 1044 1045 /* Permissions are already checked in dev_ioctl() before calling us. 1046 * The copy_to/from_user() of ifr is also dealt with in there */ 1047 1048 /* Make sure the device exist */ 1049 if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) 1050 return -ENODEV; 1051 1052 /* A bunch of special cases, then the generic case... 1053 * Note that 'cmd' is already filtered in dev_ioctl() with 1054 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ 1055 switch(cmd) 1056 { 1057 case SIOCGIWSTATS: 1058 /* Get Wireless Stats */ 1059 return ioctl_standard_call(dev, 1060 ifr, 1061 cmd, 1062 &iw_handler_get_iwstats); 1063 1064 case SIOCGIWPRIV: 1065 /* Check if we have some wireless handlers defined */ 1066 if(dev->wireless_handlers != NULL) { 1067 /* We export to user space the definition of 1068 * the private handler ourselves */ 1069 return ioctl_standard_call(dev, 1070 ifr, 1071 cmd, 1072 &iw_handler_get_private); 1073 } 1074 // ## Fall-through for old API ## 1075 default: 1076 /* Generic IOCTL */ 1077 /* Basic check */ 1078 if (!netif_device_present(dev)) 1079 return -ENODEV; 1080 /* New driver API : try to find the handler */ 1081 handler = get_handler(dev, cmd); 1082 if(handler != NULL) { 1083 /* Standard and private are not the same */ 1084 if(cmd < SIOCIWFIRSTPRIV) 1085 return ioctl_standard_call(dev, 1086 ifr, 1087 cmd, 1088 handler); 1089 else 1090 return ioctl_private_call(dev, 1091 ifr, 1092 cmd, 1093 handler); 1094 } 1095 /* Old driver API : call driver ioctl handler */ 1096 if (dev->do_ioctl) { 1097 return dev->do_ioctl(dev, ifr, cmd); 1098 } 1099 return -EOPNOTSUPP; 1100 } 1101 /* Not reached */ 1102 return -EINVAL; 1103} 1104 1105/********************** RTNETLINK REQUEST API **********************/ 1106/* 1107 * The alternate user space API to configure all those Wireless Extensions 1108 * is through RtNetlink. 1109 * This API support only the new driver API (iw_handler). 1110 * 1111 * This RtNetlink API use the same query/reply model as the ioctl API. 1112 * Maximum effort has been done to fit in the RtNetlink model, and 1113 * we support both RtNetlink Set and RtNelink Get operations. 1114 * On the other hand, we don't offer Dump operations because of the 1115 * following reasons : 1116 * o Large number of parameters, most optional 1117 * o Large size of some parameters (> 100 bytes) 1118 * o Each parameters need to be extracted from hardware 1119 * o Scan requests can take seconds and disable network activity. 1120 * Because of this high cost/overhead, we want to return only the 1121 * parameters the user application is really interested in. 1122 * We could offer partial Dump using the IW_DESCR_FLAG_DUMP flag. 1123 * 1124 * The API uses the standard RtNetlink socket. When the RtNetlink code 1125 * find a IFLA_WIRELESS field in a RtNetlink SET_LINK request, 1126 * it calls here. 1127 */ 1128 1129#ifdef CONFIG_NET_WIRELESS_RTNETLINK 1130/* ---------------------------------------------------------------- */ 1131/* 1132 * Wrapper to call a standard Wireless Extension GET handler. 1133 * We do various checks and call the handler with the proper args. 1134 */ 1135static int rtnetlink_standard_get(struct net_device * dev, 1136 struct iw_event * request, 1137 int request_len, 1138 iw_handler handler, 1139 char ** p_buf, 1140 int * p_len) 1141{ 1142 const struct iw_ioctl_description * descr = NULL; 1143 unsigned int cmd; 1144 union iwreq_data * wrqu; 1145 int hdr_len; 1146 struct iw_request_info info; 1147 char * buffer = NULL; 1148 int buffer_size = 0; 1149 int ret = -EINVAL; 1150 1151 /* Get the description of the Request */ 1152 cmd = request->cmd; 1153 if((cmd - SIOCIWFIRST) >= standard_ioctl_num) 1154 return -EOPNOTSUPP; 1155 descr = &(standard_ioctl[cmd - SIOCIWFIRST]); 1156 1157#ifdef WE_RTNETLINK_DEBUG 1158 printk(KERN_DEBUG "%s (WE.r) : Found standard handler for 0x%04X\n", 1159 dev->name, cmd); 1160 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); 1161#endif /* WE_RTNETLINK_DEBUG */ 1162 1163 /* Check if wrqu is complete */ 1164 hdr_len = event_type_size[descr->header_type]; 1165 if(request_len < hdr_len) { 1166#ifdef WE_RTNETLINK_DEBUG 1167 printk(KERN_DEBUG 1168 "%s (WE.r) : Wireless request too short (%d)\n", 1169 dev->name, request_len); 1170#endif /* WE_RTNETLINK_DEBUG */ 1171 return -EINVAL; 1172 } 1173 1174 /* Prepare the call */ 1175 info.cmd = cmd; 1176 info.flags = 0; 1177 1178 /* Check if we have extra data in the reply or not */ 1179 if(descr->header_type != IW_HEADER_TYPE_POINT) { 1180 1181 /* Create the kernel buffer that we will return. 1182 * It's at an offset to match the TYPE_POINT case... */ 1183 buffer_size = request_len + IW_EV_POINT_OFF; 1184 buffer = kmalloc(buffer_size, GFP_KERNEL); 1185 if (buffer == NULL) { 1186 return -ENOMEM; 1187 } 1188 /* Copy event data */ 1189 memcpy(buffer + IW_EV_POINT_OFF, request, request_len); 1190 /* Use our own copy of wrqu */ 1191 wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF 1192 + IW_EV_LCP_LEN); 1193 1194 /* No extra arguments. Trivial to handle */ 1195 ret = handler(dev, &info, wrqu, NULL); 1196 1197 } else { 1198 union iwreq_data wrqu_point; 1199 char * extra = NULL; 1200 int extra_size = 0; 1201 1202 /* Get a temp copy of wrqu (skip pointer) */ 1203 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, 1204 ((char *) request) + IW_EV_LCP_LEN, 1205 IW_EV_POINT_LEN - IW_EV_LCP_LEN); 1206 1207 /* Calculate space needed by arguments. Always allocate 1208 * for max space. Easier, and won't last long... */ 1209 extra_size = descr->max_tokens * descr->token_size; 1210 /* Support for very large requests */ 1211 if((descr->flags & IW_DESCR_FLAG_NOMAX) && 1212 (wrqu_point.data.length > descr->max_tokens)) 1213 extra_size = (wrqu_point.data.length 1214 * descr->token_size); 1215 buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF; 1216#ifdef WE_RTNETLINK_DEBUG 1217 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", 1218 dev->name, extra_size, buffer_size); 1219#endif /* WE_RTNETLINK_DEBUG */ 1220 1221 /* Create the kernel buffer that we will return */ 1222 buffer = kmalloc(buffer_size, GFP_KERNEL); 1223 if (buffer == NULL) { 1224 return -ENOMEM; 1225 } 1226 1227 /* Put wrqu in the right place (just before extra). 1228 * Leave space for IWE header and dummy pointer... 1229 * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned... 1230 */ 1231 memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF, 1232 ((char *) &wrqu_point) + IW_EV_POINT_OFF, 1233 IW_EV_POINT_LEN - IW_EV_LCP_LEN); 1234 wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN); 1235 1236 /* Extra comes logically after that. Offset +12 bytes. */ 1237 extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN; 1238 1239 /* Call the handler */ 1240 ret = handler(dev, &info, wrqu, extra); 1241 1242 /* Calculate real returned length */ 1243 extra_size = (wrqu->data.length * descr->token_size); 1244 /* Re-adjust reply size */ 1245 request->len = extra_size + IW_EV_POINT_LEN; 1246 1247 /* Put the iwe header where it should, i.e. scrap the 1248 * dummy pointer. */ 1249 memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN); 1250 1251#ifdef WE_RTNETLINK_DEBUG 1252 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); 1253#endif /* WE_RTNETLINK_DEBUG */ 1254 1255 /* Check if there is enough buffer up there */ 1256 if(wrqu_point.data.length < wrqu->data.length) 1257 ret = -E2BIG; 1258 } 1259 1260 /* Return the buffer to the caller */ 1261 if (!ret) { 1262 *p_buf = buffer; 1263 *p_len = request->len; 1264 } else { 1265 /* Cleanup */ 1266 if(buffer) 1267 kfree(buffer); 1268 } 1269 1270 return ret; 1271} 1272 1273/* ---------------------------------------------------------------- */ 1274/* 1275 * Wrapper to call a standard Wireless Extension SET handler. 1276 * We do various checks and call the handler with the proper args. 1277 */ 1278static inline int rtnetlink_standard_set(struct net_device * dev, 1279 struct iw_event * request, 1280 int request_len, 1281 iw_handler handler) 1282{ 1283 const struct iw_ioctl_description * descr = NULL; 1284 unsigned int cmd; 1285 union iwreq_data * wrqu; 1286 union iwreq_data wrqu_point; 1287 int hdr_len; 1288 char * extra = NULL; 1289 int extra_size = 0; 1290 struct iw_request_info info; 1291 int ret = -EINVAL; 1292 1293 /* Get the description of the Request */ 1294 cmd = request->cmd; 1295 if((cmd - SIOCIWFIRST) >= standard_ioctl_num) 1296 return -EOPNOTSUPP; 1297 descr = &(standard_ioctl[cmd - SIOCIWFIRST]); 1298 1299#ifdef WE_RTNETLINK_DEBUG 1300 printk(KERN_DEBUG "%s (WE.r) : Found standard SET handler for 0x%04X\n", 1301 dev->name, cmd); 1302 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); 1303#endif /* WE_RTNETLINK_DEBUG */ 1304 1305 /* Extract fixed header from request. This is properly aligned. */ 1306 wrqu = &request->u; 1307 1308 /* Check if wrqu is complete */ 1309 hdr_len = event_type_size[descr->header_type]; 1310 if(request_len < hdr_len) { 1311#ifdef WE_RTNETLINK_DEBUG 1312 printk(KERN_DEBUG 1313 "%s (WE.r) : Wireless request too short (%d)\n", 1314 dev->name, request_len); 1315#endif /* WE_RTNETLINK_DEBUG */ 1316 return -EINVAL; 1317 } 1318 1319 /* Prepare the call */ 1320 info.cmd = cmd; 1321 info.flags = 0; 1322 1323 /* Check if we have extra data in the request or not */ 1324 if(descr->header_type != IW_HEADER_TYPE_POINT) { 1325 1326 /* No extra arguments. Trivial to handle */ 1327 ret = handler(dev, &info, wrqu, NULL); 1328 1329 } else { 1330 int extra_len; 1331 1332 /* Put wrqu in the right place (skip pointer) */ 1333 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, 1334 wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN); 1335 /* Don't forget about the event code... */ 1336 wrqu = &wrqu_point; 1337 1338 /* Check if number of token fits within bounds */ 1339 if(wrqu_point.data.length > descr->max_tokens) 1340 return -E2BIG; 1341 if(wrqu_point.data.length < descr->min_tokens) 1342 return -EINVAL; 1343 1344 /* Real length of payload */ 1345 extra_len = wrqu_point.data.length * descr->token_size; 1346 1347 /* Check if request is self consistent */ 1348 if((request_len - hdr_len) < extra_len) { 1349#ifdef WE_RTNETLINK_DEBUG 1350 printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n", 1351 dev->name, extra_size); 1352#endif /* WE_RTNETLINK_DEBUG */ 1353 return -EINVAL; 1354 } 1355 1356#ifdef WE_RTNETLINK_DEBUG 1357 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n", 1358 dev->name, extra_size); 1359#endif /* WE_RTNETLINK_DEBUG */ 1360 1361 /* Always allocate for max space. Easier, and won't last 1362 * long... */ 1363 extra_size = descr->max_tokens * descr->token_size; 1364 extra = kmalloc(extra_size, GFP_KERNEL); 1365 if (extra == NULL) 1366 return -ENOMEM; 1367 1368 /* Copy extra in aligned buffer */ 1369 memcpy(extra, ((char *) request) + hdr_len, extra_len); 1370 1371 /* Call the handler */ 1372 ret = handler(dev, &info, &wrqu_point, extra); 1373 } 1374 1375#ifdef WE_SET_EVENT 1376 /* Generate an event to notify listeners of the change */ 1377 if((descr->flags & IW_DESCR_FLAG_EVENT) && 1378 ((ret == 0) || (ret == -EIWCOMMIT))) { 1379 if(descr->flags & IW_DESCR_FLAG_RESTRICT) 1380 /* If the event is restricted, don't 1381 * export the payload */ 1382 wireless_send_event(dev, cmd, wrqu, NULL); 1383 else 1384 wireless_send_event(dev, cmd, wrqu, extra); 1385 } 1386#endif /* WE_SET_EVENT */ 1387 1388 /* Cleanup - I told you it wasn't that long ;-) */ 1389 if(extra) 1390 kfree(extra); 1391 1392 /* Call commit handler if needed and defined */ 1393 if(ret == -EIWCOMMIT) 1394 ret = call_commit_handler(dev); 1395 1396 return ret; 1397} 1398 1399/* ---------------------------------------------------------------- */ 1400/* 1401 * Wrapper to call a private Wireless Extension GET handler. 1402 * Same as above... 1403 * It's not as nice and slimline as the standard wrapper. The cause 1404 * is struct iw_priv_args, which was not really designed for the 1405 * job we are going here. 1406 * 1407 * IMPORTANT : This function prevent to set and get data on the same 1408 * IOCTL and enforce the SET/GET convention. Not doing it would be 1409 * far too hairy... 1410 * If you need to set and get data at the same time, please don't use 1411 * a iw_handler but process it in your ioctl handler (i.e. use the 1412 * old driver API). 1413 */ 1414static inline int rtnetlink_private_get(struct net_device * dev, 1415 struct iw_event * request, 1416 int request_len, 1417 iw_handler handler, 1418 char ** p_buf, 1419 int * p_len) 1420{ 1421 const struct iw_priv_args * descr = NULL; 1422 unsigned int cmd; 1423 union iwreq_data * wrqu; 1424 int hdr_len; 1425 struct iw_request_info info; 1426 int extra_size = 0; 1427 int i; 1428 char * buffer = NULL; 1429 int buffer_size = 0; 1430 int ret = -EINVAL; 1431 1432 /* Get the description of the Request */ 1433 cmd = request->cmd; 1434 for(i = 0; i < dev->wireless_handlers->num_private_args; i++) 1435 if(cmd == dev->wireless_handlers->private_args[i].cmd) { 1436 descr = &(dev->wireless_handlers->private_args[i]); 1437 break; 1438 } 1439 if(descr == NULL) 1440 return -EOPNOTSUPP; 1441 1442#ifdef WE_RTNETLINK_DEBUG 1443 printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n", 1444 dev->name, cmd); 1445 printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n", 1446 dev->name, descr->name, descr->set_args, descr->get_args); 1447#endif /* WE_RTNETLINK_DEBUG */ 1448 1449 /* Compute the max size of the get arguments */ 1450 extra_size = get_priv_size(descr->get_args); 1451 1452 /* Does it fits in wrqu ? */ 1453 if((descr->get_args & IW_PRIV_SIZE_FIXED) && 1454 (extra_size <= IFNAMSIZ)) { 1455 hdr_len = extra_size; 1456 extra_size = 0; 1457 } else { 1458 hdr_len = IW_EV_POINT_LEN; 1459 } 1460 1461 /* Check if wrqu is complete */ 1462 if(request_len < hdr_len) { 1463#ifdef WE_RTNETLINK_DEBUG 1464 printk(KERN_DEBUG 1465 "%s (WE.r) : Wireless request too short (%d)\n", 1466 dev->name, request_len); 1467#endif /* WE_RTNETLINK_DEBUG */ 1468 return -EINVAL; 1469 } 1470 1471 /* Prepare the call */ 1472 info.cmd = cmd; 1473 info.flags = 0; 1474 1475 /* Check if we have a pointer to user space data or not. */ 1476 if(extra_size == 0) { 1477 1478 /* Create the kernel buffer that we will return. 1479 * It's at an offset to match the TYPE_POINT case... */ 1480 buffer_size = request_len + IW_EV_POINT_OFF; 1481 buffer = kmalloc(buffer_size, GFP_KERNEL); 1482 if (buffer == NULL) { 1483 return -ENOMEM; 1484 } 1485 /* Copy event data */ 1486 memcpy(buffer + IW_EV_POINT_OFF, request, request_len); 1487 /* Use our own copy of wrqu */ 1488 wrqu = (union iwreq_data *) (buffer + IW_EV_POINT_OFF 1489 + IW_EV_LCP_LEN); 1490 1491 /* No extra arguments. Trivial to handle */ 1492 ret = handler(dev, &info, wrqu, (char *) wrqu); 1493 1494 } else { 1495 char * extra; 1496 1497 /* Buffer for full reply */ 1498 buffer_size = extra_size + IW_EV_POINT_LEN + IW_EV_POINT_OFF; 1499 1500#ifdef WE_RTNETLINK_DEBUG 1501 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes (%d bytes)\n", 1502 dev->name, extra_size, buffer_size); 1503#endif /* WE_RTNETLINK_DEBUG */ 1504 1505 /* Create the kernel buffer that we will return */ 1506 buffer = kmalloc(buffer_size, GFP_KERNEL); 1507 if (buffer == NULL) { 1508 return -ENOMEM; 1509 } 1510 1511 /* Put wrqu in the right place (just before extra). 1512 * Leave space for IWE header and dummy pointer... 1513 * Note that IW_EV_LCP_LEN==4 bytes, so it's still aligned... 1514 */ 1515 memcpy(buffer + IW_EV_LCP_LEN + IW_EV_POINT_OFF, 1516 ((char *) request) + IW_EV_LCP_LEN, 1517 IW_EV_POINT_LEN - IW_EV_LCP_LEN); 1518 wrqu = (union iwreq_data *) (buffer + IW_EV_LCP_LEN); 1519 1520 /* Extra comes logically after that. Offset +12 bytes. */ 1521 extra = buffer + IW_EV_POINT_OFF + IW_EV_POINT_LEN; 1522 1523 /* Call the handler */ 1524 ret = handler(dev, &info, wrqu, extra); 1525 1526 /* Adjust for the actual length if it's variable, 1527 * avoid leaking kernel bits outside. */ 1528 if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) 1529 extra_size = adjust_priv_size(descr->get_args, wrqu); 1530 /* Re-adjust reply size */ 1531 request->len = extra_size + IW_EV_POINT_LEN; 1532 1533 /* Put the iwe header where it should, i.e. scrap the 1534 * dummy pointer. */ 1535 memcpy(buffer + IW_EV_POINT_OFF, request, IW_EV_LCP_LEN); 1536 1537#ifdef WE_RTNETLINK_DEBUG 1538 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); 1539#endif /* WE_RTNETLINK_DEBUG */ 1540 } 1541 1542 /* Return the buffer to the caller */ 1543 if (!ret) { 1544 *p_buf = buffer; 1545 *p_len = request->len; 1546 } else { 1547 /* Cleanup */ 1548 if(buffer) 1549 kfree(buffer); 1550 } 1551 1552 return ret; 1553} 1554 1555/* ---------------------------------------------------------------- */ 1556/* 1557 * Wrapper to call a private Wireless Extension SET handler. 1558 * Same as above... 1559 * It's not as nice and slimline as the standard wrapper. The cause 1560 * is struct iw_priv_args, which was not really designed for the 1561 * job we are going here. 1562 * 1563 * IMPORTANT : This function prevent to set and get data on the same 1564 * IOCTL and enforce the SET/GET convention. Not doing it would be 1565 * far too hairy... 1566 * If you need to set and get data at the same time, please don't use 1567 * a iw_handler but process it in your ioctl handler (i.e. use the 1568 * old driver API). 1569 */ 1570static inline int rtnetlink_private_set(struct net_device * dev, 1571 struct iw_event * request, 1572 int request_len, 1573 iw_handler handler) 1574{ 1575 const struct iw_priv_args * descr = NULL; 1576 unsigned int cmd; 1577 union iwreq_data * wrqu; 1578 union iwreq_data wrqu_point; 1579 int hdr_len; 1580 char * extra = NULL; 1581 int extra_size = 0; 1582 int offset = 0; /* For sub-ioctls */ 1583 struct iw_request_info info; 1584 int i; 1585 int ret = -EINVAL; 1586 1587 /* Get the description of the Request */ 1588 cmd = request->cmd; 1589 for(i = 0; i < dev->wireless_handlers->num_private_args; i++) 1590 if(cmd == dev->wireless_handlers->private_args[i].cmd) { 1591 descr = &(dev->wireless_handlers->private_args[i]); 1592 break; 1593 } 1594 if(descr == NULL) 1595 return -EOPNOTSUPP; 1596 1597#ifdef WE_RTNETLINK_DEBUG 1598 printk(KERN_DEBUG "%s (WE.r) : Found private handler for 0x%04X\n", 1599 ifr->ifr_name, cmd); 1600 printk(KERN_DEBUG "%s (WE.r) : Name %s, set %X, get %X\n", 1601 dev->name, descr->name, descr->set_args, descr->get_args); 1602#endif /* WE_RTNETLINK_DEBUG */ 1603 1604 /* Compute the size of the set arguments */ 1605 /* Check for sub-ioctl handler */ 1606 if(descr->name[0] == '\0') 1607 /* Reserve one int for sub-ioctl index */ 1608 offset = sizeof(__u32); 1609 1610 /* Size of set arguments */ 1611 extra_size = get_priv_size(descr->set_args); 1612 1613 /* Does it fits in wrqu ? */ 1614 if((descr->set_args & IW_PRIV_SIZE_FIXED) && 1615 (extra_size <= IFNAMSIZ)) { 1616 hdr_len = IW_EV_LCP_LEN + extra_size; 1617 extra_size = 0; 1618 } else { 1619 hdr_len = IW_EV_POINT_LEN; 1620 } 1621 1622 /* Extract fixed header from request. This is properly aligned. */ 1623 wrqu = &request->u; 1624 1625 /* Check if wrqu is complete */ 1626 if(request_len < hdr_len) { 1627#ifdef WE_RTNETLINK_DEBUG 1628 printk(KERN_DEBUG 1629 "%s (WE.r) : Wireless request too short (%d)\n", 1630 dev->name, request_len); 1631#endif /* WE_RTNETLINK_DEBUG */ 1632 return -EINVAL; 1633 } 1634 1635 /* Prepare the call */ 1636 info.cmd = cmd; 1637 info.flags = 0; 1638 1639 /* Check if we have a pointer to user space data or not. */ 1640 if(extra_size == 0) { 1641 1642 /* No extra arguments. Trivial to handle */ 1643 ret = handler(dev, &info, wrqu, (char *) wrqu); 1644 1645 } else { 1646 int extra_len; 1647 1648 /* Put wrqu in the right place (skip pointer) */ 1649 memcpy(((char *) &wrqu_point) + IW_EV_POINT_OFF, 1650 wrqu, IW_EV_POINT_LEN - IW_EV_LCP_LEN); 1651 1652 /* Does it fits within bounds ? */ 1653 if(wrqu_point.data.length > (descr->set_args & 1654 IW_PRIV_SIZE_MASK)) 1655 return -E2BIG; 1656 1657 /* Real length of payload */ 1658 extra_len = adjust_priv_size(descr->set_args, &wrqu_point); 1659 1660 /* Check if request is self consistent */ 1661 if((request_len - hdr_len) < extra_len) { 1662#ifdef WE_RTNETLINK_DEBUG 1663 printk(KERN_DEBUG "%s (WE.r) : Wireless request data too short (%d)\n", 1664 dev->name, extra_size); 1665#endif /* WE_RTNETLINK_DEBUG */ 1666 return -EINVAL; 1667 } 1668 1669#ifdef WE_RTNETLINK_DEBUG 1670 printk(KERN_DEBUG "%s (WE.r) : Malloc %d bytes\n", 1671 dev->name, extra_size); 1672#endif /* WE_RTNETLINK_DEBUG */ 1673 1674 /* Always allocate for max space. Easier, and won't last 1675 * long... */ 1676 extra = kmalloc(extra_size, GFP_KERNEL); 1677 if (extra == NULL) 1678 return -ENOMEM; 1679 1680 /* Copy extra in aligned buffer */ 1681 memcpy(extra, ((char *) request) + hdr_len, extra_len); 1682 1683 /* Call the handler */ 1684 ret = handler(dev, &info, &wrqu_point, extra); 1685 1686 /* Cleanup - I told you it wasn't that long ;-) */ 1687 kfree(extra); 1688 } 1689 1690 /* Call commit handler if needed and defined */ 1691 if(ret == -EIWCOMMIT) 1692 ret = call_commit_handler(dev); 1693 1694 return ret; 1695} 1696 1697/* ---------------------------------------------------------------- */ 1698/* 1699 * Main RtNetlink dispatcher. Called from the main networking code 1700 * (do_getlink() in net/core/rtnetlink.c). 1701 * Check the type of Request and call the appropriate wrapper... 1702 */ 1703int wireless_rtnetlink_get(struct net_device * dev, 1704 char * data, 1705 int len, 1706 char ** p_buf, 1707 int * p_len) 1708{ 1709 struct iw_event * request = (struct iw_event *) data; 1710 iw_handler handler; 1711 1712 /* Check length */ 1713 if(len < IW_EV_LCP_LEN) { 1714 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", 1715 dev->name, len); 1716 return -EINVAL; 1717 } 1718 1719 /* ReCheck length (len may have padding) */ 1720 if(request->len > len) { 1721 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n", 1722 dev->name, request->len, len); 1723 return -EINVAL; 1724 } 1725 1726 /* Only accept GET requests in here */ 1727 if(!IW_IS_GET(request->cmd)) 1728 return -EOPNOTSUPP; 1729 1730 /* If command is `get the encoding parameters', check if 1731 * the user has the right to do it */ 1732 if (request->cmd == SIOCGIWENCODE || 1733 request->cmd == SIOCGIWENCODEEXT) { 1734 if (!capable(CAP_NET_ADMIN)) 1735 return -EPERM; 1736 } 1737 1738 /* Special cases */ 1739 if(request->cmd == SIOCGIWSTATS) 1740 /* Get Wireless Stats */ 1741 return rtnetlink_standard_get(dev, 1742 request, 1743 request->len, 1744 &iw_handler_get_iwstats, 1745 p_buf, p_len); 1746 if(request->cmd == SIOCGIWPRIV) { 1747 /* Check if we have some wireless handlers defined */ 1748 if(dev->wireless_handlers == NULL) 1749 return -EOPNOTSUPP; 1750 /* Get Wireless Stats */ 1751 return rtnetlink_standard_get(dev, 1752 request, 1753 request->len, 1754 &iw_handler_get_private, 1755 p_buf, p_len); 1756 } 1757 1758 /* Basic check */ 1759 if (!netif_device_present(dev)) 1760 return -ENODEV; 1761 1762 /* Try to find the handler */ 1763 handler = get_handler(dev, request->cmd); 1764 if(handler != NULL) { 1765 /* Standard and private are not the same */ 1766 if(request->cmd < SIOCIWFIRSTPRIV) 1767 return rtnetlink_standard_get(dev, 1768 request, 1769 request->len, 1770 handler, 1771 p_buf, p_len); 1772 else 1773 return rtnetlink_private_get(dev, 1774 request, 1775 request->len, 1776 handler, 1777 p_buf, p_len); 1778 } 1779 1780 return -EOPNOTSUPP; 1781} 1782 1783/* ---------------------------------------------------------------- */ 1784/* 1785 * Main RtNetlink dispatcher. Called from the main networking code 1786 * (do_setlink() in net/core/rtnetlink.c). 1787 * Check the type of Request and call the appropriate wrapper... 1788 */ 1789int wireless_rtnetlink_set(struct net_device * dev, 1790 char * data, 1791 int len) 1792{ 1793 struct iw_event * request = (struct iw_event *) data; 1794 iw_handler handler; 1795 1796 /* Check length */ 1797 if(len < IW_EV_LCP_LEN) { 1798 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request too short (%d)\n", 1799 dev->name, len); 1800 return -EINVAL; 1801 } 1802 1803 /* ReCheck length (len may have padding) */ 1804 if(request->len > len) { 1805 printk(KERN_DEBUG "%s (WE.r) : RtNetlink request len invalid (%d-%d)\n", 1806 dev->name, request->len, len); 1807 return -EINVAL; 1808 } 1809 1810 /* Only accept SET requests in here */ 1811 if(!IW_IS_SET(request->cmd)) 1812 return -EOPNOTSUPP; 1813 1814 /* Basic check */ 1815 if (!netif_device_present(dev)) 1816 return -ENODEV; 1817 1818 /* New driver API : try to find the handler */ 1819 handler = get_handler(dev, request->cmd); 1820 if(handler != NULL) { 1821 /* Standard and private are not the same */ 1822 if(request->cmd < SIOCIWFIRSTPRIV) 1823 return rtnetlink_standard_set(dev, 1824 request, 1825 request->len, 1826 handler); 1827 else 1828 return rtnetlink_private_set(dev, 1829 request, 1830 request->len, 1831 handler); 1832 } 1833 1834 return -EOPNOTSUPP; 1835} 1836#endif /* CONFIG_NET_WIRELESS_RTNETLINK */ 1837 1838 1839/************************* EVENT PROCESSING *************************/ 1840/* 1841 * Process events generated by the wireless layer or the driver. 1842 * Most often, the event will be propagated through rtnetlink 1843 */ 1844 1845#ifdef WE_EVENT_RTNETLINK 1846static struct sk_buff_head wireless_nlevent_queue; 1847 1848static void wireless_nlevent_process(unsigned long data) 1849{ 1850 struct sk_buff *skb; 1851 1852 while ((skb = skb_dequeue(&wireless_nlevent_queue))) 1853 netlink_broadcast(rtnl, skb, 0, RTNLGRP_LINK, GFP_ATOMIC); 1854} 1855 1856static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); 1857 1858/* ---------------------------------------------------------------- */ 1859/* 1860 * Fill a rtnetlink message with our event data. 1861 * Note that we propage only the specified event and don't dump the 1862 * current wireless config. Dumping the wireless config is far too 1863 * expensive (for each parameter, the driver need to query the hardware). 1864 */ 1865static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb, 1866 struct net_device * dev, 1867 int type, 1868 char * event, 1869 int event_len) 1870{ 1871 struct ifinfomsg *r; 1872 struct nlmsghdr *nlh; 1873 unsigned char *b = skb->tail; 1874 1875 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r)); 1876 r = NLMSG_DATA(nlh); 1877 r->ifi_family = AF_UNSPEC; 1878 r->__ifi_pad = 0; 1879 r->ifi_type = dev->type; 1880 r->ifi_index = dev->ifindex; 1881 r->ifi_flags = dev_get_flags(dev); 1882 r->ifi_change = 0; /* Wireless changes don't affect those flags */ 1883 1884 /* Add the wireless events in the netlink packet */ 1885 RTA_PUT(skb, IFLA_WIRELESS, event_len, event); 1886 1887 nlh->nlmsg_len = skb->tail - b; 1888 return skb->len; 1889 1890nlmsg_failure: 1891rtattr_failure: 1892 skb_trim(skb, b - skb->data); 1893 return -1; 1894} 1895 1896/* ---------------------------------------------------------------- */ 1897/* 1898 * Create and broadcast and send it on the standard rtnetlink socket 1899 * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c 1900 * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field 1901 * within a RTM_NEWLINK event. 1902 */ 1903static inline void rtmsg_iwinfo(struct net_device * dev, 1904 char * event, 1905 int event_len) 1906{ 1907 struct sk_buff *skb; 1908 int size = NLMSG_GOODSIZE; 1909 1910 skb = alloc_skb(size, GFP_ATOMIC); 1911 if (!skb) 1912 return; 1913 1914 if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, 1915 event, event_len) < 0) { 1916 kfree_skb(skb); 1917 return; 1918 } 1919 NETLINK_CB(skb).dst_group = RTNLGRP_LINK; 1920 skb_queue_tail(&wireless_nlevent_queue, skb); 1921 tasklet_schedule(&wireless_nlevent_tasklet); 1922} 1923 1924static int __init wireless_nlevent_init(void) 1925{ 1926 skb_queue_head_init(&wireless_nlevent_queue); 1927 return 0; 1928} 1929 1930subsys_initcall(wireless_nlevent_init); 1931#endif /* WE_EVENT_RTNETLINK */ 1932 1933/* ---------------------------------------------------------------- */ 1934/* 1935 * Main event dispatcher. Called from other parts and drivers. 1936 * Send the event on the appropriate channels. 1937 * May be called from interrupt context. 1938 */ 1939void wireless_send_event(struct net_device * dev, 1940 unsigned int cmd, 1941 union iwreq_data * wrqu, 1942 char * extra) 1943{ 1944 const struct iw_ioctl_description * descr = NULL; 1945 int extra_len = 0; 1946 struct iw_event *event; /* Mallocated whole event */ 1947 int event_len; /* Its size */ 1948 int hdr_len; /* Size of the event header */ 1949 int wrqu_off = 0; /* Offset in wrqu */ 1950 /* Don't "optimise" the following variable, it will crash */ 1951 unsigned cmd_index; /* *MUST* be unsigned */ 1952 1953 /* Get the description of the Event */ 1954 if(cmd <= SIOCIWLAST) { 1955 cmd_index = cmd - SIOCIWFIRST; 1956 if(cmd_index < standard_ioctl_num) 1957 descr = &(standard_ioctl[cmd_index]); 1958 } else { 1959 cmd_index = cmd - IWEVFIRST; 1960 if(cmd_index < standard_event_num) 1961 descr = &(standard_event[cmd_index]); 1962 } 1963 /* Don't accept unknown events */ 1964 if(descr == NULL) { 1965 /* Note : we don't return an error to the driver, because 1966 * the driver would not know what to do about it. It can't 1967 * return an error to the user, because the event is not 1968 * initiated by a user request. 1969 * The best the driver could do is to log an error message. 1970 * We will do it ourselves instead... 1971 */ 1972 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", 1973 dev->name, cmd); 1974 return; 1975 } 1976#ifdef WE_EVENT_DEBUG 1977 printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n", 1978 dev->name, cmd); 1979 printk(KERN_DEBUG "%s (WE) : 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); 1980#endif /* WE_EVENT_DEBUG */ 1981 1982 /* Check extra parameters and set extra_len */ 1983 if(descr->header_type == IW_HEADER_TYPE_POINT) { 1984 /* Check if number of token fits within bounds */ 1985 if(wrqu->data.length > descr->max_tokens) { 1986 printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); 1987 return; 1988 } 1989 if(wrqu->data.length < descr->min_tokens) { 1990 printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); 1991 return; 1992 } 1993 /* Calculate extra_len - extra is NULL for restricted events */ 1994 if(extra != NULL) 1995 extra_len = wrqu->data.length * descr->token_size; 1996 /* Always at an offset in wrqu */ 1997 wrqu_off = IW_EV_POINT_OFF; 1998#ifdef WE_EVENT_DEBUG 1999 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len); 2000#endif /* WE_EVENT_DEBUG */ 2001 } 2002 2003 /* Total length of the event */ 2004 hdr_len = event_type_size[descr->header_type]; 2005 event_len = hdr_len + extra_len; 2006 2007#ifdef WE_EVENT_DEBUG 2008 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, wrqu_off %d, event_len %d\n", dev->name, cmd, hdr_len, wrqu_off, event_len); 2009#endif /* WE_EVENT_DEBUG */ 2010 2011 /* Create temporary buffer to hold the event */ 2012 event = kmalloc(event_len, GFP_ATOMIC); 2013 if(event == NULL) 2014 return; 2015 2016 /* Fill event */ 2017 event->len = event_len; 2018 event->cmd = cmd; 2019 memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); 2020 if(extra != NULL) 2021 memcpy(((char *) event) + hdr_len, extra, extra_len); 2022 2023#ifdef WE_EVENT_RTNETLINK 2024 /* Send via the RtNetlink event channel */ 2025 rtmsg_iwinfo(dev, (char *) event, event_len); 2026#endif /* WE_EVENT_RTNETLINK */ 2027 2028 /* Cleanup */ 2029 kfree(event); 2030 2031 return; /* Always success, I guess ;-) */ 2032} 2033 2034/********************** ENHANCED IWSPY SUPPORT **********************/ 2035/* 2036 * In the old days, the driver was handling spy support all by itself. 2037 * Now, the driver can delegate this task to Wireless Extensions. 2038 * It needs to use those standard spy iw_handler in struct iw_handler_def, 2039 * push data to us via wireless_spy_update() and include struct iw_spy_data 2040 * in its private part (and export it in net_device->wireless_data->spy_data). 2041 * One of the main advantage of centralising spy support here is that 2042 * it becomes much easier to improve and extend it without having to touch 2043 * the drivers. One example is the addition of the Spy-Threshold events. 2044 */ 2045 2046/* ---------------------------------------------------------------- */ 2047/* 2048 * Return the pointer to the spy data in the driver. 2049 * Because this is called on the Rx path via wireless_spy_update(), 2050 * we want it to be efficient... 2051 */ 2052static inline struct iw_spy_data * get_spydata(struct net_device *dev) 2053{ 2054 /* This is the new way */ 2055 if(dev->wireless_data) 2056 return(dev->wireless_data->spy_data); 2057 return NULL; 2058} 2059 2060/*------------------------------------------------------------------*/ 2061/* 2062 * Standard Wireless Handler : set Spy List 2063 */ 2064int iw_handler_set_spy(struct net_device * dev, 2065 struct iw_request_info * info, 2066 union iwreq_data * wrqu, 2067 char * extra) 2068{ 2069 struct iw_spy_data * spydata = get_spydata(dev); 2070 struct sockaddr * address = (struct sockaddr *) extra; 2071 2072 /* Make sure driver is not buggy or using the old API */ 2073 if(!spydata) 2074 return -EOPNOTSUPP; 2075 2076 /* Disable spy collection while we copy the addresses. 2077 * While we copy addresses, any call to wireless_spy_update() 2078 * will NOP. This is OK, as anyway the addresses are changing. */ 2079 spydata->spy_number = 0; 2080 2081 /* We want to operate without locking, because wireless_spy_update() 2082 * most likely will happen in the interrupt handler, and therefore 2083 * have its own locking constraints and needs performance. 2084 * The rtnl_lock() make sure we don't race with the other iw_handlers. 2085 * This make sure wireless_spy_update() "see" that the spy list 2086 * is temporarily disabled. */ 2087 wmb(); 2088 2089 /* Are there are addresses to copy? */ 2090 if(wrqu->data.length > 0) { 2091 int i; 2092 2093 /* Copy addresses */ 2094 for(i = 0; i < wrqu->data.length; i++) 2095 memcpy(spydata->spy_address[i], address[i].sa_data, 2096 ETH_ALEN); 2097 /* Reset stats */ 2098 memset(spydata->spy_stat, 0, 2099 sizeof(struct iw_quality) * IW_MAX_SPY); 2100 2101#ifdef WE_SPY_DEBUG 2102 printk(KERN_DEBUG "iw_handler_set_spy() : wireless_data %p, spydata %p, num %d\n", dev->wireless_data, spydata, wrqu->data.length); 2103 for (i = 0; i < wrqu->data.length; i++) 2104 printk(KERN_DEBUG 2105 "%02X:%02X:%02X:%02X:%02X:%02X \n", 2106 spydata->spy_address[i][0], 2107 spydata->spy_address[i][1], 2108 spydata->spy_address[i][2], 2109 spydata->spy_address[i][3], 2110 spydata->spy_address[i][4], 2111 spydata->spy_address[i][5]); 2112#endif /* WE_SPY_DEBUG */ 2113 } 2114 2115 /* Make sure above is updated before re-enabling */ 2116 wmb(); 2117 2118 /* Enable addresses */ 2119 spydata->spy_number = wrqu->data.length; 2120 2121 return 0; 2122} 2123 2124/*------------------------------------------------------------------*/ 2125/* 2126 * Standard Wireless Handler : get Spy List 2127 */ 2128int iw_handler_get_spy(struct net_device * dev, 2129 struct iw_request_info * info, 2130 union iwreq_data * wrqu, 2131 char * extra) 2132{ 2133 struct iw_spy_data * spydata = get_spydata(dev); 2134 struct sockaddr * address = (struct sockaddr *) extra; 2135 int i; 2136 2137 /* Make sure driver is not buggy or using the old API */ 2138 if(!spydata) 2139 return -EOPNOTSUPP; 2140 2141 wrqu->data.length = spydata->spy_number; 2142 2143 /* Copy addresses. */ 2144 for(i = 0; i < spydata->spy_number; i++) { 2145 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); 2146 address[i].sa_family = AF_UNIX; 2147 } 2148 /* Copy stats to the user buffer (just after). */ 2149 if(spydata->spy_number > 0) 2150 memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), 2151 spydata->spy_stat, 2152 sizeof(struct iw_quality) * spydata->spy_number); 2153 /* Reset updated flags. */ 2154 for(i = 0; i < spydata->spy_number; i++) 2155 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; 2156 return 0; 2157} 2158 2159/*------------------------------------------------------------------*/ 2160/* 2161 * Standard Wireless Handler : set spy threshold 2162 */ 2163int iw_handler_set_thrspy(struct net_device * dev, 2164 struct iw_request_info *info, 2165 union iwreq_data * wrqu, 2166 char * extra) 2167{ 2168 struct iw_spy_data * spydata = get_spydata(dev); 2169 struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 2170 2171 /* Make sure driver is not buggy or using the old API */ 2172 if(!spydata) 2173 return -EOPNOTSUPP; 2174 2175 /* Just do it */ 2176 memcpy(&(spydata->spy_thr_low), &(threshold->low), 2177 2 * sizeof(struct iw_quality)); 2178 2179 /* Clear flag */ 2180 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); 2181 2182#ifdef WE_SPY_DEBUG 2183 printk(KERN_DEBUG "iw_handler_set_thrspy() : low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level); 2184#endif /* WE_SPY_DEBUG */ 2185 2186 return 0; 2187} 2188 2189/*------------------------------------------------------------------*/ 2190/* 2191 * Standard Wireless Handler : get spy threshold 2192 */ 2193int iw_handler_get_thrspy(struct net_device * dev, 2194 struct iw_request_info *info, 2195 union iwreq_data * wrqu, 2196 char * extra) 2197{ 2198 struct iw_spy_data * spydata = get_spydata(dev); 2199 struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 2200 2201 /* Make sure driver is not buggy or using the old API */ 2202 if(!spydata) 2203 return -EOPNOTSUPP; 2204 2205 /* Just do it */ 2206 memcpy(&(threshold->low), &(spydata->spy_thr_low), 2207 2 * sizeof(struct iw_quality)); 2208 2209 return 0; 2210} 2211 2212/*------------------------------------------------------------------*/ 2213/* 2214 * Prepare and send a Spy Threshold event 2215 */ 2216static void iw_send_thrspy_event(struct net_device * dev, 2217 struct iw_spy_data * spydata, 2218 unsigned char * address, 2219 struct iw_quality * wstats) 2220{ 2221 union iwreq_data wrqu; 2222 struct iw_thrspy threshold; 2223 2224 /* Init */ 2225 wrqu.data.length = 1; 2226 wrqu.data.flags = 0; 2227 /* Copy address */ 2228 memcpy(threshold.addr.sa_data, address, ETH_ALEN); 2229 threshold.addr.sa_family = ARPHRD_ETHER; 2230 /* Copy stats */ 2231 memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); 2232 /* Copy also thresholds */ 2233 memcpy(&(threshold.low), &(spydata->spy_thr_low), 2234 2 * sizeof(struct iw_quality)); 2235 2236#ifdef WE_SPY_DEBUG 2237 printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n", 2238 threshold.addr.sa_data[0], 2239 threshold.addr.sa_data[1], 2240 threshold.addr.sa_data[2], 2241 threshold.addr.sa_data[3], 2242 threshold.addr.sa_data[4], 2243 threshold.addr.sa_data[5], threshold.qual.level); 2244#endif /* WE_SPY_DEBUG */ 2245 2246 /* Send event to user space */ 2247 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); 2248} 2249 2250/* ---------------------------------------------------------------- */ 2251/* 2252 * Call for the driver to update the spy data. 2253 * For now, the spy data is a simple array. As the size of the array is 2254 * small, this is good enough. If we wanted to support larger number of 2255 * spy addresses, we should use something more efficient... 2256 */ 2257void wireless_spy_update(struct net_device * dev, 2258 unsigned char * address, 2259 struct iw_quality * wstats) 2260{ 2261 struct iw_spy_data * spydata = get_spydata(dev); 2262 int i; 2263 int match = -1; 2264 2265 /* Make sure driver is not buggy or using the old API */ 2266 if(!spydata) 2267 return; 2268 2269#ifdef WE_SPY_DEBUG 2270 printk(KERN_DEBUG "wireless_spy_update() : wireless_data %p, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_data, spydata, address[0], address[1], address[2], address[3], address[4], address[5]); 2271#endif /* WE_SPY_DEBUG */ 2272 2273 /* Update all records that match */ 2274 for(i = 0; i < spydata->spy_number; i++) 2275 if(!compare_ether_addr(address, spydata->spy_address[i])) { 2276 memcpy(&(spydata->spy_stat[i]), wstats, 2277 sizeof(struct iw_quality)); 2278 match = i; 2279 } 2280 2281 /* Generate an event if we cross the spy threshold. 2282 * To avoid event storms, we have a simple hysteresis : we generate 2283 * event only when we go under the low threshold or above the 2284 * high threshold. */ 2285 if(match >= 0) { 2286 if(spydata->spy_thr_under[match]) { 2287 if(wstats->level > spydata->spy_thr_high.level) { 2288 spydata->spy_thr_under[match] = 0; 2289 iw_send_thrspy_event(dev, spydata, 2290 address, wstats); 2291 } 2292 } else { 2293 if(wstats->level < spydata->spy_thr_low.level) { 2294 spydata->spy_thr_under[match] = 1; 2295 iw_send_thrspy_event(dev, spydata, 2296 address, wstats); 2297 } 2298 } 2299 } 2300} 2301 2302EXPORT_SYMBOL(iw_handler_get_spy); 2303EXPORT_SYMBOL(iw_handler_get_thrspy); 2304EXPORT_SYMBOL(iw_handler_set_spy); 2305EXPORT_SYMBOL(iw_handler_set_thrspy); 2306EXPORT_SYMBOL(wireless_send_event); 2307EXPORT_SYMBOL(wireless_spy_update);