Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.26-rc5 1507 lines 45 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-2007 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 * v8b - 03.08.06 - Herbert Xu 73 * o Fix Wireless Event locking issues. 74 * 75 * v9 - 14.3.06 - Jean II 76 * o Change length in ESSID and NICK to strlen() instead of strlen()+1 77 * o Make standard_ioctl_num and standard_event_num unsigned 78 * o Remove (struct net_device *)->get_wireless_stats() 79 * 80 * v10 - 16.3.07 - Jean II 81 * o Prevent leaking of kernel space in stream on 64 bits. 82 */ 83 84/***************************** INCLUDES *****************************/ 85 86#include <linux/module.h> 87#include <linux/types.h> /* off_t */ 88#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ 89#include <linux/proc_fs.h> 90#include <linux/rtnetlink.h> /* rtnetlink stuff */ 91#include <linux/seq_file.h> 92#include <linux/init.h> /* for __init */ 93#include <linux/if_arp.h> /* ARPHRD_ETHER */ 94#include <linux/etherdevice.h> /* compare_ether_addr */ 95#include <linux/interrupt.h> 96#include <net/net_namespace.h> 97 98#include <linux/wireless.h> /* Pretty obvious */ 99#include <net/iw_handler.h> /* New driver API */ 100#include <net/netlink.h> 101#include <net/wext.h> 102 103#include <asm/uaccess.h> /* copy_to_user() */ 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, 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, 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, 250 }, 251 [SIOCGIWNICKN - SIOCIWFIRST] = { 252 .header_type = IW_HEADER_TYPE_POINT, 253 .token_size = 1, 254 .max_tokens = IW_ESSID_MAX_SIZE, 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 unsigned standard_ioctl_num = ARRAY_SIZE(standard_ioctl); 342 343/* 344 * Meta-data about all the additional standard Wireless Extension events 345 * we know about. 346 */ 347static const struct iw_ioctl_description standard_event[] = { 348 [IWEVTXDROP - IWEVFIRST] = { 349 .header_type = IW_HEADER_TYPE_ADDR, 350 }, 351 [IWEVQUAL - IWEVFIRST] = { 352 .header_type = IW_HEADER_TYPE_QUAL, 353 }, 354 [IWEVCUSTOM - IWEVFIRST] = { 355 .header_type = IW_HEADER_TYPE_POINT, 356 .token_size = 1, 357 .max_tokens = IW_CUSTOM_MAX, 358 }, 359 [IWEVREGISTERED - IWEVFIRST] = { 360 .header_type = IW_HEADER_TYPE_ADDR, 361 }, 362 [IWEVEXPIRED - IWEVFIRST] = { 363 .header_type = IW_HEADER_TYPE_ADDR, 364 }, 365 [IWEVGENIE - IWEVFIRST] = { 366 .header_type = IW_HEADER_TYPE_POINT, 367 .token_size = 1, 368 .max_tokens = IW_GENERIC_IE_MAX, 369 }, 370 [IWEVMICHAELMICFAILURE - IWEVFIRST] = { 371 .header_type = IW_HEADER_TYPE_POINT, 372 .token_size = 1, 373 .max_tokens = sizeof(struct iw_michaelmicfailure), 374 }, 375 [IWEVASSOCREQIE - IWEVFIRST] = { 376 .header_type = IW_HEADER_TYPE_POINT, 377 .token_size = 1, 378 .max_tokens = IW_GENERIC_IE_MAX, 379 }, 380 [IWEVASSOCRESPIE - IWEVFIRST] = { 381 .header_type = IW_HEADER_TYPE_POINT, 382 .token_size = 1, 383 .max_tokens = IW_GENERIC_IE_MAX, 384 }, 385 [IWEVPMKIDCAND - IWEVFIRST] = { 386 .header_type = IW_HEADER_TYPE_POINT, 387 .token_size = 1, 388 .max_tokens = sizeof(struct iw_pmkid_cand), 389 }, 390}; 391static const unsigned standard_event_num = ARRAY_SIZE(standard_event); 392 393/* Size (in bytes) of the various private data types */ 394static const char iw_priv_type_size[] = { 395 0, /* IW_PRIV_TYPE_NONE */ 396 1, /* IW_PRIV_TYPE_BYTE */ 397 1, /* IW_PRIV_TYPE_CHAR */ 398 0, /* Not defined */ 399 sizeof(__u32), /* IW_PRIV_TYPE_INT */ 400 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ 401 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ 402 0, /* Not defined */ 403}; 404 405/* Size (in bytes) of various events */ 406static const int event_type_size[] = { 407 IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ 408 0, 409 IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ 410 0, 411 IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ 412 IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ 413 IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ 414 0, 415 IW_EV_POINT_LEN, /* Without variable payload */ 416 IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ 417 IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ 418}; 419 420 421/************************ COMMON SUBROUTINES ************************/ 422/* 423 * Stuff that may be used in various place or doesn't fit in one 424 * of the section below. 425 */ 426 427/* ---------------------------------------------------------------- */ 428/* 429 * Return the driver handler associated with a specific Wireless Extension. 430 */ 431static iw_handler get_handler(struct net_device *dev, unsigned int cmd) 432{ 433 /* Don't "optimise" the following variable, it will crash */ 434 unsigned int index; /* *MUST* be unsigned */ 435 436 /* Check if we have some wireless handlers defined */ 437 if (dev->wireless_handlers == NULL) 438 return NULL; 439 440 /* Try as a standard command */ 441 index = cmd - SIOCIWFIRST; 442 if (index < dev->wireless_handlers->num_standard) 443 return dev->wireless_handlers->standard[index]; 444 445 /* Try as a private command */ 446 index = cmd - SIOCIWFIRSTPRIV; 447 if (index < dev->wireless_handlers->num_private) 448 return dev->wireless_handlers->private[index]; 449 450 /* Not found */ 451 return NULL; 452} 453 454/* ---------------------------------------------------------------- */ 455/* 456 * Get statistics out of the driver 457 */ 458static struct iw_statistics *get_wireless_stats(struct net_device *dev) 459{ 460 /* New location */ 461 if ((dev->wireless_handlers != NULL) && 462 (dev->wireless_handlers->get_wireless_stats != NULL)) 463 return dev->wireless_handlers->get_wireless_stats(dev); 464 465 /* Not found */ 466 return NULL; 467} 468 469/* ---------------------------------------------------------------- */ 470/* 471 * Call the commit handler in the driver 472 * (if exist and if conditions are right) 473 * 474 * Note : our current commit strategy is currently pretty dumb, 475 * but we will be able to improve on that... 476 * The goal is to try to agreagate as many changes as possible 477 * before doing the commit. Drivers that will define a commit handler 478 * are usually those that need a reset after changing parameters, so 479 * we want to minimise the number of reset. 480 * A cool idea is to use a timer : at each "set" command, we re-set the 481 * timer, when the timer eventually fires, we call the driver. 482 * Hopefully, more on that later. 483 * 484 * Also, I'm waiting to see how many people will complain about the 485 * netif_running(dev) test. I'm open on that one... 486 * Hopefully, the driver will remember to do a commit in "open()" ;-) 487 */ 488static int call_commit_handler(struct net_device *dev) 489{ 490 if ((netif_running(dev)) && 491 (dev->wireless_handlers->standard[0] != NULL)) 492 /* Call the commit handler on the driver */ 493 return dev->wireless_handlers->standard[0](dev, NULL, 494 NULL, NULL); 495 else 496 return 0; /* Command completed successfully */ 497} 498 499/* ---------------------------------------------------------------- */ 500/* 501 * Calculate size of private arguments 502 */ 503static inline int get_priv_size(__u16 args) 504{ 505 int num = args & IW_PRIV_SIZE_MASK; 506 int type = (args & IW_PRIV_TYPE_MASK) >> 12; 507 508 return num * iw_priv_type_size[type]; 509} 510 511/* ---------------------------------------------------------------- */ 512/* 513 * Re-calculate the size of private arguments 514 */ 515static inline int adjust_priv_size(__u16 args, 516 union iwreq_data * wrqu) 517{ 518 int num = wrqu->data.length; 519 int max = args & IW_PRIV_SIZE_MASK; 520 int type = (args & IW_PRIV_TYPE_MASK) >> 12; 521 522 /* Make sure the driver doesn't goof up */ 523 if (max < num) 524 num = max; 525 526 return num * iw_priv_type_size[type]; 527} 528 529/* ---------------------------------------------------------------- */ 530/* 531 * Standard Wireless Handler : get wireless stats 532 * Allow programatic access to /proc/net/wireless even if /proc 533 * doesn't exist... Also more efficient... 534 */ 535static int iw_handler_get_iwstats(struct net_device * dev, 536 struct iw_request_info * info, 537 union iwreq_data * wrqu, 538 char * extra) 539{ 540 /* Get stats from the driver */ 541 struct iw_statistics *stats; 542 543 stats = get_wireless_stats(dev); 544 if (stats) { 545 /* Copy statistics to extra */ 546 memcpy(extra, stats, sizeof(struct iw_statistics)); 547 wrqu->data.length = sizeof(struct iw_statistics); 548 549 /* Check if we need to clear the updated flag */ 550 if (wrqu->data.flags != 0) 551 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 552 return 0; 553 } else 554 return -EOPNOTSUPP; 555} 556 557/* ---------------------------------------------------------------- */ 558/* 559 * Standard Wireless Handler : get iwpriv definitions 560 * Export the driver private handler definition 561 * They will be picked up by tools like iwpriv... 562 */ 563static int iw_handler_get_private(struct net_device * dev, 564 struct iw_request_info * info, 565 union iwreq_data * wrqu, 566 char * extra) 567{ 568 /* Check if the driver has something to export */ 569 if ((dev->wireless_handlers->num_private_args == 0) || 570 (dev->wireless_handlers->private_args == NULL)) 571 return -EOPNOTSUPP; 572 573 /* Check if there is enough buffer up there */ 574 if (wrqu->data.length < dev->wireless_handlers->num_private_args) { 575 /* User space can't know in advance how large the buffer 576 * needs to be. Give it a hint, so that we can support 577 * any size buffer we want somewhat efficiently... */ 578 wrqu->data.length = dev->wireless_handlers->num_private_args; 579 return -E2BIG; 580 } 581 582 /* Set the number of available ioctls. */ 583 wrqu->data.length = dev->wireless_handlers->num_private_args; 584 585 /* Copy structure to the user buffer. */ 586 memcpy(extra, dev->wireless_handlers->private_args, 587 sizeof(struct iw_priv_args) * wrqu->data.length); 588 589 return 0; 590} 591 592 593/******************** /proc/net/wireless SUPPORT ********************/ 594/* 595 * The /proc/net/wireless file is a human readable user-space interface 596 * exporting various wireless specific statistics from the wireless devices. 597 * This is the most popular part of the Wireless Extensions ;-) 598 * 599 * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). 600 * The content of the file is basically the content of "struct iw_statistics". 601 */ 602 603#ifdef CONFIG_PROC_FS 604 605/* ---------------------------------------------------------------- */ 606/* 607 * Print one entry (line) of /proc/net/wireless 608 */ 609static void wireless_seq_printf_stats(struct seq_file *seq, 610 struct net_device *dev) 611{ 612 /* Get stats from the driver */ 613 struct iw_statistics *stats = get_wireless_stats(dev); 614 615 if (stats) { 616 seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " 617 "%6d %6d %6d\n", 618 dev->name, stats->status, stats->qual.qual, 619 stats->qual.updated & IW_QUAL_QUAL_UPDATED 620 ? '.' : ' ', 621 ((__s32) stats->qual.level) - 622 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), 623 stats->qual.updated & IW_QUAL_LEVEL_UPDATED 624 ? '.' : ' ', 625 ((__s32) stats->qual.noise) - 626 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), 627 stats->qual.updated & IW_QUAL_NOISE_UPDATED 628 ? '.' : ' ', 629 stats->discard.nwid, stats->discard.code, 630 stats->discard.fragment, stats->discard.retries, 631 stats->discard.misc, stats->miss.beacon); 632 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 633 } 634} 635 636/* ---------------------------------------------------------------- */ 637/* 638 * Print info for /proc/net/wireless (print all entries) 639 */ 640static int wireless_seq_show(struct seq_file *seq, void *v) 641{ 642 if (v == SEQ_START_TOKEN) 643 seq_printf(seq, "Inter-| sta-| Quality | Discarded " 644 "packets | Missed | WE\n" 645 " face | tus | link level noise | nwid " 646 "crypt frag retry misc | beacon | %d\n", 647 WIRELESS_EXT); 648 else 649 wireless_seq_printf_stats(seq, v); 650 return 0; 651} 652 653static const struct seq_operations wireless_seq_ops = { 654 .start = dev_seq_start, 655 .next = dev_seq_next, 656 .stop = dev_seq_stop, 657 .show = wireless_seq_show, 658}; 659 660static int wireless_seq_open(struct inode *inode, struct file *file) 661{ 662 return seq_open_net(inode, file, &wireless_seq_ops, 663 sizeof(struct seq_net_private)); 664} 665 666static const struct file_operations wireless_seq_fops = { 667 .owner = THIS_MODULE, 668 .open = wireless_seq_open, 669 .read = seq_read, 670 .llseek = seq_lseek, 671 .release = seq_release_net, 672}; 673 674int wext_proc_init(struct net *net) 675{ 676 /* Create /proc/net/wireless entry */ 677 if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops)) 678 return -ENOMEM; 679 680 return 0; 681} 682 683void wext_proc_exit(struct net *net) 684{ 685 proc_net_remove(net, "wireless"); 686} 687#endif /* CONFIG_PROC_FS */ 688 689/************************** IOCTL SUPPORT **************************/ 690/* 691 * The original user space API to configure all those Wireless Extensions 692 * is through IOCTLs. 693 * In there, we check if we need to call the new driver API (iw_handler) 694 * or just call the driver ioctl handler. 695 */ 696 697/* ---------------------------------------------------------------- */ 698/* 699 * Wrapper to call a standard Wireless Extension handler. 700 * We do various checks and also take care of moving data between 701 * user space and kernel space. 702 */ 703static int ioctl_standard_call(struct net_device * dev, 704 struct ifreq * ifr, 705 unsigned int cmd, 706 iw_handler handler) 707{ 708 struct iwreq * iwr = (struct iwreq *) ifr; 709 const struct iw_ioctl_description * descr; 710 struct iw_request_info info; 711 int ret = -EINVAL; 712 713 /* Get the description of the IOCTL */ 714 if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) 715 return -EOPNOTSUPP; 716 descr = &(standard_ioctl[cmd - SIOCIWFIRST]); 717 718 /* Prepare the call */ 719 info.cmd = cmd; 720 info.flags = 0; 721 722 /* Check if we have a pointer to user space data or not */ 723 if (descr->header_type != IW_HEADER_TYPE_POINT) { 724 725 /* No extra arguments. Trivial to handle */ 726 ret = handler(dev, &info, &(iwr->u), NULL); 727 728 /* Generate an event to notify listeners of the change */ 729 if ((descr->flags & IW_DESCR_FLAG_EVENT) && 730 ((ret == 0) || (ret == -EIWCOMMIT))) 731 wireless_send_event(dev, cmd, &(iwr->u), NULL); 732 } else { 733 char * extra; 734 int extra_size; 735 int user_length = 0; 736 int err; 737 int essid_compat = 0; 738 739 /* Calculate space needed by arguments. Always allocate 740 * for max space. Easier, and won't last long... */ 741 extra_size = descr->max_tokens * descr->token_size; 742 743 /* Check need for ESSID compatibility for WE < 21 */ 744 switch (cmd) { 745 case SIOCSIWESSID: 746 case SIOCGIWESSID: 747 case SIOCSIWNICKN: 748 case SIOCGIWNICKN: 749 if (iwr->u.data.length == descr->max_tokens + 1) 750 essid_compat = 1; 751 else if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { 752 char essid[IW_ESSID_MAX_SIZE + 1]; 753 754 err = copy_from_user(essid, iwr->u.data.pointer, 755 iwr->u.data.length * 756 descr->token_size); 757 if (err) 758 return -EFAULT; 759 760 if (essid[iwr->u.data.length - 1] == '\0') 761 essid_compat = 1; 762 } 763 break; 764 default: 765 break; 766 } 767 768 iwr->u.data.length -= essid_compat; 769 770 /* Check what user space is giving us */ 771 if (IW_IS_SET(cmd)) { 772 /* Check NULL pointer */ 773 if ((iwr->u.data.pointer == NULL) && 774 (iwr->u.data.length != 0)) 775 return -EFAULT; 776 /* Check if number of token fits within bounds */ 777 if (iwr->u.data.length > descr->max_tokens) 778 return -E2BIG; 779 if (iwr->u.data.length < descr->min_tokens) 780 return -EINVAL; 781 } else { 782 /* Check NULL pointer */ 783 if (iwr->u.data.pointer == NULL) 784 return -EFAULT; 785 /* Save user space buffer size for checking */ 786 user_length = iwr->u.data.length; 787 788 /* Don't check if user_length > max to allow forward 789 * compatibility. The test user_length < min is 790 * implied by the test at the end. */ 791 792 /* Support for very large requests */ 793 if ((descr->flags & IW_DESCR_FLAG_NOMAX) && 794 (user_length > descr->max_tokens)) { 795 /* Allow userspace to GET more than max so 796 * we can support any size GET requests. 797 * There is still a limit : -ENOMEM. */ 798 extra_size = user_length * descr->token_size; 799 /* Note : user_length is originally a __u16, 800 * and token_size is controlled by us, 801 * so extra_size won't get negative and 802 * won't overflow... */ 803 } 804 } 805 806 /* Create the kernel buffer */ 807 /* kzalloc ensures NULL-termination for essid_compat */ 808 extra = kzalloc(extra_size, GFP_KERNEL); 809 if (extra == NULL) 810 return -ENOMEM; 811 812 /* If it is a SET, get all the extra data in here */ 813 if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { 814 err = copy_from_user(extra, iwr->u.data.pointer, 815 iwr->u.data.length * 816 descr->token_size); 817 if (err) { 818 kfree(extra); 819 return -EFAULT; 820 } 821 } 822 823 /* Call the handler */ 824 ret = handler(dev, &info, &(iwr->u), extra); 825 826 iwr->u.data.length += essid_compat; 827 828 /* If we have something to return to the user */ 829 if (!ret && IW_IS_GET(cmd)) { 830 /* Check if there is enough buffer up there */ 831 if (user_length < iwr->u.data.length) { 832 kfree(extra); 833 return -E2BIG; 834 } 835 836 err = copy_to_user(iwr->u.data.pointer, extra, 837 iwr->u.data.length * 838 descr->token_size); 839 if (err) 840 ret = -EFAULT; 841 } 842 843 /* Generate an event to notify listeners of the change */ 844 if ((descr->flags & IW_DESCR_FLAG_EVENT) && 845 ((ret == 0) || (ret == -EIWCOMMIT))) { 846 if (descr->flags & IW_DESCR_FLAG_RESTRICT) 847 /* If the event is restricted, don't 848 * export the payload */ 849 wireless_send_event(dev, cmd, &(iwr->u), NULL); 850 else 851 wireless_send_event(dev, cmd, &(iwr->u), 852 extra); 853 } 854 855 /* Cleanup - I told you it wasn't that long ;-) */ 856 kfree(extra); 857 } 858 859 /* Call commit handler if needed and defined */ 860 if (ret == -EIWCOMMIT) 861 ret = call_commit_handler(dev); 862 863 /* Here, we will generate the appropriate event if needed */ 864 865 return ret; 866} 867 868/* ---------------------------------------------------------------- */ 869/* 870 * Wrapper to call a private Wireless Extension handler. 871 * We do various checks and also take care of moving data between 872 * user space and kernel space. 873 * It's not as nice and slimline as the standard wrapper. The cause 874 * is struct iw_priv_args, which was not really designed for the 875 * job we are going here. 876 * 877 * IMPORTANT : This function prevent to set and get data on the same 878 * IOCTL and enforce the SET/GET convention. Not doing it would be 879 * far too hairy... 880 * If you need to set and get data at the same time, please don't use 881 * a iw_handler but process it in your ioctl handler (i.e. use the 882 * old driver API). 883 */ 884static int ioctl_private_call(struct net_device *dev, struct ifreq *ifr, 885 unsigned int cmd, iw_handler handler) 886{ 887 struct iwreq * iwr = (struct iwreq *) ifr; 888 const struct iw_priv_args * descr = NULL; 889 struct iw_request_info info; 890 int extra_size = 0; 891 int i; 892 int ret = -EINVAL; 893 894 /* Get the description of the IOCTL */ 895 for (i = 0; i < dev->wireless_handlers->num_private_args; i++) 896 if (cmd == dev->wireless_handlers->private_args[i].cmd) { 897 descr = &(dev->wireless_handlers->private_args[i]); 898 break; 899 } 900 901 /* Compute the size of the set/get arguments */ 902 if (descr != NULL) { 903 if (IW_IS_SET(cmd)) { 904 int offset = 0; /* For sub-ioctls */ 905 /* Check for sub-ioctl handler */ 906 if (descr->name[0] == '\0') 907 /* Reserve one int for sub-ioctl index */ 908 offset = sizeof(__u32); 909 910 /* Size of set arguments */ 911 extra_size = get_priv_size(descr->set_args); 912 913 /* Does it fits in iwr ? */ 914 if ((descr->set_args & IW_PRIV_SIZE_FIXED) && 915 ((extra_size + offset) <= IFNAMSIZ)) 916 extra_size = 0; 917 } else { 918 /* Size of get arguments */ 919 extra_size = get_priv_size(descr->get_args); 920 921 /* Does it fits in iwr ? */ 922 if ((descr->get_args & IW_PRIV_SIZE_FIXED) && 923 (extra_size <= IFNAMSIZ)) 924 extra_size = 0; 925 } 926 } 927 928 /* Prepare the call */ 929 info.cmd = cmd; 930 info.flags = 0; 931 932 /* Check if we have a pointer to user space data or not. */ 933 if (extra_size == 0) { 934 /* No extra arguments. Trivial to handle */ 935 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); 936 } else { 937 char * extra; 938 int err; 939 940 /* Check what user space is giving us */ 941 if (IW_IS_SET(cmd)) { 942 /* Check NULL pointer */ 943 if ((iwr->u.data.pointer == NULL) && 944 (iwr->u.data.length != 0)) 945 return -EFAULT; 946 947 /* Does it fits within bounds ? */ 948 if (iwr->u.data.length > (descr->set_args & 949 IW_PRIV_SIZE_MASK)) 950 return -E2BIG; 951 } else if (iwr->u.data.pointer == NULL) 952 return -EFAULT; 953 954 /* Always allocate for max space. Easier, and won't last 955 * long... */ 956 extra = kmalloc(extra_size, GFP_KERNEL); 957 if (extra == NULL) 958 return -ENOMEM; 959 960 /* If it is a SET, get all the extra data in here */ 961 if (IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { 962 err = copy_from_user(extra, iwr->u.data.pointer, 963 extra_size); 964 if (err) { 965 kfree(extra); 966 return -EFAULT; 967 } 968 } 969 970 /* Call the handler */ 971 ret = handler(dev, &info, &(iwr->u), extra); 972 973 /* If we have something to return to the user */ 974 if (!ret && IW_IS_GET(cmd)) { 975 976 /* Adjust for the actual length if it's variable, 977 * avoid leaking kernel bits outside. */ 978 if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) { 979 extra_size = adjust_priv_size(descr->get_args, 980 &(iwr->u)); 981 } 982 983 err = copy_to_user(iwr->u.data.pointer, extra, 984 extra_size); 985 if (err) 986 ret = -EFAULT; 987 } 988 989 /* Cleanup - I told you it wasn't that long ;-) */ 990 kfree(extra); 991 } 992 993 994 /* Call commit handler if needed and defined */ 995 if (ret == -EIWCOMMIT) 996 ret = call_commit_handler(dev); 997 998 return ret; 999} 1000 1001/* ---------------------------------------------------------------- */ 1002/* 1003 * Main IOCTl dispatcher. 1004 * Check the type of IOCTL and call the appropriate wrapper... 1005 */ 1006static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd) 1007{ 1008 struct net_device *dev; 1009 iw_handler handler; 1010 1011 /* Permissions are already checked in dev_ioctl() before calling us. 1012 * The copy_to/from_user() of ifr is also dealt with in there */ 1013 1014 /* Make sure the device exist */ 1015 if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) 1016 return -ENODEV; 1017 1018 /* A bunch of special cases, then the generic case... 1019 * Note that 'cmd' is already filtered in dev_ioctl() with 1020 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ 1021 if (cmd == SIOCGIWSTATS) 1022 return ioctl_standard_call(dev, ifr, cmd, 1023 &iw_handler_get_iwstats); 1024 1025 if (cmd == SIOCGIWPRIV && dev->wireless_handlers) 1026 return ioctl_standard_call(dev, ifr, cmd, 1027 &iw_handler_get_private); 1028 1029 /* Basic check */ 1030 if (!netif_device_present(dev)) 1031 return -ENODEV; 1032 1033 /* New driver API : try to find the handler */ 1034 handler = get_handler(dev, cmd); 1035 if (handler) { 1036 /* Standard and private are not the same */ 1037 if (cmd < SIOCIWFIRSTPRIV) 1038 return ioctl_standard_call(dev, ifr, cmd, handler); 1039 else 1040 return ioctl_private_call(dev, ifr, cmd, handler); 1041 } 1042 /* Old driver API : call driver ioctl handler */ 1043 if (dev->do_ioctl) 1044 return dev->do_ioctl(dev, ifr, cmd); 1045 return -EOPNOTSUPP; 1046} 1047 1048/* entry point from dev ioctl */ 1049int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 1050 void __user *arg) 1051{ 1052 int ret; 1053 1054 /* If command is `set a parameter', or 1055 * `get the encoding parameters', check if 1056 * the user has the right to do it */ 1057 if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) 1058 && !capable(CAP_NET_ADMIN)) 1059 return -EPERM; 1060 1061 dev_load(net, ifr->ifr_name); 1062 rtnl_lock(); 1063 ret = wireless_process_ioctl(net, ifr, cmd); 1064 rtnl_unlock(); 1065 if (IW_IS_GET(cmd) && copy_to_user(arg, ifr, sizeof(struct iwreq))) 1066 return -EFAULT; 1067 return ret; 1068} 1069 1070/************************* EVENT PROCESSING *************************/ 1071/* 1072 * Process events generated by the wireless layer or the driver. 1073 * Most often, the event will be propagated through rtnetlink 1074 */ 1075 1076/* ---------------------------------------------------------------- */ 1077/* 1078 * Locking... 1079 * ---------- 1080 * 1081 * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing 1082 * the locking issue in here and implementing this code ! 1083 * 1084 * The issue : wireless_send_event() is often called in interrupt context, 1085 * while the Netlink layer can never be called in interrupt context. 1086 * The fully formed RtNetlink events are queued, and then a tasklet is run 1087 * to feed those to Netlink. 1088 * The skb_queue is interrupt safe, and its lock is not held while calling 1089 * Netlink, so there is no possibility of dealock. 1090 * Jean II 1091 */ 1092 1093static struct sk_buff_head wireless_nlevent_queue; 1094 1095static int __init wireless_nlevent_init(void) 1096{ 1097 skb_queue_head_init(&wireless_nlevent_queue); 1098 return 0; 1099} 1100 1101subsys_initcall(wireless_nlevent_init); 1102 1103static void wireless_nlevent_process(unsigned long data) 1104{ 1105 struct sk_buff *skb; 1106 1107 while ((skb = skb_dequeue(&wireless_nlevent_queue))) 1108 rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); 1109} 1110 1111static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); 1112 1113/* ---------------------------------------------------------------- */ 1114/* 1115 * Fill a rtnetlink message with our event data. 1116 * Note that we propage only the specified event and don't dump the 1117 * current wireless config. Dumping the wireless config is far too 1118 * expensive (for each parameter, the driver need to query the hardware). 1119 */ 1120static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev, 1121 int type, char *event, int event_len) 1122{ 1123 struct ifinfomsg *r; 1124 struct nlmsghdr *nlh; 1125 1126 nlh = nlmsg_put(skb, 0, 0, type, sizeof(*r), 0); 1127 if (nlh == NULL) 1128 return -EMSGSIZE; 1129 1130 r = nlmsg_data(nlh); 1131 r->ifi_family = AF_UNSPEC; 1132 r->__ifi_pad = 0; 1133 r->ifi_type = dev->type; 1134 r->ifi_index = dev->ifindex; 1135 r->ifi_flags = dev_get_flags(dev); 1136 r->ifi_change = 0; /* Wireless changes don't affect those flags */ 1137 1138 /* Add the wireless events in the netlink packet */ 1139 NLA_PUT(skb, IFLA_WIRELESS, event_len, event); 1140 1141 return nlmsg_end(skb, nlh); 1142 1143nla_put_failure: 1144 nlmsg_cancel(skb, nlh); 1145 return -EMSGSIZE; 1146} 1147 1148/* ---------------------------------------------------------------- */ 1149/* 1150 * Create and broadcast and send it on the standard rtnetlink socket 1151 * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c 1152 * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field 1153 * within a RTM_NEWLINK event. 1154 */ 1155static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) 1156{ 1157 struct sk_buff *skb; 1158 int err; 1159 1160 if (dev_net(dev) != &init_net) 1161 return; 1162 1163 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1164 if (!skb) 1165 return; 1166 1167 err = rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, event, event_len); 1168 if (err < 0) { 1169 WARN_ON(err == -EMSGSIZE); 1170 kfree_skb(skb); 1171 return; 1172 } 1173 1174 NETLINK_CB(skb).dst_group = RTNLGRP_LINK; 1175 skb_queue_tail(&wireless_nlevent_queue, skb); 1176 tasklet_schedule(&wireless_nlevent_tasklet); 1177} 1178 1179/* ---------------------------------------------------------------- */ 1180/* 1181 * Main event dispatcher. Called from other parts and drivers. 1182 * Send the event on the appropriate channels. 1183 * May be called from interrupt context. 1184 */ 1185void wireless_send_event(struct net_device * dev, 1186 unsigned int cmd, 1187 union iwreq_data * wrqu, 1188 char * extra) 1189{ 1190 const struct iw_ioctl_description * descr = NULL; 1191 int extra_len = 0; 1192 struct iw_event *event; /* Mallocated whole event */ 1193 int event_len; /* Its size */ 1194 int hdr_len; /* Size of the event header */ 1195 int wrqu_off = 0; /* Offset in wrqu */ 1196 /* Don't "optimise" the following variable, it will crash */ 1197 unsigned cmd_index; /* *MUST* be unsigned */ 1198 1199 /* Get the description of the Event */ 1200 if (cmd <= SIOCIWLAST) { 1201 cmd_index = cmd - SIOCIWFIRST; 1202 if (cmd_index < standard_ioctl_num) 1203 descr = &(standard_ioctl[cmd_index]); 1204 } else { 1205 cmd_index = cmd - IWEVFIRST; 1206 if (cmd_index < standard_event_num) 1207 descr = &(standard_event[cmd_index]); 1208 } 1209 /* Don't accept unknown events */ 1210 if (descr == NULL) { 1211 /* Note : we don't return an error to the driver, because 1212 * the driver would not know what to do about it. It can't 1213 * return an error to the user, because the event is not 1214 * initiated by a user request. 1215 * The best the driver could do is to log an error message. 1216 * We will do it ourselves instead... 1217 */ 1218 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", 1219 dev->name, cmd); 1220 return; 1221 } 1222 1223 /* Check extra parameters and set extra_len */ 1224 if (descr->header_type == IW_HEADER_TYPE_POINT) { 1225 /* Check if number of token fits within bounds */ 1226 if (wrqu->data.length > descr->max_tokens) { 1227 printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); 1228 return; 1229 } 1230 if (wrqu->data.length < descr->min_tokens) { 1231 printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); 1232 return; 1233 } 1234 /* Calculate extra_len - extra is NULL for restricted events */ 1235 if (extra != NULL) 1236 extra_len = wrqu->data.length * descr->token_size; 1237 /* Always at an offset in wrqu */ 1238 wrqu_off = IW_EV_POINT_OFF; 1239 } 1240 1241 /* Total length of the event */ 1242 hdr_len = event_type_size[descr->header_type]; 1243 event_len = hdr_len + extra_len; 1244 1245 /* Create temporary buffer to hold the event */ 1246 event = kmalloc(event_len, GFP_ATOMIC); 1247 if (event == NULL) 1248 return; 1249 1250 /* Fill event */ 1251 event->len = event_len; 1252 event->cmd = cmd; 1253 memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); 1254 if (extra) 1255 memcpy(((char *) event) + hdr_len, extra, extra_len); 1256 1257 /* Send via the RtNetlink event channel */ 1258 rtmsg_iwinfo(dev, (char *) event, event_len); 1259 1260 /* Cleanup */ 1261 kfree(event); 1262 1263 return; /* Always success, I guess ;-) */ 1264} 1265EXPORT_SYMBOL(wireless_send_event); 1266 1267/********************** ENHANCED IWSPY SUPPORT **********************/ 1268/* 1269 * In the old days, the driver was handling spy support all by itself. 1270 * Now, the driver can delegate this task to Wireless Extensions. 1271 * It needs to use those standard spy iw_handler in struct iw_handler_def, 1272 * push data to us via wireless_spy_update() and include struct iw_spy_data 1273 * in its private part (and export it in net_device->wireless_data->spy_data). 1274 * One of the main advantage of centralising spy support here is that 1275 * it becomes much easier to improve and extend it without having to touch 1276 * the drivers. One example is the addition of the Spy-Threshold events. 1277 */ 1278 1279/* ---------------------------------------------------------------- */ 1280/* 1281 * Return the pointer to the spy data in the driver. 1282 * Because this is called on the Rx path via wireless_spy_update(), 1283 * we want it to be efficient... 1284 */ 1285static inline struct iw_spy_data *get_spydata(struct net_device *dev) 1286{ 1287 /* This is the new way */ 1288 if (dev->wireless_data) 1289 return dev->wireless_data->spy_data; 1290 return NULL; 1291} 1292 1293/*------------------------------------------------------------------*/ 1294/* 1295 * Standard Wireless Handler : set Spy List 1296 */ 1297int iw_handler_set_spy(struct net_device * dev, 1298 struct iw_request_info * info, 1299 union iwreq_data * wrqu, 1300 char * extra) 1301{ 1302 struct iw_spy_data * spydata = get_spydata(dev); 1303 struct sockaddr * address = (struct sockaddr *) extra; 1304 1305 /* Make sure driver is not buggy or using the old API */ 1306 if (!spydata) 1307 return -EOPNOTSUPP; 1308 1309 /* Disable spy collection while we copy the addresses. 1310 * While we copy addresses, any call to wireless_spy_update() 1311 * will NOP. This is OK, as anyway the addresses are changing. */ 1312 spydata->spy_number = 0; 1313 1314 /* We want to operate without locking, because wireless_spy_update() 1315 * most likely will happen in the interrupt handler, and therefore 1316 * have its own locking constraints and needs performance. 1317 * The rtnl_lock() make sure we don't race with the other iw_handlers. 1318 * This make sure wireless_spy_update() "see" that the spy list 1319 * is temporarily disabled. */ 1320 smp_wmb(); 1321 1322 /* Are there are addresses to copy? */ 1323 if (wrqu->data.length > 0) { 1324 int i; 1325 1326 /* Copy addresses */ 1327 for (i = 0; i < wrqu->data.length; i++) 1328 memcpy(spydata->spy_address[i], address[i].sa_data, 1329 ETH_ALEN); 1330 /* Reset stats */ 1331 memset(spydata->spy_stat, 0, 1332 sizeof(struct iw_quality) * IW_MAX_SPY); 1333 } 1334 1335 /* Make sure above is updated before re-enabling */ 1336 smp_wmb(); 1337 1338 /* Enable addresses */ 1339 spydata->spy_number = wrqu->data.length; 1340 1341 return 0; 1342} 1343EXPORT_SYMBOL(iw_handler_set_spy); 1344 1345/*------------------------------------------------------------------*/ 1346/* 1347 * Standard Wireless Handler : get Spy List 1348 */ 1349int iw_handler_get_spy(struct net_device * dev, 1350 struct iw_request_info * info, 1351 union iwreq_data * wrqu, 1352 char * extra) 1353{ 1354 struct iw_spy_data * spydata = get_spydata(dev); 1355 struct sockaddr * address = (struct sockaddr *) extra; 1356 int i; 1357 1358 /* Make sure driver is not buggy or using the old API */ 1359 if (!spydata) 1360 return -EOPNOTSUPP; 1361 1362 wrqu->data.length = spydata->spy_number; 1363 1364 /* Copy addresses. */ 1365 for (i = 0; i < spydata->spy_number; i++) { 1366 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); 1367 address[i].sa_family = AF_UNIX; 1368 } 1369 /* Copy stats to the user buffer (just after). */ 1370 if (spydata->spy_number > 0) 1371 memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), 1372 spydata->spy_stat, 1373 sizeof(struct iw_quality) * spydata->spy_number); 1374 /* Reset updated flags. */ 1375 for (i = 0; i < spydata->spy_number; i++) 1376 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; 1377 return 0; 1378} 1379EXPORT_SYMBOL(iw_handler_get_spy); 1380 1381/*------------------------------------------------------------------*/ 1382/* 1383 * Standard Wireless Handler : set spy threshold 1384 */ 1385int iw_handler_set_thrspy(struct net_device * dev, 1386 struct iw_request_info *info, 1387 union iwreq_data * wrqu, 1388 char * extra) 1389{ 1390 struct iw_spy_data * spydata = get_spydata(dev); 1391 struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 1392 1393 /* Make sure driver is not buggy or using the old API */ 1394 if (!spydata) 1395 return -EOPNOTSUPP; 1396 1397 /* Just do it */ 1398 memcpy(&(spydata->spy_thr_low), &(threshold->low), 1399 2 * sizeof(struct iw_quality)); 1400 1401 /* Clear flag */ 1402 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); 1403 1404 return 0; 1405} 1406EXPORT_SYMBOL(iw_handler_set_thrspy); 1407 1408/*------------------------------------------------------------------*/ 1409/* 1410 * Standard Wireless Handler : get spy threshold 1411 */ 1412int iw_handler_get_thrspy(struct net_device * dev, 1413 struct iw_request_info *info, 1414 union iwreq_data * wrqu, 1415 char * extra) 1416{ 1417 struct iw_spy_data * spydata = get_spydata(dev); 1418 struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 1419 1420 /* Make sure driver is not buggy or using the old API */ 1421 if (!spydata) 1422 return -EOPNOTSUPP; 1423 1424 /* Just do it */ 1425 memcpy(&(threshold->low), &(spydata->spy_thr_low), 1426 2 * sizeof(struct iw_quality)); 1427 1428 return 0; 1429} 1430EXPORT_SYMBOL(iw_handler_get_thrspy); 1431 1432/*------------------------------------------------------------------*/ 1433/* 1434 * Prepare and send a Spy Threshold event 1435 */ 1436static void iw_send_thrspy_event(struct net_device * dev, 1437 struct iw_spy_data * spydata, 1438 unsigned char * address, 1439 struct iw_quality * wstats) 1440{ 1441 union iwreq_data wrqu; 1442 struct iw_thrspy threshold; 1443 1444 /* Init */ 1445 wrqu.data.length = 1; 1446 wrqu.data.flags = 0; 1447 /* Copy address */ 1448 memcpy(threshold.addr.sa_data, address, ETH_ALEN); 1449 threshold.addr.sa_family = ARPHRD_ETHER; 1450 /* Copy stats */ 1451 memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); 1452 /* Copy also thresholds */ 1453 memcpy(&(threshold.low), &(spydata->spy_thr_low), 1454 2 * sizeof(struct iw_quality)); 1455 1456 /* Send event to user space */ 1457 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); 1458} 1459 1460/* ---------------------------------------------------------------- */ 1461/* 1462 * Call for the driver to update the spy data. 1463 * For now, the spy data is a simple array. As the size of the array is 1464 * small, this is good enough. If we wanted to support larger number of 1465 * spy addresses, we should use something more efficient... 1466 */ 1467void wireless_spy_update(struct net_device * dev, 1468 unsigned char * address, 1469 struct iw_quality * wstats) 1470{ 1471 struct iw_spy_data * spydata = get_spydata(dev); 1472 int i; 1473 int match = -1; 1474 1475 /* Make sure driver is not buggy or using the old API */ 1476 if (!spydata) 1477 return; 1478 1479 /* Update all records that match */ 1480 for (i = 0; i < spydata->spy_number; i++) 1481 if (!compare_ether_addr(address, spydata->spy_address[i])) { 1482 memcpy(&(spydata->spy_stat[i]), wstats, 1483 sizeof(struct iw_quality)); 1484 match = i; 1485 } 1486 1487 /* Generate an event if we cross the spy threshold. 1488 * To avoid event storms, we have a simple hysteresis : we generate 1489 * event only when we go under the low threshold or above the 1490 * high threshold. */ 1491 if (match >= 0) { 1492 if (spydata->spy_thr_under[match]) { 1493 if (wstats->level > spydata->spy_thr_high.level) { 1494 spydata->spy_thr_under[match] = 0; 1495 iw_send_thrspy_event(dev, spydata, 1496 address, wstats); 1497 } 1498 } else { 1499 if (wstats->level < spydata->spy_thr_low.level) { 1500 spydata->spy_thr_under[match] = 1; 1501 iw_send_thrspy_event(dev, spydata, 1502 address, wstats); 1503 } 1504 } 1505 } 1506} 1507EXPORT_SYMBOL(wireless_spy_update);