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