at v2.6.31-rc1 1691 lines 49 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 lose 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 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 int adjust_priv_size(__u16 args, struct iw_point *iwp) 516{ 517 int num = iwp->length; 518 int max = args & IW_PRIV_SIZE_MASK; 519 int type = (args & IW_PRIV_TYPE_MASK) >> 12; 520 521 /* Make sure the driver doesn't goof up */ 522 if (max < num) 523 num = max; 524 525 return num * iw_priv_type_size[type]; 526} 527 528/* ---------------------------------------------------------------- */ 529/* 530 * Standard Wireless Handler : get wireless stats 531 * Allow programatic access to /proc/net/wireless even if /proc 532 * doesn't exist... Also more efficient... 533 */ 534static int iw_handler_get_iwstats(struct net_device * dev, 535 struct iw_request_info * info, 536 union iwreq_data * wrqu, 537 char * extra) 538{ 539 /* Get stats from the driver */ 540 struct iw_statistics *stats; 541 542 stats = get_wireless_stats(dev); 543 if (stats) { 544 /* Copy statistics to extra */ 545 memcpy(extra, stats, sizeof(struct iw_statistics)); 546 wrqu->data.length = sizeof(struct iw_statistics); 547 548 /* Check if we need to clear the updated flag */ 549 if (wrqu->data.flags != 0) 550 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 551 return 0; 552 } else 553 return -EOPNOTSUPP; 554} 555 556/* ---------------------------------------------------------------- */ 557/* 558 * Standard Wireless Handler : get iwpriv definitions 559 * Export the driver private handler definition 560 * They will be picked up by tools like iwpriv... 561 */ 562static int iw_handler_get_private(struct net_device * dev, 563 struct iw_request_info * info, 564 union iwreq_data * wrqu, 565 char * extra) 566{ 567 /* Check if the driver has something to export */ 568 if ((dev->wireless_handlers->num_private_args == 0) || 569 (dev->wireless_handlers->private_args == NULL)) 570 return -EOPNOTSUPP; 571 572 /* Check if there is enough buffer up there */ 573 if (wrqu->data.length < dev->wireless_handlers->num_private_args) { 574 /* User space can't know in advance how large the buffer 575 * needs to be. Give it a hint, so that we can support 576 * any size buffer we want somewhat efficiently... */ 577 wrqu->data.length = dev->wireless_handlers->num_private_args; 578 return -E2BIG; 579 } 580 581 /* Set the number of available ioctls. */ 582 wrqu->data.length = dev->wireless_handlers->num_private_args; 583 584 /* Copy structure to the user buffer. */ 585 memcpy(extra, dev->wireless_handlers->private_args, 586 sizeof(struct iw_priv_args) * wrqu->data.length); 587 588 return 0; 589} 590 591 592/******************** /proc/net/wireless SUPPORT ********************/ 593/* 594 * The /proc/net/wireless file is a human readable user-space interface 595 * exporting various wireless specific statistics from the wireless devices. 596 * This is the most popular part of the Wireless Extensions ;-) 597 * 598 * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). 599 * The content of the file is basically the content of "struct iw_statistics". 600 */ 601 602#ifdef CONFIG_PROC_FS 603 604/* ---------------------------------------------------------------- */ 605/* 606 * Print one entry (line) of /proc/net/wireless 607 */ 608static void wireless_seq_printf_stats(struct seq_file *seq, 609 struct net_device *dev) 610{ 611 /* Get stats from the driver */ 612 struct iw_statistics *stats = get_wireless_stats(dev); 613 614 if (stats) { 615 seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " 616 "%6d %6d %6d\n", 617 dev->name, stats->status, stats->qual.qual, 618 stats->qual.updated & IW_QUAL_QUAL_UPDATED 619 ? '.' : ' ', 620 ((__s32) stats->qual.level) - 621 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), 622 stats->qual.updated & IW_QUAL_LEVEL_UPDATED 623 ? '.' : ' ', 624 ((__s32) stats->qual.noise) - 625 ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0), 626 stats->qual.updated & IW_QUAL_NOISE_UPDATED 627 ? '.' : ' ', 628 stats->discard.nwid, stats->discard.code, 629 stats->discard.fragment, stats->discard.retries, 630 stats->discard.misc, stats->miss.beacon); 631 stats->qual.updated &= ~IW_QUAL_ALL_UPDATED; 632 } 633} 634 635/* ---------------------------------------------------------------- */ 636/* 637 * Print info for /proc/net/wireless (print all entries) 638 */ 639static int wireless_dev_seq_show(struct seq_file *seq, void *v) 640{ 641 might_sleep(); 642 643 if (v == SEQ_START_TOKEN) 644 seq_printf(seq, "Inter-| sta-| Quality | Discarded " 645 "packets | Missed | WE\n" 646 " face | tus | link level noise | nwid " 647 "crypt frag retry misc | beacon | %d\n", 648 WIRELESS_EXT); 649 else 650 wireless_seq_printf_stats(seq, v); 651 return 0; 652} 653 654static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos) 655{ 656 struct net *net = seq_file_net(seq); 657 loff_t off; 658 struct net_device *dev; 659 660 rtnl_lock(); 661 if (!*pos) 662 return SEQ_START_TOKEN; 663 664 off = 1; 665 for_each_netdev(net, dev) 666 if (off++ == *pos) 667 return dev; 668 return NULL; 669} 670 671static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) 672{ 673 struct net *net = seq_file_net(seq); 674 675 ++*pos; 676 677 return v == SEQ_START_TOKEN ? 678 first_net_device(net) : next_net_device(v); 679} 680 681static void wireless_dev_seq_stop(struct seq_file *seq, void *v) 682{ 683 rtnl_unlock(); 684} 685 686static const struct seq_operations wireless_seq_ops = { 687 .start = wireless_dev_seq_start, 688 .next = wireless_dev_seq_next, 689 .stop = wireless_dev_seq_stop, 690 .show = wireless_dev_seq_show, 691}; 692 693static int seq_open_wireless(struct inode *inode, struct file *file) 694{ 695 return seq_open_net(inode, file, &wireless_seq_ops, 696 sizeof(struct seq_net_private)); 697} 698 699static const struct file_operations wireless_seq_fops = { 700 .owner = THIS_MODULE, 701 .open = seq_open_wireless, 702 .read = seq_read, 703 .llseek = seq_lseek, 704 .release = seq_release_net, 705}; 706 707int wext_proc_init(struct net *net) 708{ 709 /* Create /proc/net/wireless entry */ 710 if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops)) 711 return -ENOMEM; 712 713 return 0; 714} 715 716void wext_proc_exit(struct net *net) 717{ 718 proc_net_remove(net, "wireless"); 719} 720#endif /* CONFIG_PROC_FS */ 721 722/************************** IOCTL SUPPORT **************************/ 723/* 724 * The original user space API to configure all those Wireless Extensions 725 * is through IOCTLs. 726 * In there, we check if we need to call the new driver API (iw_handler) 727 * or just call the driver ioctl handler. 728 */ 729 730/* ---------------------------------------------------------------- */ 731static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, 732 const struct iw_ioctl_description *descr, 733 iw_handler handler, struct net_device *dev, 734 struct iw_request_info *info) 735{ 736 int err, extra_size, user_length = 0, essid_compat = 0; 737 char *extra; 738 739 /* Calculate space needed by arguments. Always allocate 740 * for max space. 741 */ 742 extra_size = descr->max_tokens * descr->token_size; 743 744 /* Check need for ESSID compatibility for WE < 21 */ 745 switch (cmd) { 746 case SIOCSIWESSID: 747 case SIOCGIWESSID: 748 case SIOCSIWNICKN: 749 case SIOCGIWNICKN: 750 if (iwp->length == descr->max_tokens + 1) 751 essid_compat = 1; 752 else if (IW_IS_SET(cmd) && (iwp->length != 0)) { 753 char essid[IW_ESSID_MAX_SIZE + 1]; 754 755 err = copy_from_user(essid, iwp->pointer, 756 iwp->length * 757 descr->token_size); 758 if (err) 759 return -EFAULT; 760 761 if (essid[iwp->length - 1] == '\0') 762 essid_compat = 1; 763 } 764 break; 765 default: 766 break; 767 } 768 769 iwp->length -= essid_compat; 770 771 /* Check what user space is giving us */ 772 if (IW_IS_SET(cmd)) { 773 /* Check NULL pointer */ 774 if (!iwp->pointer && iwp->length != 0) 775 return -EFAULT; 776 /* Check if number of token fits within bounds */ 777 if (iwp->length > descr->max_tokens) 778 return -E2BIG; 779 if (iwp->length < descr->min_tokens) 780 return -EINVAL; 781 } else { 782 /* Check NULL pointer */ 783 if (!iwp->pointer) 784 return -EFAULT; 785 /* Save user space buffer size for checking */ 786 user_length = iwp->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 793 /* Support for very large requests */ 794 if ((descr->flags & IW_DESCR_FLAG_NOMAX) && 795 (user_length > descr->max_tokens)) { 796 /* Allow userspace to GET more than max so 797 * we can support any size GET requests. 798 * There is still a limit : -ENOMEM. 799 */ 800 extra_size = user_length * descr->token_size; 801 802 /* Note : user_length is originally a __u16, 803 * and token_size is controlled by us, 804 * so extra_size won't get negative and 805 * won't overflow... 806 */ 807 } 808 } 809 810 /* kzalloc() ensures NULL-termination for essid_compat. */ 811 extra = kzalloc(extra_size, GFP_KERNEL); 812 if (!extra) 813 return -ENOMEM; 814 815 /* If it is a SET, get all the extra data in here */ 816 if (IW_IS_SET(cmd) && (iwp->length != 0)) { 817 if (copy_from_user(extra, iwp->pointer, 818 iwp->length * 819 descr->token_size)) { 820 err = -EFAULT; 821 goto out; 822 } 823 824 if (cmd == SIOCSIWENCODEEXT) { 825 struct iw_encode_ext *ee = (void *) extra; 826 827 if (iwp->length < sizeof(*ee) + ee->key_len) 828 return -EFAULT; 829 } 830 } 831 832 err = handler(dev, info, (union iwreq_data *) iwp, extra); 833 834 iwp->length += essid_compat; 835 836 /* If we have something to return to the user */ 837 if (!err && IW_IS_GET(cmd)) { 838 /* Check if there is enough buffer up there */ 839 if (user_length < iwp->length) { 840 err = -E2BIG; 841 goto out; 842 } 843 844 if (copy_to_user(iwp->pointer, extra, 845 iwp->length * 846 descr->token_size)) { 847 err = -EFAULT; 848 goto out; 849 } 850 } 851 852 /* Generate an event to notify listeners of the change */ 853 if ((descr->flags & IW_DESCR_FLAG_EVENT) && err == -EIWCOMMIT) { 854 union iwreq_data *data = (union iwreq_data *) iwp; 855 856 if (descr->flags & IW_DESCR_FLAG_RESTRICT) 857 /* If the event is restricted, don't 858 * export the payload. 859 */ 860 wireless_send_event(dev, cmd, data, NULL); 861 else 862 wireless_send_event(dev, cmd, data, extra); 863 } 864 865out: 866 kfree(extra); 867 return err; 868} 869 870/* 871 * Wrapper to call a standard Wireless Extension handler. 872 * We do various checks and also take care of moving data between 873 * user space and kernel space. 874 */ 875static int ioctl_standard_call(struct net_device * dev, 876 struct iwreq *iwr, 877 unsigned int cmd, 878 struct iw_request_info *info, 879 iw_handler handler) 880{ 881 const struct iw_ioctl_description * descr; 882 int ret = -EINVAL; 883 884 /* Get the description of the IOCTL */ 885 if ((cmd - SIOCIWFIRST) >= standard_ioctl_num) 886 return -EOPNOTSUPP; 887 descr = &(standard_ioctl[cmd - SIOCIWFIRST]); 888 889 /* Check if we have a pointer to user space data or not */ 890 if (descr->header_type != IW_HEADER_TYPE_POINT) { 891 892 /* No extra arguments. Trivial to handle */ 893 ret = handler(dev, info, &(iwr->u), NULL); 894 895 /* Generate an event to notify listeners of the change */ 896 if ((descr->flags & IW_DESCR_FLAG_EVENT) && 897 ((ret == 0) || (ret == -EIWCOMMIT))) 898 wireless_send_event(dev, cmd, &(iwr->u), NULL); 899 } else { 900 ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr, 901 handler, dev, info); 902 } 903 904 /* Call commit handler if needed and defined */ 905 if (ret == -EIWCOMMIT) 906 ret = call_commit_handler(dev); 907 908 /* Here, we will generate the appropriate event if needed */ 909 910 return ret; 911} 912 913/* ---------------------------------------------------------------- */ 914/* 915 * Wrapper to call a private Wireless Extension handler. 916 * We do various checks and also take care of moving data between 917 * user space and kernel space. 918 * It's not as nice and slimline as the standard wrapper. The cause 919 * is struct iw_priv_args, which was not really designed for the 920 * job we are going here. 921 * 922 * IMPORTANT : This function prevent to set and get data on the same 923 * IOCTL and enforce the SET/GET convention. Not doing it would be 924 * far too hairy... 925 * If you need to set and get data at the same time, please don't use 926 * a iw_handler but process it in your ioctl handler (i.e. use the 927 * old driver API). 928 */ 929static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd, 930 const struct iw_priv_args **descrp) 931{ 932 const struct iw_priv_args *descr; 933 int i, extra_size; 934 935 descr = NULL; 936 for (i = 0; i < dev->wireless_handlers->num_private_args; i++) { 937 if (cmd == dev->wireless_handlers->private_args[i].cmd) { 938 descr = &dev->wireless_handlers->private_args[i]; 939 break; 940 } 941 } 942 943 extra_size = 0; 944 if (descr) { 945 if (IW_IS_SET(cmd)) { 946 int offset = 0; /* For sub-ioctls */ 947 /* Check for sub-ioctl handler */ 948 if (descr->name[0] == '\0') 949 /* Reserve one int for sub-ioctl index */ 950 offset = sizeof(__u32); 951 952 /* Size of set arguments */ 953 extra_size = get_priv_size(descr->set_args); 954 955 /* Does it fits in iwr ? */ 956 if ((descr->set_args & IW_PRIV_SIZE_FIXED) && 957 ((extra_size + offset) <= IFNAMSIZ)) 958 extra_size = 0; 959 } else { 960 /* Size of get arguments */ 961 extra_size = get_priv_size(descr->get_args); 962 963 /* Does it fits in iwr ? */ 964 if ((descr->get_args & IW_PRIV_SIZE_FIXED) && 965 (extra_size <= IFNAMSIZ)) 966 extra_size = 0; 967 } 968 } 969 *descrp = descr; 970 return extra_size; 971} 972 973static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd, 974 const struct iw_priv_args *descr, 975 iw_handler handler, struct net_device *dev, 976 struct iw_request_info *info, int extra_size) 977{ 978 char *extra; 979 int err; 980 981 /* Check what user space is giving us */ 982 if (IW_IS_SET(cmd)) { 983 if (!iwp->pointer && iwp->length != 0) 984 return -EFAULT; 985 986 if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK)) 987 return -E2BIG; 988 } else if (!iwp->pointer) 989 return -EFAULT; 990 991 extra = kmalloc(extra_size, GFP_KERNEL); 992 if (!extra) 993 return -ENOMEM; 994 995 /* If it is a SET, get all the extra data in here */ 996 if (IW_IS_SET(cmd) && (iwp->length != 0)) { 997 if (copy_from_user(extra, iwp->pointer, extra_size)) { 998 err = -EFAULT; 999 goto out; 1000 } 1001 } 1002 1003 /* Call the handler */ 1004 err = handler(dev, info, (union iwreq_data *) iwp, extra); 1005 1006 /* If we have something to return to the user */ 1007 if (!err && IW_IS_GET(cmd)) { 1008 /* Adjust for the actual length if it's variable, 1009 * avoid leaking kernel bits outside. 1010 */ 1011 if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) 1012 extra_size = adjust_priv_size(descr->get_args, iwp); 1013 1014 if (copy_to_user(iwp->pointer, extra, extra_size)) 1015 err = -EFAULT; 1016 } 1017 1018out: 1019 kfree(extra); 1020 return err; 1021} 1022 1023static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, 1024 unsigned int cmd, struct iw_request_info *info, 1025 iw_handler handler) 1026{ 1027 int extra_size = 0, ret = -EINVAL; 1028 const struct iw_priv_args *descr; 1029 1030 extra_size = get_priv_descr_and_size(dev, cmd, &descr); 1031 1032 /* Check if we have a pointer to user space data or not. */ 1033 if (extra_size == 0) { 1034 /* No extra arguments. Trivial to handle */ 1035 ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); 1036 } else { 1037 ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr, 1038 handler, dev, info, extra_size); 1039 } 1040 1041 /* Call commit handler if needed and defined */ 1042 if (ret == -EIWCOMMIT) 1043 ret = call_commit_handler(dev); 1044 1045 return ret; 1046} 1047 1048/* ---------------------------------------------------------------- */ 1049typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *, 1050 unsigned int, struct iw_request_info *, 1051 iw_handler); 1052 1053/* 1054 * Main IOCTl dispatcher. 1055 * Check the type of IOCTL and call the appropriate wrapper... 1056 */ 1057static int wireless_process_ioctl(struct net *net, struct ifreq *ifr, 1058 unsigned int cmd, 1059 struct iw_request_info *info, 1060 wext_ioctl_func standard, 1061 wext_ioctl_func private) 1062{ 1063 struct iwreq *iwr = (struct iwreq *) ifr; 1064 struct net_device *dev; 1065 iw_handler handler; 1066 1067 /* Permissions are already checked in dev_ioctl() before calling us. 1068 * The copy_to/from_user() of ifr is also dealt with in there */ 1069 1070 /* Make sure the device exist */ 1071 if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL) 1072 return -ENODEV; 1073 1074 /* A bunch of special cases, then the generic case... 1075 * Note that 'cmd' is already filtered in dev_ioctl() with 1076 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ 1077 if (cmd == SIOCGIWSTATS) 1078 return standard(dev, iwr, cmd, info, 1079 &iw_handler_get_iwstats); 1080 1081 if (cmd == SIOCGIWPRIV && dev->wireless_handlers) 1082 return standard(dev, iwr, cmd, info, 1083 &iw_handler_get_private); 1084 1085 /* Basic check */ 1086 if (!netif_device_present(dev)) 1087 return -ENODEV; 1088 1089 /* New driver API : try to find the handler */ 1090 handler = get_handler(dev, cmd); 1091 if (handler) { 1092 /* Standard and private are not the same */ 1093 if (cmd < SIOCIWFIRSTPRIV) 1094 return standard(dev, iwr, cmd, info, handler); 1095 else 1096 return private(dev, iwr, cmd, info, handler); 1097 } 1098 /* Old driver API : call driver ioctl handler */ 1099 if (dev->netdev_ops->ndo_do_ioctl) 1100 return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd); 1101 return -EOPNOTSUPP; 1102} 1103 1104/* If command is `set a parameter', or `get the encoding parameters', 1105 * check if the user has the right to do it. 1106 */ 1107static int wext_permission_check(unsigned int cmd) 1108{ 1109 if ((IW_IS_SET(cmd) || cmd == SIOCGIWENCODE || cmd == SIOCGIWENCODEEXT) 1110 && !capable(CAP_NET_ADMIN)) 1111 return -EPERM; 1112 1113 return 0; 1114} 1115 1116/* entry point from dev ioctl */ 1117static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr, 1118 unsigned int cmd, struct iw_request_info *info, 1119 wext_ioctl_func standard, 1120 wext_ioctl_func private) 1121{ 1122 int ret = wext_permission_check(cmd); 1123 1124 if (ret) 1125 return ret; 1126 1127 dev_load(net, ifr->ifr_name); 1128 rtnl_lock(); 1129 ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private); 1130 rtnl_unlock(); 1131 1132 return ret; 1133} 1134 1135int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, 1136 void __user *arg) 1137{ 1138 struct iw_request_info info = { .cmd = cmd, .flags = 0 }; 1139 int ret; 1140 1141 ret = wext_ioctl_dispatch(net, ifr, cmd, &info, 1142 ioctl_standard_call, 1143 ioctl_private_call); 1144 if (ret >= 0 && 1145 IW_IS_GET(cmd) && 1146 copy_to_user(arg, ifr, sizeof(struct iwreq))) 1147 return -EFAULT; 1148 1149 return ret; 1150} 1151 1152#ifdef CONFIG_COMPAT 1153static int compat_standard_call(struct net_device *dev, 1154 struct iwreq *iwr, 1155 unsigned int cmd, 1156 struct iw_request_info *info, 1157 iw_handler handler) 1158{ 1159 const struct iw_ioctl_description *descr; 1160 struct compat_iw_point *iwp_compat; 1161 struct iw_point iwp; 1162 int err; 1163 1164 descr = standard_ioctl + (cmd - SIOCIWFIRST); 1165 1166 if (descr->header_type != IW_HEADER_TYPE_POINT) 1167 return ioctl_standard_call(dev, iwr, cmd, info, handler); 1168 1169 iwp_compat = (struct compat_iw_point *) &iwr->u.data; 1170 iwp.pointer = compat_ptr(iwp_compat->pointer); 1171 iwp.length = iwp_compat->length; 1172 iwp.flags = iwp_compat->flags; 1173 1174 err = ioctl_standard_iw_point(&iwp, cmd, descr, handler, dev, info); 1175 1176 iwp_compat->pointer = ptr_to_compat(iwp.pointer); 1177 iwp_compat->length = iwp.length; 1178 iwp_compat->flags = iwp.flags; 1179 1180 return err; 1181} 1182 1183static int compat_private_call(struct net_device *dev, struct iwreq *iwr, 1184 unsigned int cmd, struct iw_request_info *info, 1185 iw_handler handler) 1186{ 1187 const struct iw_priv_args *descr; 1188 int ret, extra_size; 1189 1190 extra_size = get_priv_descr_and_size(dev, cmd, &descr); 1191 1192 /* Check if we have a pointer to user space data or not. */ 1193 if (extra_size == 0) { 1194 /* No extra arguments. Trivial to handle */ 1195 ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u)); 1196 } else { 1197 struct compat_iw_point *iwp_compat; 1198 struct iw_point iwp; 1199 1200 iwp_compat = (struct compat_iw_point *) &iwr->u.data; 1201 iwp.pointer = compat_ptr(iwp_compat->pointer); 1202 iwp.length = iwp_compat->length; 1203 iwp.flags = iwp_compat->flags; 1204 1205 ret = ioctl_private_iw_point(&iwp, cmd, descr, 1206 handler, dev, info, extra_size); 1207 1208 iwp_compat->pointer = ptr_to_compat(iwp.pointer); 1209 iwp_compat->length = iwp.length; 1210 iwp_compat->flags = iwp.flags; 1211 } 1212 1213 /* Call commit handler if needed and defined */ 1214 if (ret == -EIWCOMMIT) 1215 ret = call_commit_handler(dev); 1216 1217 return ret; 1218} 1219 1220int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, 1221 unsigned long arg) 1222{ 1223 void __user *argp = (void __user *)arg; 1224 struct iw_request_info info; 1225 struct iwreq iwr; 1226 char *colon; 1227 int ret; 1228 1229 if (copy_from_user(&iwr, argp, sizeof(struct iwreq))) 1230 return -EFAULT; 1231 1232 iwr.ifr_name[IFNAMSIZ-1] = 0; 1233 colon = strchr(iwr.ifr_name, ':'); 1234 if (colon) 1235 *colon = 0; 1236 1237 info.cmd = cmd; 1238 info.flags = IW_REQUEST_FLAG_COMPAT; 1239 1240 ret = wext_ioctl_dispatch(net, (struct ifreq *) &iwr, cmd, &info, 1241 compat_standard_call, 1242 compat_private_call); 1243 1244 if (ret >= 0 && 1245 IW_IS_GET(cmd) && 1246 copy_to_user(argp, &iwr, sizeof(struct iwreq))) 1247 return -EFAULT; 1248 1249 return ret; 1250} 1251#endif 1252 1253/************************* EVENT PROCESSING *************************/ 1254/* 1255 * Process events generated by the wireless layer or the driver. 1256 * Most often, the event will be propagated through rtnetlink 1257 */ 1258 1259/* ---------------------------------------------------------------- */ 1260/* 1261 * Locking... 1262 * ---------- 1263 * 1264 * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing 1265 * the locking issue in here and implementing this code ! 1266 * 1267 * The issue : wireless_send_event() is often called in interrupt context, 1268 * while the Netlink layer can never be called in interrupt context. 1269 * The fully formed RtNetlink events are queued, and then a tasklet is run 1270 * to feed those to Netlink. 1271 * The skb_queue is interrupt safe, and its lock is not held while calling 1272 * Netlink, so there is no possibility of dealock. 1273 * Jean II 1274 */ 1275 1276static struct sk_buff_head wireless_nlevent_queue; 1277 1278static int __init wireless_nlevent_init(void) 1279{ 1280 skb_queue_head_init(&wireless_nlevent_queue); 1281 return 0; 1282} 1283 1284subsys_initcall(wireless_nlevent_init); 1285 1286static void wireless_nlevent_process(unsigned long data) 1287{ 1288 struct sk_buff *skb; 1289 1290 while ((skb = skb_dequeue(&wireless_nlevent_queue))) 1291 rtnl_notify(skb, &init_net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); 1292} 1293 1294static DECLARE_TASKLET(wireless_nlevent_tasklet, wireless_nlevent_process, 0); 1295 1296/* ---------------------------------------------------------------- */ 1297/* 1298 * Fill a rtnetlink message with our event data. 1299 * Note that we propage only the specified event and don't dump the 1300 * current wireless config. Dumping the wireless config is far too 1301 * expensive (for each parameter, the driver need to query the hardware). 1302 */ 1303static int rtnetlink_fill_iwinfo(struct sk_buff *skb, struct net_device *dev, 1304 int type, char *event, int event_len) 1305{ 1306 struct ifinfomsg *r; 1307 struct nlmsghdr *nlh; 1308 1309 nlh = nlmsg_put(skb, 0, 0, type, sizeof(*r), 0); 1310 if (nlh == NULL) 1311 return -EMSGSIZE; 1312 1313 r = nlmsg_data(nlh); 1314 r->ifi_family = AF_UNSPEC; 1315 r->__ifi_pad = 0; 1316 r->ifi_type = dev->type; 1317 r->ifi_index = dev->ifindex; 1318 r->ifi_flags = dev_get_flags(dev); 1319 r->ifi_change = 0; /* Wireless changes don't affect those flags */ 1320 1321 NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name); 1322 /* Add the wireless events in the netlink packet */ 1323 NLA_PUT(skb, IFLA_WIRELESS, event_len, event); 1324 1325 return nlmsg_end(skb, nlh); 1326 1327nla_put_failure: 1328 nlmsg_cancel(skb, nlh); 1329 return -EMSGSIZE; 1330} 1331 1332/* ---------------------------------------------------------------- */ 1333/* 1334 * Create and broadcast and send it on the standard rtnetlink socket 1335 * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c 1336 * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field 1337 * within a RTM_NEWLINK event. 1338 */ 1339static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) 1340{ 1341 struct sk_buff *skb; 1342 int err; 1343 1344 if (!net_eq(dev_net(dev), &init_net)) 1345 return; 1346 1347 skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 1348 if (!skb) 1349 return; 1350 1351 err = rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, event, event_len); 1352 if (err < 0) { 1353 WARN_ON(err == -EMSGSIZE); 1354 kfree_skb(skb); 1355 return; 1356 } 1357 1358 NETLINK_CB(skb).dst_group = RTNLGRP_LINK; 1359 skb_queue_tail(&wireless_nlevent_queue, skb); 1360 tasklet_schedule(&wireless_nlevent_tasklet); 1361} 1362 1363/* ---------------------------------------------------------------- */ 1364/* 1365 * Main event dispatcher. Called from other parts and drivers. 1366 * Send the event on the appropriate channels. 1367 * May be called from interrupt context. 1368 */ 1369void wireless_send_event(struct net_device * dev, 1370 unsigned int cmd, 1371 union iwreq_data * wrqu, 1372 char * extra) 1373{ 1374 const struct iw_ioctl_description * descr = NULL; 1375 int extra_len = 0; 1376 struct iw_event *event; /* Mallocated whole event */ 1377 int event_len; /* Its size */ 1378 int hdr_len; /* Size of the event header */ 1379 int wrqu_off = 0; /* Offset in wrqu */ 1380 /* Don't "optimise" the following variable, it will crash */ 1381 unsigned cmd_index; /* *MUST* be unsigned */ 1382 1383 /* Get the description of the Event */ 1384 if (cmd <= SIOCIWLAST) { 1385 cmd_index = cmd - SIOCIWFIRST; 1386 if (cmd_index < standard_ioctl_num) 1387 descr = &(standard_ioctl[cmd_index]); 1388 } else { 1389 cmd_index = cmd - IWEVFIRST; 1390 if (cmd_index < standard_event_num) 1391 descr = &(standard_event[cmd_index]); 1392 } 1393 /* Don't accept unknown events */ 1394 if (descr == NULL) { 1395 /* Note : we don't return an error to the driver, because 1396 * the driver would not know what to do about it. It can't 1397 * return an error to the user, because the event is not 1398 * initiated by a user request. 1399 * The best the driver could do is to log an error message. 1400 * We will do it ourselves instead... 1401 */ 1402 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", 1403 dev->name, cmd); 1404 return; 1405 } 1406 1407 /* Check extra parameters and set extra_len */ 1408 if (descr->header_type == IW_HEADER_TYPE_POINT) { 1409 /* Check if number of token fits within bounds */ 1410 if (wrqu->data.length > descr->max_tokens) { 1411 printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); 1412 return; 1413 } 1414 if (wrqu->data.length < descr->min_tokens) { 1415 printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); 1416 return; 1417 } 1418 /* Calculate extra_len - extra is NULL for restricted events */ 1419 if (extra != NULL) 1420 extra_len = wrqu->data.length * descr->token_size; 1421 /* Always at an offset in wrqu */ 1422 wrqu_off = IW_EV_POINT_OFF; 1423 } 1424 1425 /* Total length of the event */ 1426 hdr_len = event_type_size[descr->header_type]; 1427 event_len = hdr_len + extra_len; 1428 1429 /* Create temporary buffer to hold the event */ 1430 event = kmalloc(event_len, GFP_ATOMIC); 1431 if (event == NULL) 1432 return; 1433 1434 /* Fill event */ 1435 event->len = event_len; 1436 event->cmd = cmd; 1437 memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN); 1438 if (extra) 1439 memcpy(((char *) event) + hdr_len, extra, extra_len); 1440 1441 /* Send via the RtNetlink event channel */ 1442 rtmsg_iwinfo(dev, (char *) event, event_len); 1443 1444 /* Cleanup */ 1445 kfree(event); 1446 1447 return; /* Always success, I guess ;-) */ 1448} 1449EXPORT_SYMBOL(wireless_send_event); 1450 1451/********************** ENHANCED IWSPY SUPPORT **********************/ 1452/* 1453 * In the old days, the driver was handling spy support all by itself. 1454 * Now, the driver can delegate this task to Wireless Extensions. 1455 * It needs to use those standard spy iw_handler in struct iw_handler_def, 1456 * push data to us via wireless_spy_update() and include struct iw_spy_data 1457 * in its private part (and export it in net_device->wireless_data->spy_data). 1458 * One of the main advantage of centralising spy support here is that 1459 * it becomes much easier to improve and extend it without having to touch 1460 * the drivers. One example is the addition of the Spy-Threshold events. 1461 */ 1462 1463/* ---------------------------------------------------------------- */ 1464/* 1465 * Return the pointer to the spy data in the driver. 1466 * Because this is called on the Rx path via wireless_spy_update(), 1467 * we want it to be efficient... 1468 */ 1469static inline struct iw_spy_data *get_spydata(struct net_device *dev) 1470{ 1471 /* This is the new way */ 1472 if (dev->wireless_data) 1473 return dev->wireless_data->spy_data; 1474 return NULL; 1475} 1476 1477/*------------------------------------------------------------------*/ 1478/* 1479 * Standard Wireless Handler : set Spy List 1480 */ 1481int iw_handler_set_spy(struct net_device * dev, 1482 struct iw_request_info * info, 1483 union iwreq_data * wrqu, 1484 char * extra) 1485{ 1486 struct iw_spy_data * spydata = get_spydata(dev); 1487 struct sockaddr * address = (struct sockaddr *) extra; 1488 1489 /* Make sure driver is not buggy or using the old API */ 1490 if (!spydata) 1491 return -EOPNOTSUPP; 1492 1493 /* Disable spy collection while we copy the addresses. 1494 * While we copy addresses, any call to wireless_spy_update() 1495 * will NOP. This is OK, as anyway the addresses are changing. */ 1496 spydata->spy_number = 0; 1497 1498 /* We want to operate without locking, because wireless_spy_update() 1499 * most likely will happen in the interrupt handler, and therefore 1500 * have its own locking constraints and needs performance. 1501 * The rtnl_lock() make sure we don't race with the other iw_handlers. 1502 * This make sure wireless_spy_update() "see" that the spy list 1503 * is temporarily disabled. */ 1504 smp_wmb(); 1505 1506 /* Are there are addresses to copy? */ 1507 if (wrqu->data.length > 0) { 1508 int i; 1509 1510 /* Copy addresses */ 1511 for (i = 0; i < wrqu->data.length; i++) 1512 memcpy(spydata->spy_address[i], address[i].sa_data, 1513 ETH_ALEN); 1514 /* Reset stats */ 1515 memset(spydata->spy_stat, 0, 1516 sizeof(struct iw_quality) * IW_MAX_SPY); 1517 } 1518 1519 /* Make sure above is updated before re-enabling */ 1520 smp_wmb(); 1521 1522 /* Enable addresses */ 1523 spydata->spy_number = wrqu->data.length; 1524 1525 return 0; 1526} 1527EXPORT_SYMBOL(iw_handler_set_spy); 1528 1529/*------------------------------------------------------------------*/ 1530/* 1531 * Standard Wireless Handler : get Spy List 1532 */ 1533int iw_handler_get_spy(struct net_device * dev, 1534 struct iw_request_info * info, 1535 union iwreq_data * wrqu, 1536 char * extra) 1537{ 1538 struct iw_spy_data * spydata = get_spydata(dev); 1539 struct sockaddr * address = (struct sockaddr *) extra; 1540 int i; 1541 1542 /* Make sure driver is not buggy or using the old API */ 1543 if (!spydata) 1544 return -EOPNOTSUPP; 1545 1546 wrqu->data.length = spydata->spy_number; 1547 1548 /* Copy addresses. */ 1549 for (i = 0; i < spydata->spy_number; i++) { 1550 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); 1551 address[i].sa_family = AF_UNIX; 1552 } 1553 /* Copy stats to the user buffer (just after). */ 1554 if (spydata->spy_number > 0) 1555 memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), 1556 spydata->spy_stat, 1557 sizeof(struct iw_quality) * spydata->spy_number); 1558 /* Reset updated flags. */ 1559 for (i = 0; i < spydata->spy_number; i++) 1560 spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED; 1561 return 0; 1562} 1563EXPORT_SYMBOL(iw_handler_get_spy); 1564 1565/*------------------------------------------------------------------*/ 1566/* 1567 * Standard Wireless Handler : set spy threshold 1568 */ 1569int iw_handler_set_thrspy(struct net_device * dev, 1570 struct iw_request_info *info, 1571 union iwreq_data * wrqu, 1572 char * extra) 1573{ 1574 struct iw_spy_data * spydata = get_spydata(dev); 1575 struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 1576 1577 /* Make sure driver is not buggy or using the old API */ 1578 if (!spydata) 1579 return -EOPNOTSUPP; 1580 1581 /* Just do it */ 1582 memcpy(&(spydata->spy_thr_low), &(threshold->low), 1583 2 * sizeof(struct iw_quality)); 1584 1585 /* Clear flag */ 1586 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); 1587 1588 return 0; 1589} 1590EXPORT_SYMBOL(iw_handler_set_thrspy); 1591 1592/*------------------------------------------------------------------*/ 1593/* 1594 * Standard Wireless Handler : get spy threshold 1595 */ 1596int iw_handler_get_thrspy(struct net_device * dev, 1597 struct iw_request_info *info, 1598 union iwreq_data * wrqu, 1599 char * extra) 1600{ 1601 struct iw_spy_data * spydata = get_spydata(dev); 1602 struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 1603 1604 /* Make sure driver is not buggy or using the old API */ 1605 if (!spydata) 1606 return -EOPNOTSUPP; 1607 1608 /* Just do it */ 1609 memcpy(&(threshold->low), &(spydata->spy_thr_low), 1610 2 * sizeof(struct iw_quality)); 1611 1612 return 0; 1613} 1614EXPORT_SYMBOL(iw_handler_get_thrspy); 1615 1616/*------------------------------------------------------------------*/ 1617/* 1618 * Prepare and send a Spy Threshold event 1619 */ 1620static void iw_send_thrspy_event(struct net_device * dev, 1621 struct iw_spy_data * spydata, 1622 unsigned char * address, 1623 struct iw_quality * wstats) 1624{ 1625 union iwreq_data wrqu; 1626 struct iw_thrspy threshold; 1627 1628 /* Init */ 1629 wrqu.data.length = 1; 1630 wrqu.data.flags = 0; 1631 /* Copy address */ 1632 memcpy(threshold.addr.sa_data, address, ETH_ALEN); 1633 threshold.addr.sa_family = ARPHRD_ETHER; 1634 /* Copy stats */ 1635 memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); 1636 /* Copy also thresholds */ 1637 memcpy(&(threshold.low), &(spydata->spy_thr_low), 1638 2 * sizeof(struct iw_quality)); 1639 1640 /* Send event to user space */ 1641 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); 1642} 1643 1644/* ---------------------------------------------------------------- */ 1645/* 1646 * Call for the driver to update the spy data. 1647 * For now, the spy data is a simple array. As the size of the array is 1648 * small, this is good enough. If we wanted to support larger number of 1649 * spy addresses, we should use something more efficient... 1650 */ 1651void wireless_spy_update(struct net_device * dev, 1652 unsigned char * address, 1653 struct iw_quality * wstats) 1654{ 1655 struct iw_spy_data * spydata = get_spydata(dev); 1656 int i; 1657 int match = -1; 1658 1659 /* Make sure driver is not buggy or using the old API */ 1660 if (!spydata) 1661 return; 1662 1663 /* Update all records that match */ 1664 for (i = 0; i < spydata->spy_number; i++) 1665 if (!compare_ether_addr(address, spydata->spy_address[i])) { 1666 memcpy(&(spydata->spy_stat[i]), wstats, 1667 sizeof(struct iw_quality)); 1668 match = i; 1669 } 1670 1671 /* Generate an event if we cross the spy threshold. 1672 * To avoid event storms, we have a simple hysteresis : we generate 1673 * event only when we go under the low threshold or above the 1674 * high threshold. */ 1675 if (match >= 0) { 1676 if (spydata->spy_thr_under[match]) { 1677 if (wstats->level > spydata->spy_thr_high.level) { 1678 spydata->spy_thr_under[match] = 0; 1679 iw_send_thrspy_event(dev, spydata, 1680 address, wstats); 1681 } 1682 } else { 1683 if (wstats->level < spydata->spy_thr_low.level) { 1684 spydata->spy_thr_under[match] = 1; 1685 iw_send_thrspy_event(dev, spydata, 1686 address, wstats); 1687 } 1688 } 1689 } 1690} 1691EXPORT_SYMBOL(wireless_spy_update);