at v2.6.13-rc3 1530 lines 47 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-2005 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 63/***************************** INCLUDES *****************************/ 64 65#include <linux/config.h> /* Not needed ??? */ 66#include <linux/module.h> 67#include <linux/types.h> /* off_t */ 68#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */ 69#include <linux/proc_fs.h> 70#include <linux/rtnetlink.h> /* rtnetlink stuff */ 71#include <linux/seq_file.h> 72#include <linux/init.h> /* for __init */ 73#include <linux/if_arp.h> /* ARPHRD_ETHER */ 74 75#include <linux/wireless.h> /* Pretty obvious */ 76#include <net/iw_handler.h> /* New driver API */ 77 78#include <asm/uaccess.h> /* copy_to_user() */ 79 80/**************************** CONSTANTS ****************************/ 81 82/* Debugging stuff */ 83#undef WE_IOCTL_DEBUG /* Debug IOCTL API */ 84#undef WE_EVENT_DEBUG /* Debug Event dispatcher */ 85#undef WE_SPY_DEBUG /* Debug enhanced spy support */ 86 87/* Options */ 88#define WE_EVENT_NETLINK /* Propagate events using rtnetlink */ 89#define WE_SET_EVENT /* Generate an event on some set commands */ 90 91/************************* GLOBAL VARIABLES *************************/ 92/* 93 * You should not use global variables, because of re-entrancy. 94 * On our case, it's only const, so it's OK... 95 */ 96/* 97 * Meta-data about all the standard Wireless Extension request we 98 * know about. 99 */ 100static const struct iw_ioctl_description standard_ioctl[] = { 101 [SIOCSIWCOMMIT - SIOCIWFIRST] = { 102 .header_type = IW_HEADER_TYPE_NULL, 103 }, 104 [SIOCGIWNAME - SIOCIWFIRST] = { 105 .header_type = IW_HEADER_TYPE_CHAR, 106 .flags = IW_DESCR_FLAG_DUMP, 107 }, 108 [SIOCSIWNWID - SIOCIWFIRST] = { 109 .header_type = IW_HEADER_TYPE_PARAM, 110 .flags = IW_DESCR_FLAG_EVENT, 111 }, 112 [SIOCGIWNWID - SIOCIWFIRST] = { 113 .header_type = IW_HEADER_TYPE_PARAM, 114 .flags = IW_DESCR_FLAG_DUMP, 115 }, 116 [SIOCSIWFREQ - SIOCIWFIRST] = { 117 .header_type = IW_HEADER_TYPE_FREQ, 118 .flags = IW_DESCR_FLAG_EVENT, 119 }, 120 [SIOCGIWFREQ - SIOCIWFIRST] = { 121 .header_type = IW_HEADER_TYPE_FREQ, 122 .flags = IW_DESCR_FLAG_DUMP, 123 }, 124 [SIOCSIWMODE - SIOCIWFIRST] = { 125 .header_type = IW_HEADER_TYPE_UINT, 126 .flags = IW_DESCR_FLAG_EVENT, 127 }, 128 [SIOCGIWMODE - SIOCIWFIRST] = { 129 .header_type = IW_HEADER_TYPE_UINT, 130 .flags = IW_DESCR_FLAG_DUMP, 131 }, 132 [SIOCSIWSENS - SIOCIWFIRST] = { 133 .header_type = IW_HEADER_TYPE_PARAM, 134 }, 135 [SIOCGIWSENS - SIOCIWFIRST] = { 136 .header_type = IW_HEADER_TYPE_PARAM, 137 }, 138 [SIOCSIWRANGE - SIOCIWFIRST] = { 139 .header_type = IW_HEADER_TYPE_NULL, 140 }, 141 [SIOCGIWRANGE - SIOCIWFIRST] = { 142 .header_type = IW_HEADER_TYPE_POINT, 143 .token_size = 1, 144 .max_tokens = sizeof(struct iw_range), 145 .flags = IW_DESCR_FLAG_DUMP, 146 }, 147 [SIOCSIWPRIV - SIOCIWFIRST] = { 148 .header_type = IW_HEADER_TYPE_NULL, 149 }, 150 [SIOCGIWPRIV - SIOCIWFIRST] = { /* (handled directly by us) */ 151 .header_type = IW_HEADER_TYPE_NULL, 152 }, 153 [SIOCSIWSTATS - SIOCIWFIRST] = { 154 .header_type = IW_HEADER_TYPE_NULL, 155 }, 156 [SIOCGIWSTATS - SIOCIWFIRST] = { /* (handled directly by us) */ 157 .header_type = IW_HEADER_TYPE_NULL, 158 .flags = IW_DESCR_FLAG_DUMP, 159 }, 160 [SIOCSIWSPY - SIOCIWFIRST] = { 161 .header_type = IW_HEADER_TYPE_POINT, 162 .token_size = sizeof(struct sockaddr), 163 .max_tokens = IW_MAX_SPY, 164 }, 165 [SIOCGIWSPY - SIOCIWFIRST] = { 166 .header_type = IW_HEADER_TYPE_POINT, 167 .token_size = sizeof(struct sockaddr) + 168 sizeof(struct iw_quality), 169 .max_tokens = IW_MAX_SPY, 170 }, 171 [SIOCSIWTHRSPY - SIOCIWFIRST] = { 172 .header_type = IW_HEADER_TYPE_POINT, 173 .token_size = sizeof(struct iw_thrspy), 174 .min_tokens = 1, 175 .max_tokens = 1, 176 }, 177 [SIOCGIWTHRSPY - SIOCIWFIRST] = { 178 .header_type = IW_HEADER_TYPE_POINT, 179 .token_size = sizeof(struct iw_thrspy), 180 .min_tokens = 1, 181 .max_tokens = 1, 182 }, 183 [SIOCSIWAP - SIOCIWFIRST] = { 184 .header_type = IW_HEADER_TYPE_ADDR, 185 }, 186 [SIOCGIWAP - SIOCIWFIRST] = { 187 .header_type = IW_HEADER_TYPE_ADDR, 188 .flags = IW_DESCR_FLAG_DUMP, 189 }, 190 [SIOCSIWMLME - SIOCIWFIRST] = { 191 .header_type = IW_HEADER_TYPE_POINT, 192 .token_size = 1, 193 .min_tokens = sizeof(struct iw_mlme), 194 .max_tokens = sizeof(struct iw_mlme), 195 }, 196 [SIOCGIWAPLIST - SIOCIWFIRST] = { 197 .header_type = IW_HEADER_TYPE_POINT, 198 .token_size = sizeof(struct sockaddr) + 199 sizeof(struct iw_quality), 200 .max_tokens = IW_MAX_AP, 201 .flags = IW_DESCR_FLAG_NOMAX, 202 }, 203 [SIOCSIWSCAN - SIOCIWFIRST] = { 204 .header_type = IW_HEADER_TYPE_POINT, 205 .token_size = 1, 206 .min_tokens = 0, 207 .max_tokens = sizeof(struct iw_scan_req), 208 }, 209 [SIOCGIWSCAN - SIOCIWFIRST] = { 210 .header_type = IW_HEADER_TYPE_POINT, 211 .token_size = 1, 212 .max_tokens = IW_SCAN_MAX_DATA, 213 .flags = IW_DESCR_FLAG_NOMAX, 214 }, 215 [SIOCSIWESSID - SIOCIWFIRST] = { 216 .header_type = IW_HEADER_TYPE_POINT, 217 .token_size = 1, 218 .max_tokens = IW_ESSID_MAX_SIZE + 1, 219 .flags = IW_DESCR_FLAG_EVENT, 220 }, 221 [SIOCGIWESSID - SIOCIWFIRST] = { 222 .header_type = IW_HEADER_TYPE_POINT, 223 .token_size = 1, 224 .max_tokens = IW_ESSID_MAX_SIZE + 1, 225 .flags = IW_DESCR_FLAG_DUMP, 226 }, 227 [SIOCSIWNICKN - SIOCIWFIRST] = { 228 .header_type = IW_HEADER_TYPE_POINT, 229 .token_size = 1, 230 .max_tokens = IW_ESSID_MAX_SIZE + 1, 231 }, 232 [SIOCGIWNICKN - SIOCIWFIRST] = { 233 .header_type = IW_HEADER_TYPE_POINT, 234 .token_size = 1, 235 .max_tokens = IW_ESSID_MAX_SIZE + 1, 236 }, 237 [SIOCSIWRATE - SIOCIWFIRST] = { 238 .header_type = IW_HEADER_TYPE_PARAM, 239 }, 240 [SIOCGIWRATE - SIOCIWFIRST] = { 241 .header_type = IW_HEADER_TYPE_PARAM, 242 }, 243 [SIOCSIWRTS - SIOCIWFIRST] = { 244 .header_type = IW_HEADER_TYPE_PARAM, 245 }, 246 [SIOCGIWRTS - SIOCIWFIRST] = { 247 .header_type = IW_HEADER_TYPE_PARAM, 248 }, 249 [SIOCSIWFRAG - SIOCIWFIRST] = { 250 .header_type = IW_HEADER_TYPE_PARAM, 251 }, 252 [SIOCGIWFRAG - SIOCIWFIRST] = { 253 .header_type = IW_HEADER_TYPE_PARAM, 254 }, 255 [SIOCSIWTXPOW - SIOCIWFIRST] = { 256 .header_type = IW_HEADER_TYPE_PARAM, 257 }, 258 [SIOCGIWTXPOW - SIOCIWFIRST] = { 259 .header_type = IW_HEADER_TYPE_PARAM, 260 }, 261 [SIOCSIWRETRY - SIOCIWFIRST] = { 262 .header_type = IW_HEADER_TYPE_PARAM, 263 }, 264 [SIOCGIWRETRY - SIOCIWFIRST] = { 265 .header_type = IW_HEADER_TYPE_PARAM, 266 }, 267 [SIOCSIWENCODE - SIOCIWFIRST] = { 268 .header_type = IW_HEADER_TYPE_POINT, 269 .token_size = 1, 270 .max_tokens = IW_ENCODING_TOKEN_MAX, 271 .flags = IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT, 272 }, 273 [SIOCGIWENCODE - SIOCIWFIRST] = { 274 .header_type = IW_HEADER_TYPE_POINT, 275 .token_size = 1, 276 .max_tokens = IW_ENCODING_TOKEN_MAX, 277 .flags = IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT, 278 }, 279 [SIOCSIWPOWER - SIOCIWFIRST] = { 280 .header_type = IW_HEADER_TYPE_PARAM, 281 }, 282 [SIOCGIWPOWER - SIOCIWFIRST] = { 283 .header_type = IW_HEADER_TYPE_PARAM, 284 }, 285 [SIOCSIWGENIE - SIOCIWFIRST] = { 286 .header_type = IW_HEADER_TYPE_POINT, 287 .token_size = 1, 288 .max_tokens = IW_GENERIC_IE_MAX, 289 }, 290 [SIOCGIWGENIE - SIOCIWFIRST] = { 291 .header_type = IW_HEADER_TYPE_POINT, 292 .token_size = 1, 293 .max_tokens = IW_GENERIC_IE_MAX, 294 }, 295 [SIOCSIWAUTH - SIOCIWFIRST] = { 296 .header_type = IW_HEADER_TYPE_PARAM, 297 }, 298 [SIOCGIWAUTH - SIOCIWFIRST] = { 299 .header_type = IW_HEADER_TYPE_PARAM, 300 }, 301 [SIOCSIWENCODEEXT - SIOCIWFIRST] = { 302 .header_type = IW_HEADER_TYPE_POINT, 303 .token_size = 1, 304 .min_tokens = sizeof(struct iw_encode_ext), 305 .max_tokens = sizeof(struct iw_encode_ext) + 306 IW_ENCODING_TOKEN_MAX, 307 }, 308 [SIOCGIWENCODEEXT - SIOCIWFIRST] = { 309 .header_type = IW_HEADER_TYPE_POINT, 310 .token_size = 1, 311 .min_tokens = sizeof(struct iw_encode_ext), 312 .max_tokens = sizeof(struct iw_encode_ext) + 313 IW_ENCODING_TOKEN_MAX, 314 }, 315 [SIOCSIWPMKSA - SIOCIWFIRST] = { 316 .header_type = IW_HEADER_TYPE_POINT, 317 .token_size = 1, 318 .min_tokens = sizeof(struct iw_pmksa), 319 .max_tokens = sizeof(struct iw_pmksa), 320 }, 321}; 322static const int standard_ioctl_num = (sizeof(standard_ioctl) / 323 sizeof(struct iw_ioctl_description)); 324 325/* 326 * Meta-data about all the additional standard Wireless Extension events 327 * we know about. 328 */ 329static const struct iw_ioctl_description standard_event[] = { 330 [IWEVTXDROP - IWEVFIRST] = { 331 .header_type = IW_HEADER_TYPE_ADDR, 332 }, 333 [IWEVQUAL - IWEVFIRST] = { 334 .header_type = IW_HEADER_TYPE_QUAL, 335 }, 336 [IWEVCUSTOM - IWEVFIRST] = { 337 .header_type = IW_HEADER_TYPE_POINT, 338 .token_size = 1, 339 .max_tokens = IW_CUSTOM_MAX, 340 }, 341 [IWEVREGISTERED - IWEVFIRST] = { 342 .header_type = IW_HEADER_TYPE_ADDR, 343 }, 344 [IWEVEXPIRED - IWEVFIRST] = { 345 .header_type = IW_HEADER_TYPE_ADDR, 346 }, 347 [IWEVGENIE - IWEVFIRST] = { 348 .header_type = IW_HEADER_TYPE_POINT, 349 .token_size = 1, 350 .max_tokens = IW_GENERIC_IE_MAX, 351 }, 352 [IWEVMICHAELMICFAILURE - IWEVFIRST] = { 353 .header_type = IW_HEADER_TYPE_POINT, 354 .token_size = 1, 355 .max_tokens = sizeof(struct iw_michaelmicfailure), 356 }, 357 [IWEVASSOCREQIE - IWEVFIRST] = { 358 .header_type = IW_HEADER_TYPE_POINT, 359 .token_size = 1, 360 .max_tokens = IW_GENERIC_IE_MAX, 361 }, 362 [IWEVASSOCRESPIE - IWEVFIRST] = { 363 .header_type = IW_HEADER_TYPE_POINT, 364 .token_size = 1, 365 .max_tokens = IW_GENERIC_IE_MAX, 366 }, 367 [IWEVPMKIDCAND - IWEVFIRST] = { 368 .header_type = IW_HEADER_TYPE_POINT, 369 .token_size = 1, 370 .max_tokens = sizeof(struct iw_pmkid_cand), 371 }, 372}; 373static const int standard_event_num = (sizeof(standard_event) / 374 sizeof(struct iw_ioctl_description)); 375 376/* Size (in bytes) of the various private data types */ 377static const char iw_priv_type_size[] = { 378 0, /* IW_PRIV_TYPE_NONE */ 379 1, /* IW_PRIV_TYPE_BYTE */ 380 1, /* IW_PRIV_TYPE_CHAR */ 381 0, /* Not defined */ 382 sizeof(__u32), /* IW_PRIV_TYPE_INT */ 383 sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */ 384 sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */ 385 0, /* Not defined */ 386}; 387 388/* Size (in bytes) of various events */ 389static const int event_type_size[] = { 390 IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */ 391 0, 392 IW_EV_CHAR_LEN, /* IW_HEADER_TYPE_CHAR */ 393 0, 394 IW_EV_UINT_LEN, /* IW_HEADER_TYPE_UINT */ 395 IW_EV_FREQ_LEN, /* IW_HEADER_TYPE_FREQ */ 396 IW_EV_ADDR_LEN, /* IW_HEADER_TYPE_ADDR */ 397 0, 398 IW_EV_POINT_LEN, /* Without variable payload */ 399 IW_EV_PARAM_LEN, /* IW_HEADER_TYPE_PARAM */ 400 IW_EV_QUAL_LEN, /* IW_HEADER_TYPE_QUAL */ 401}; 402 403/************************ COMMON SUBROUTINES ************************/ 404/* 405 * Stuff that may be used in various place or doesn't fit in one 406 * of the section below. 407 */ 408 409/* ---------------------------------------------------------------- */ 410/* 411 * Return the driver handler associated with a specific Wireless Extension. 412 * Called from various place, so make sure it remains efficient. 413 */ 414static inline iw_handler get_handler(struct net_device *dev, 415 unsigned int cmd) 416{ 417 /* Don't "optimise" the following variable, it will crash */ 418 unsigned int index; /* *MUST* be unsigned */ 419 420 /* Check if we have some wireless handlers defined */ 421 if(dev->wireless_handlers == NULL) 422 return NULL; 423 424 /* Try as a standard command */ 425 index = cmd - SIOCIWFIRST; 426 if(index < dev->wireless_handlers->num_standard) 427 return dev->wireless_handlers->standard[index]; 428 429 /* Try as a private command */ 430 index = cmd - SIOCIWFIRSTPRIV; 431 if(index < dev->wireless_handlers->num_private) 432 return dev->wireless_handlers->private[index]; 433 434 /* Not found */ 435 return NULL; 436} 437 438/* ---------------------------------------------------------------- */ 439/* 440 * Get statistics out of the driver 441 */ 442static inline struct iw_statistics *get_wireless_stats(struct net_device *dev) 443{ 444 /* New location */ 445 if((dev->wireless_handlers != NULL) && 446 (dev->wireless_handlers->get_wireless_stats != NULL)) 447 return dev->wireless_handlers->get_wireless_stats(dev); 448 449 /* Old location, will be phased out in next WE */ 450 return (dev->get_wireless_stats ? 451 dev->get_wireless_stats(dev) : 452 (struct iw_statistics *) NULL); 453} 454 455/* ---------------------------------------------------------------- */ 456/* 457 * Call the commit handler in the driver 458 * (if exist and if conditions are right) 459 * 460 * Note : our current commit strategy is currently pretty dumb, 461 * but we will be able to improve on that... 462 * The goal is to try to agreagate as many changes as possible 463 * before doing the commit. Drivers that will define a commit handler 464 * are usually those that need a reset after changing parameters, so 465 * we want to minimise the number of reset. 466 * A cool idea is to use a timer : at each "set" command, we re-set the 467 * timer, when the timer eventually fires, we call the driver. 468 * Hopefully, more on that later. 469 * 470 * Also, I'm waiting to see how many people will complain about the 471 * netif_running(dev) test. I'm open on that one... 472 * Hopefully, the driver will remember to do a commit in "open()" ;-) 473 */ 474static inline int call_commit_handler(struct net_device * dev) 475{ 476 if((netif_running(dev)) && 477 (dev->wireless_handlers->standard[0] != NULL)) { 478 /* Call the commit handler on the driver */ 479 return dev->wireless_handlers->standard[0](dev, NULL, 480 NULL, NULL); 481 } else 482 return 0; /* Command completed successfully */ 483} 484 485/* ---------------------------------------------------------------- */ 486/* 487 * Calculate size of private arguments 488 */ 489static inline int get_priv_size(__u16 args) 490{ 491 int num = args & IW_PRIV_SIZE_MASK; 492 int type = (args & IW_PRIV_TYPE_MASK) >> 12; 493 494 return num * iw_priv_type_size[type]; 495} 496 497/* ---------------------------------------------------------------- */ 498/* 499 * Re-calculate the size of private arguments 500 */ 501static inline int adjust_priv_size(__u16 args, 502 union iwreq_data * wrqu) 503{ 504 int num = wrqu->data.length; 505 int max = args & IW_PRIV_SIZE_MASK; 506 int type = (args & IW_PRIV_TYPE_MASK) >> 12; 507 508 /* Make sure the driver doesn't goof up */ 509 if (max < num) 510 num = max; 511 512 return num * iw_priv_type_size[type]; 513} 514 515 516/******************** /proc/net/wireless SUPPORT ********************/ 517/* 518 * The /proc/net/wireless file is a human readable user-space interface 519 * exporting various wireless specific statistics from the wireless devices. 520 * This is the most popular part of the Wireless Extensions ;-) 521 * 522 * This interface is a pure clone of /proc/net/dev (in net/core/dev.c). 523 * The content of the file is basically the content of "struct iw_statistics". 524 */ 525 526#ifdef CONFIG_PROC_FS 527 528/* ---------------------------------------------------------------- */ 529/* 530 * Print one entry (line) of /proc/net/wireless 531 */ 532static __inline__ void wireless_seq_printf_stats(struct seq_file *seq, 533 struct net_device *dev) 534{ 535 /* Get stats from the driver */ 536 struct iw_statistics *stats = get_wireless_stats(dev); 537 538 if (stats) { 539 seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " 540 "%6d %6d %6d\n", 541 dev->name, stats->status, stats->qual.qual, 542 stats->qual.updated & IW_QUAL_QUAL_UPDATED 543 ? '.' : ' ', 544 ((__u8) stats->qual.level), 545 stats->qual.updated & IW_QUAL_LEVEL_UPDATED 546 ? '.' : ' ', 547 ((__u8) stats->qual.noise), 548 stats->qual.updated & IW_QUAL_NOISE_UPDATED 549 ? '.' : ' ', 550 stats->discard.nwid, stats->discard.code, 551 stats->discard.fragment, stats->discard.retries, 552 stats->discard.misc, stats->miss.beacon); 553 stats->qual.updated = 0; 554 } 555} 556 557/* ---------------------------------------------------------------- */ 558/* 559 * Print info for /proc/net/wireless (print all entries) 560 */ 561static int wireless_seq_show(struct seq_file *seq, void *v) 562{ 563 if (v == SEQ_START_TOKEN) 564 seq_printf(seq, "Inter-| sta-| Quality | Discarded " 565 "packets | Missed | WE\n" 566 " face | tus | link level noise | nwid " 567 "crypt frag retry misc | beacon | %d\n", 568 WIRELESS_EXT); 569 else 570 wireless_seq_printf_stats(seq, v); 571 return 0; 572} 573 574extern void *dev_seq_start(struct seq_file *seq, loff_t *pos); 575extern void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos); 576extern void dev_seq_stop(struct seq_file *seq, void *v); 577 578static struct seq_operations wireless_seq_ops = { 579 .start = dev_seq_start, 580 .next = dev_seq_next, 581 .stop = dev_seq_stop, 582 .show = wireless_seq_show, 583}; 584 585static int wireless_seq_open(struct inode *inode, struct file *file) 586{ 587 return seq_open(file, &wireless_seq_ops); 588} 589 590static struct file_operations wireless_seq_fops = { 591 .owner = THIS_MODULE, 592 .open = wireless_seq_open, 593 .read = seq_read, 594 .llseek = seq_lseek, 595 .release = seq_release, 596}; 597 598int __init wireless_proc_init(void) 599{ 600 if (!proc_net_fops_create("wireless", S_IRUGO, &wireless_seq_fops)) 601 return -ENOMEM; 602 603 return 0; 604} 605#endif /* CONFIG_PROC_FS */ 606 607/************************** IOCTL SUPPORT **************************/ 608/* 609 * The original user space API to configure all those Wireless Extensions 610 * is through IOCTLs. 611 * In there, we check if we need to call the new driver API (iw_handler) 612 * or just call the driver ioctl handler. 613 */ 614 615/* ---------------------------------------------------------------- */ 616/* 617 * Allow programatic access to /proc/net/wireless even if /proc 618 * doesn't exist... Also more efficient... 619 */ 620static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) 621{ 622 /* Get stats from the driver */ 623 struct iw_statistics *stats; 624 625 stats = get_wireless_stats(dev); 626 if (stats != (struct iw_statistics *) NULL) { 627 struct iwreq * wrq = (struct iwreq *)ifr; 628 629 /* Copy statistics to the user buffer */ 630 if(copy_to_user(wrq->u.data.pointer, stats, 631 sizeof(struct iw_statistics))) 632 return -EFAULT; 633 634 /* Check if we need to clear the update flag */ 635 if(wrq->u.data.flags != 0) 636 stats->qual.updated = 0; 637 return 0; 638 } else 639 return -EOPNOTSUPP; 640} 641 642/* ---------------------------------------------------------------- */ 643/* 644 * Export the driver private handler definition 645 * They will be picked up by tools like iwpriv... 646 */ 647static inline int ioctl_export_private(struct net_device * dev, 648 struct ifreq * ifr) 649{ 650 struct iwreq * iwr = (struct iwreq *) ifr; 651 652 /* Check if the driver has something to export */ 653 if((dev->wireless_handlers->num_private_args == 0) || 654 (dev->wireless_handlers->private_args == NULL)) 655 return -EOPNOTSUPP; 656 657 /* Check NULL pointer */ 658 if(iwr->u.data.pointer == NULL) 659 return -EFAULT; 660 661 /* Check if there is enough buffer up there */ 662 if(iwr->u.data.length < dev->wireless_handlers->num_private_args) { 663 /* User space can't know in advance how large the buffer 664 * needs to be. Give it a hint, so that we can support 665 * any size buffer we want somewhat efficiently... */ 666 iwr->u.data.length = dev->wireless_handlers->num_private_args; 667 return -E2BIG; 668 } 669 670 /* Set the number of available ioctls. */ 671 iwr->u.data.length = dev->wireless_handlers->num_private_args; 672 673 /* Copy structure to the user buffer. */ 674 if (copy_to_user(iwr->u.data.pointer, 675 dev->wireless_handlers->private_args, 676 sizeof(struct iw_priv_args) * iwr->u.data.length)) 677 return -EFAULT; 678 679 return 0; 680} 681 682/* ---------------------------------------------------------------- */ 683/* 684 * Wrapper to call a standard Wireless Extension handler. 685 * We do various checks and also take care of moving data between 686 * user space and kernel space. 687 */ 688static inline int ioctl_standard_call(struct net_device * dev, 689 struct ifreq * ifr, 690 unsigned int cmd, 691 iw_handler handler) 692{ 693 struct iwreq * iwr = (struct iwreq *) ifr; 694 const struct iw_ioctl_description * descr; 695 struct iw_request_info info; 696 int ret = -EINVAL; 697 698 /* Get the description of the IOCTL */ 699 if((cmd - SIOCIWFIRST) >= standard_ioctl_num) 700 return -EOPNOTSUPP; 701 descr = &(standard_ioctl[cmd - SIOCIWFIRST]); 702 703#ifdef WE_IOCTL_DEBUG 704 printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n", 705 ifr->ifr_name, cmd); 706 printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); 707#endif /* WE_IOCTL_DEBUG */ 708 709 /* Prepare the call */ 710 info.cmd = cmd; 711 info.flags = 0; 712 713 /* Check if we have a pointer to user space data or not */ 714 if(descr->header_type != IW_HEADER_TYPE_POINT) { 715 716 /* No extra arguments. Trivial to handle */ 717 ret = handler(dev, &info, &(iwr->u), NULL); 718 719#ifdef WE_SET_EVENT 720 /* Generate an event to notify listeners of the change */ 721 if((descr->flags & IW_DESCR_FLAG_EVENT) && 722 ((ret == 0) || (ret == -EIWCOMMIT))) 723 wireless_send_event(dev, cmd, &(iwr->u), NULL); 724#endif /* WE_SET_EVENT */ 725 } else { 726 char * extra; 727 int extra_size; 728 int user_length = 0; 729 int err; 730 731 /* Calculate space needed by arguments. Always allocate 732 * for max space. Easier, and won't last long... */ 733 extra_size = descr->max_tokens * descr->token_size; 734 735 /* Check what user space is giving us */ 736 if(IW_IS_SET(cmd)) { 737 /* Check NULL pointer */ 738 if((iwr->u.data.pointer == NULL) && 739 (iwr->u.data.length != 0)) 740 return -EFAULT; 741 /* Check if number of token fits within bounds */ 742 if(iwr->u.data.length > descr->max_tokens) 743 return -E2BIG; 744 if(iwr->u.data.length < descr->min_tokens) 745 return -EINVAL; 746 } else { 747 /* Check NULL pointer */ 748 if(iwr->u.data.pointer == NULL) 749 return -EFAULT; 750 /* Save user space buffer size for checking */ 751 user_length = iwr->u.data.length; 752 753 /* Don't check if user_length > max to allow forward 754 * compatibility. The test user_length < min is 755 * implied by the test at the end. */ 756 757 /* Support for very large requests */ 758 if((descr->flags & IW_DESCR_FLAG_NOMAX) && 759 (user_length > descr->max_tokens)) { 760 /* Allow userspace to GET more than max so 761 * we can support any size GET requests. 762 * There is still a limit : -ENOMEM. */ 763 extra_size = user_length * descr->token_size; 764 /* Note : user_length is originally a __u16, 765 * and token_size is controlled by us, 766 * so extra_size won't get negative and 767 * won't overflow... */ 768 } 769 } 770 771#ifdef WE_IOCTL_DEBUG 772 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", 773 dev->name, extra_size); 774#endif /* WE_IOCTL_DEBUG */ 775 776 /* Create the kernel buffer */ 777 extra = kmalloc(extra_size, GFP_KERNEL); 778 if (extra == NULL) { 779 return -ENOMEM; 780 } 781 782 /* If it is a SET, get all the extra data in here */ 783 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { 784 err = copy_from_user(extra, iwr->u.data.pointer, 785 iwr->u.data.length * 786 descr->token_size); 787 if (err) { 788 kfree(extra); 789 return -EFAULT; 790 } 791#ifdef WE_IOCTL_DEBUG 792 printk(KERN_DEBUG "%s (WE) : Got %d bytes\n", 793 dev->name, 794 iwr->u.data.length * descr->token_size); 795#endif /* WE_IOCTL_DEBUG */ 796 } 797 798 /* Call the handler */ 799 ret = handler(dev, &info, &(iwr->u), extra); 800 801 /* If we have something to return to the user */ 802 if (!ret && IW_IS_GET(cmd)) { 803 /* Check if there is enough buffer up there */ 804 if(user_length < iwr->u.data.length) { 805 kfree(extra); 806 return -E2BIG; 807 } 808 809 err = copy_to_user(iwr->u.data.pointer, extra, 810 iwr->u.data.length * 811 descr->token_size); 812 if (err) 813 ret = -EFAULT; 814#ifdef WE_IOCTL_DEBUG 815 printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n", 816 dev->name, 817 iwr->u.data.length * descr->token_size); 818#endif /* WE_IOCTL_DEBUG */ 819 } 820 821#ifdef WE_SET_EVENT 822 /* Generate an event to notify listeners of the change */ 823 if((descr->flags & IW_DESCR_FLAG_EVENT) && 824 ((ret == 0) || (ret == -EIWCOMMIT))) { 825 if(descr->flags & IW_DESCR_FLAG_RESTRICT) 826 /* If the event is restricted, don't 827 * export the payload */ 828 wireless_send_event(dev, cmd, &(iwr->u), NULL); 829 else 830 wireless_send_event(dev, cmd, &(iwr->u), 831 extra); 832 } 833#endif /* WE_SET_EVENT */ 834 835 /* Cleanup - I told you it wasn't that long ;-) */ 836 kfree(extra); 837 } 838 839 /* Call commit handler if needed and defined */ 840 if(ret == -EIWCOMMIT) 841 ret = call_commit_handler(dev); 842 843 /* Here, we will generate the appropriate event if needed */ 844 845 return ret; 846} 847 848/* ---------------------------------------------------------------- */ 849/* 850 * Wrapper to call a private Wireless Extension handler. 851 * We do various checks and also take care of moving data between 852 * user space and kernel space. 853 * It's not as nice and slimline as the standard wrapper. The cause 854 * is struct iw_priv_args, which was not really designed for the 855 * job we are going here. 856 * 857 * IMPORTANT : This function prevent to set and get data on the same 858 * IOCTL and enforce the SET/GET convention. Not doing it would be 859 * far too hairy... 860 * If you need to set and get data at the same time, please don't use 861 * a iw_handler but process it in your ioctl handler (i.e. use the 862 * old driver API). 863 */ 864static inline int ioctl_private_call(struct net_device * dev, 865 struct ifreq * ifr, 866 unsigned int cmd, 867 iw_handler handler) 868{ 869 struct iwreq * iwr = (struct iwreq *) ifr; 870 const struct iw_priv_args * descr = NULL; 871 struct iw_request_info info; 872 int extra_size = 0; 873 int i; 874 int ret = -EINVAL; 875 876 /* Get the description of the IOCTL */ 877 for(i = 0; i < dev->wireless_handlers->num_private_args; i++) 878 if(cmd == dev->wireless_handlers->private_args[i].cmd) { 879 descr = &(dev->wireless_handlers->private_args[i]); 880 break; 881 } 882 883#ifdef WE_IOCTL_DEBUG 884 printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n", 885 ifr->ifr_name, cmd); 886 if(descr) { 887 printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n", 888 dev->name, descr->name, 889 descr->set_args, descr->get_args); 890 } 891#endif /* WE_IOCTL_DEBUG */ 892 893 /* Compute the size of the set/get arguments */ 894 if(descr != NULL) { 895 if(IW_IS_SET(cmd)) { 896 int offset = 0; /* For sub-ioctls */ 897 /* Check for sub-ioctl handler */ 898 if(descr->name[0] == '\0') 899 /* Reserve one int for sub-ioctl index */ 900 offset = sizeof(__u32); 901 902 /* Size of set arguments */ 903 extra_size = get_priv_size(descr->set_args); 904 905 /* Does it fits in iwr ? */ 906 if((descr->set_args & IW_PRIV_SIZE_FIXED) && 907 ((extra_size + offset) <= IFNAMSIZ)) 908 extra_size = 0; 909 } else { 910 /* Size of get arguments */ 911 extra_size = get_priv_size(descr->get_args); 912 913 /* Does it fits in iwr ? */ 914 if((descr->get_args & IW_PRIV_SIZE_FIXED) && 915 (extra_size <= IFNAMSIZ)) 916 extra_size = 0; 917 } 918 } 919 920 /* Prepare the call */ 921 info.cmd = cmd; 922 info.flags = 0; 923 924 /* Check if we have a pointer to user space data or not. */ 925 if(extra_size == 0) { 926 /* No extra arguments. Trivial to handle */ 927 ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u)); 928 } else { 929 char * extra; 930 int err; 931 932 /* Check what user space is giving us */ 933 if(IW_IS_SET(cmd)) { 934 /* Check NULL pointer */ 935 if((iwr->u.data.pointer == NULL) && 936 (iwr->u.data.length != 0)) 937 return -EFAULT; 938 939 /* Does it fits within bounds ? */ 940 if(iwr->u.data.length > (descr->set_args & 941 IW_PRIV_SIZE_MASK)) 942 return -E2BIG; 943 } else { 944 /* Check NULL pointer */ 945 if(iwr->u.data.pointer == NULL) 946 return -EFAULT; 947 } 948 949#ifdef WE_IOCTL_DEBUG 950 printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n", 951 dev->name, extra_size); 952#endif /* WE_IOCTL_DEBUG */ 953 954 /* Always allocate for max space. Easier, and won't last 955 * long... */ 956 extra = kmalloc(extra_size, GFP_KERNEL); 957 if (extra == NULL) { 958 return -ENOMEM; 959 } 960 961 /* If it is a SET, get all the extra data in here */ 962 if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) { 963 err = copy_from_user(extra, iwr->u.data.pointer, 964 extra_size); 965 if (err) { 966 kfree(extra); 967 return -EFAULT; 968 } 969#ifdef WE_IOCTL_DEBUG 970 printk(KERN_DEBUG "%s (WE) : Got %d elem\n", 971 dev->name, iwr->u.data.length); 972#endif /* WE_IOCTL_DEBUG */ 973 } 974 975 /* Call the handler */ 976 ret = handler(dev, &info, &(iwr->u), extra); 977 978 /* If we have something to return to the user */ 979 if (!ret && IW_IS_GET(cmd)) { 980 981 /* Adjust for the actual length if it's variable, 982 * avoid leaking kernel bits outside. */ 983 if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) { 984 extra_size = adjust_priv_size(descr->get_args, 985 &(iwr->u)); 986 } 987 988 err = copy_to_user(iwr->u.data.pointer, extra, 989 extra_size); 990 if (err) 991 ret = -EFAULT; 992#ifdef WE_IOCTL_DEBUG 993 printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n", 994 dev->name, iwr->u.data.length); 995#endif /* WE_IOCTL_DEBUG */ 996 } 997 998 /* Cleanup - I told you it wasn't that long ;-) */ 999 kfree(extra); 1000 } 1001 1002 1003 /* Call commit handler if needed and defined */ 1004 if(ret == -EIWCOMMIT) 1005 ret = call_commit_handler(dev); 1006 1007 return ret; 1008} 1009 1010/* ---------------------------------------------------------------- */ 1011/* 1012 * Main IOCTl dispatcher. Called from the main networking code 1013 * (dev_ioctl() in net/core/dev.c). 1014 * Check the type of IOCTL and call the appropriate wrapper... 1015 */ 1016int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd) 1017{ 1018 struct net_device *dev; 1019 iw_handler handler; 1020 1021 /* Permissions are already checked in dev_ioctl() before calling us. 1022 * The copy_to/from_user() of ifr is also dealt with in there */ 1023 1024 /* Make sure the device exist */ 1025 if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) 1026 return -ENODEV; 1027 1028 /* A bunch of special cases, then the generic case... 1029 * Note that 'cmd' is already filtered in dev_ioctl() with 1030 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */ 1031 switch(cmd) 1032 { 1033 case SIOCGIWSTATS: 1034 /* Get Wireless Stats */ 1035 return dev_iwstats(dev, ifr); 1036 1037 case SIOCGIWPRIV: 1038 /* Check if we have some wireless handlers defined */ 1039 if(dev->wireless_handlers != NULL) { 1040 /* We export to user space the definition of 1041 * the private handler ourselves */ 1042 return ioctl_export_private(dev, ifr); 1043 } 1044 // ## Fall-through for old API ## 1045 default: 1046 /* Generic IOCTL */ 1047 /* Basic check */ 1048 if (!netif_device_present(dev)) 1049 return -ENODEV; 1050 /* New driver API : try to find the handler */ 1051 handler = get_handler(dev, cmd); 1052 if(handler != NULL) { 1053 /* Standard and private are not the same */ 1054 if(cmd < SIOCIWFIRSTPRIV) 1055 return ioctl_standard_call(dev, 1056 ifr, 1057 cmd, 1058 handler); 1059 else 1060 return ioctl_private_call(dev, 1061 ifr, 1062 cmd, 1063 handler); 1064 } 1065 /* Old driver API : call driver ioctl handler */ 1066 if (dev->do_ioctl) { 1067 return dev->do_ioctl(dev, ifr, cmd); 1068 } 1069 return -EOPNOTSUPP; 1070 } 1071 /* Not reached */ 1072 return -EINVAL; 1073} 1074 1075/************************* EVENT PROCESSING *************************/ 1076/* 1077 * Process events generated by the wireless layer or the driver. 1078 * Most often, the event will be propagated through rtnetlink 1079 */ 1080 1081#ifdef WE_EVENT_NETLINK 1082/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here. 1083 * It is declared in <linux/rtnetlink.h> */ 1084 1085/* ---------------------------------------------------------------- */ 1086/* 1087 * Fill a rtnetlink message with our event data. 1088 * Note that we propage only the specified event and don't dump the 1089 * current wireless config. Dumping the wireless config is far too 1090 * expensive (for each parameter, the driver need to query the hardware). 1091 */ 1092static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb, 1093 struct net_device * dev, 1094 int type, 1095 char * event, 1096 int event_len) 1097{ 1098 struct ifinfomsg *r; 1099 struct nlmsghdr *nlh; 1100 unsigned char *b = skb->tail; 1101 1102 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r)); 1103 r = NLMSG_DATA(nlh); 1104 r->ifi_family = AF_UNSPEC; 1105 r->__ifi_pad = 0; 1106 r->ifi_type = dev->type; 1107 r->ifi_index = dev->ifindex; 1108 r->ifi_flags = dev->flags; 1109 r->ifi_change = 0; /* Wireless changes don't affect those flags */ 1110 1111 /* Add the wireless events in the netlink packet */ 1112 RTA_PUT(skb, IFLA_WIRELESS, 1113 event_len, event); 1114 1115 nlh->nlmsg_len = skb->tail - b; 1116 return skb->len; 1117 1118nlmsg_failure: 1119rtattr_failure: 1120 skb_trim(skb, b - skb->data); 1121 return -1; 1122} 1123 1124/* ---------------------------------------------------------------- */ 1125/* 1126 * Create and broadcast and send it on the standard rtnetlink socket 1127 * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c 1128 * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field 1129 * within a RTM_NEWLINK event. 1130 */ 1131static inline void rtmsg_iwinfo(struct net_device * dev, 1132 char * event, 1133 int event_len) 1134{ 1135 struct sk_buff *skb; 1136 int size = NLMSG_GOODSIZE; 1137 1138 skb = alloc_skb(size, GFP_ATOMIC); 1139 if (!skb) 1140 return; 1141 1142 if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK, 1143 event, event_len) < 0) { 1144 kfree_skb(skb); 1145 return; 1146 } 1147 NETLINK_CB(skb).dst_groups = RTMGRP_LINK; 1148 netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC); 1149} 1150#endif /* WE_EVENT_NETLINK */ 1151 1152/* ---------------------------------------------------------------- */ 1153/* 1154 * Main event dispatcher. Called from other parts and drivers. 1155 * Send the event on the appropriate channels. 1156 * May be called from interrupt context. 1157 */ 1158void wireless_send_event(struct net_device * dev, 1159 unsigned int cmd, 1160 union iwreq_data * wrqu, 1161 char * extra) 1162{ 1163 const struct iw_ioctl_description * descr = NULL; 1164 int extra_len = 0; 1165 struct iw_event *event; /* Mallocated whole event */ 1166 int event_len; /* Its size */ 1167 int hdr_len; /* Size of the event header */ 1168 /* Don't "optimise" the following variable, it will crash */ 1169 unsigned cmd_index; /* *MUST* be unsigned */ 1170 1171 /* Get the description of the IOCTL */ 1172 if(cmd <= SIOCIWLAST) { 1173 cmd_index = cmd - SIOCIWFIRST; 1174 if(cmd_index < standard_ioctl_num) 1175 descr = &(standard_ioctl[cmd_index]); 1176 } else { 1177 cmd_index = cmd - IWEVFIRST; 1178 if(cmd_index < standard_event_num) 1179 descr = &(standard_event[cmd_index]); 1180 } 1181 /* Don't accept unknown events */ 1182 if(descr == NULL) { 1183 /* Note : we don't return an error to the driver, because 1184 * the driver would not know what to do about it. It can't 1185 * return an error to the user, because the event is not 1186 * initiated by a user request. 1187 * The best the driver could do is to log an error message. 1188 * We will do it ourselves instead... 1189 */ 1190 printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n", 1191 dev->name, cmd); 1192 return; 1193 } 1194#ifdef WE_EVENT_DEBUG 1195 printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n", 1196 dev->name, cmd); 1197 printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens); 1198#endif /* WE_EVENT_DEBUG */ 1199 1200 /* Check extra parameters and set extra_len */ 1201 if(descr->header_type == IW_HEADER_TYPE_POINT) { 1202 /* Check if number of token fits within bounds */ 1203 if(wrqu->data.length > descr->max_tokens) { 1204 printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length); 1205 return; 1206 } 1207 if(wrqu->data.length < descr->min_tokens) { 1208 printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length); 1209 return; 1210 } 1211 /* Calculate extra_len - extra is NULL for restricted events */ 1212 if(extra != NULL) 1213 extra_len = wrqu->data.length * descr->token_size; 1214#ifdef WE_EVENT_DEBUG 1215 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len); 1216#endif /* WE_EVENT_DEBUG */ 1217 } 1218 1219 /* Total length of the event */ 1220 hdr_len = event_type_size[descr->header_type]; 1221 event_len = hdr_len + extra_len; 1222 1223#ifdef WE_EVENT_DEBUG 1224 printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len); 1225#endif /* WE_EVENT_DEBUG */ 1226 1227 /* Create temporary buffer to hold the event */ 1228 event = kmalloc(event_len, GFP_ATOMIC); 1229 if(event == NULL) 1230 return; 1231 1232 /* Fill event */ 1233 event->len = event_len; 1234 event->cmd = cmd; 1235 memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN); 1236 if(extra != NULL) 1237 memcpy(((char *) event) + hdr_len, extra, extra_len); 1238 1239#ifdef WE_EVENT_NETLINK 1240 /* rtnetlink event channel */ 1241 rtmsg_iwinfo(dev, (char *) event, event_len); 1242#endif /* WE_EVENT_NETLINK */ 1243 1244 /* Cleanup */ 1245 kfree(event); 1246 1247 return; /* Always success, I guess ;-) */ 1248} 1249 1250/********************** ENHANCED IWSPY SUPPORT **********************/ 1251/* 1252 * In the old days, the driver was handling spy support all by itself. 1253 * Now, the driver can delegate this task to Wireless Extensions. 1254 * It needs to use those standard spy iw_handler in struct iw_handler_def, 1255 * push data to us via wireless_spy_update() and include struct iw_spy_data 1256 * in its private part (and advertise it in iw_handler_def->spy_offset). 1257 * One of the main advantage of centralising spy support here is that 1258 * it becomes much easier to improve and extend it without having to touch 1259 * the drivers. One example is the addition of the Spy-Threshold events. 1260 */ 1261 1262/* ---------------------------------------------------------------- */ 1263/* 1264 * Return the pointer to the spy data in the driver. 1265 * Because this is called on the Rx path via wireless_spy_update(), 1266 * we want it to be efficient... 1267 */ 1268static inline struct iw_spy_data * get_spydata(struct net_device *dev) 1269{ 1270 /* This is the new way */ 1271 if(dev->wireless_data) 1272 return(dev->wireless_data->spy_data); 1273 1274 /* This is the old way. Doesn't work for multi-headed drivers. 1275 * It will be removed in the next version of WE. */ 1276 return (dev->priv + dev->wireless_handlers->spy_offset); 1277} 1278 1279/*------------------------------------------------------------------*/ 1280/* 1281 * Standard Wireless Handler : set Spy List 1282 */ 1283int iw_handler_set_spy(struct net_device * dev, 1284 struct iw_request_info * info, 1285 union iwreq_data * wrqu, 1286 char * extra) 1287{ 1288 struct iw_spy_data * spydata = get_spydata(dev); 1289 struct sockaddr * address = (struct sockaddr *) extra; 1290 1291 if(!dev->wireless_data) 1292 /* Help user know that driver needs updating */ 1293 printk(KERN_DEBUG "%s (WE) : Driver using old/buggy spy support, please fix driver !\n", 1294 dev->name); 1295 /* Make sure driver is not buggy or using the old API */ 1296 if(!spydata) 1297 return -EOPNOTSUPP; 1298 1299 /* Disable spy collection while we copy the addresses. 1300 * While we copy addresses, any call to wireless_spy_update() 1301 * will NOP. This is OK, as anyway the addresses are changing. */ 1302 spydata->spy_number = 0; 1303 1304 /* We want to operate without locking, because wireless_spy_update() 1305 * most likely will happen in the interrupt handler, and therefore 1306 * have its own locking constraints and needs performance. 1307 * The rtnl_lock() make sure we don't race with the other iw_handlers. 1308 * This make sure wireless_spy_update() "see" that the spy list 1309 * is temporarily disabled. */ 1310 wmb(); 1311 1312 /* Are there are addresses to copy? */ 1313 if(wrqu->data.length > 0) { 1314 int i; 1315 1316 /* Copy addresses */ 1317 for(i = 0; i < wrqu->data.length; i++) 1318 memcpy(spydata->spy_address[i], address[i].sa_data, 1319 ETH_ALEN); 1320 /* Reset stats */ 1321 memset(spydata->spy_stat, 0, 1322 sizeof(struct iw_quality) * IW_MAX_SPY); 1323 1324#ifdef WE_SPY_DEBUG 1325 printk(KERN_DEBUG "iw_handler_set_spy() : offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length); 1326 for (i = 0; i < wrqu->data.length; i++) 1327 printk(KERN_DEBUG 1328 "%02X:%02X:%02X:%02X:%02X:%02X \n", 1329 spydata->spy_address[i][0], 1330 spydata->spy_address[i][1], 1331 spydata->spy_address[i][2], 1332 spydata->spy_address[i][3], 1333 spydata->spy_address[i][4], 1334 spydata->spy_address[i][5]); 1335#endif /* WE_SPY_DEBUG */ 1336 } 1337 1338 /* Make sure above is updated before re-enabling */ 1339 wmb(); 1340 1341 /* Enable addresses */ 1342 spydata->spy_number = wrqu->data.length; 1343 1344 return 0; 1345} 1346 1347/*------------------------------------------------------------------*/ 1348/* 1349 * Standard Wireless Handler : get Spy List 1350 */ 1351int iw_handler_get_spy(struct net_device * dev, 1352 struct iw_request_info * info, 1353 union iwreq_data * wrqu, 1354 char * extra) 1355{ 1356 struct iw_spy_data * spydata = get_spydata(dev); 1357 struct sockaddr * address = (struct sockaddr *) extra; 1358 int i; 1359 1360 /* Make sure driver is not buggy or using the old API */ 1361 if(!spydata) 1362 return -EOPNOTSUPP; 1363 1364 wrqu->data.length = spydata->spy_number; 1365 1366 /* Copy addresses. */ 1367 for(i = 0; i < spydata->spy_number; i++) { 1368 memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN); 1369 address[i].sa_family = AF_UNIX; 1370 } 1371 /* Copy stats to the user buffer (just after). */ 1372 if(spydata->spy_number > 0) 1373 memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number), 1374 spydata->spy_stat, 1375 sizeof(struct iw_quality) * spydata->spy_number); 1376 /* Reset updated flags. */ 1377 for(i = 0; i < spydata->spy_number; i++) 1378 spydata->spy_stat[i].updated = 0; 1379 return 0; 1380} 1381 1382/*------------------------------------------------------------------*/ 1383/* 1384 * Standard Wireless Handler : set spy threshold 1385 */ 1386int iw_handler_set_thrspy(struct net_device * dev, 1387 struct iw_request_info *info, 1388 union iwreq_data * wrqu, 1389 char * extra) 1390{ 1391 struct iw_spy_data * spydata = get_spydata(dev); 1392 struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 1393 1394 /* Make sure driver is not buggy or using the old API */ 1395 if(!spydata) 1396 return -EOPNOTSUPP; 1397 1398 /* Just do it */ 1399 memcpy(&(spydata->spy_thr_low), &(threshold->low), 1400 2 * sizeof(struct iw_quality)); 1401 1402 /* Clear flag */ 1403 memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under)); 1404 1405#ifdef WE_SPY_DEBUG 1406 printk(KERN_DEBUG "iw_handler_set_thrspy() : low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level); 1407#endif /* WE_SPY_DEBUG */ 1408 1409 return 0; 1410} 1411 1412/*------------------------------------------------------------------*/ 1413/* 1414 * Standard Wireless Handler : get spy threshold 1415 */ 1416int iw_handler_get_thrspy(struct net_device * dev, 1417 struct iw_request_info *info, 1418 union iwreq_data * wrqu, 1419 char * extra) 1420{ 1421 struct iw_spy_data * spydata = get_spydata(dev); 1422 struct iw_thrspy * threshold = (struct iw_thrspy *) extra; 1423 1424 /* Make sure driver is not buggy or using the old API */ 1425 if(!spydata) 1426 return -EOPNOTSUPP; 1427 1428 /* Just do it */ 1429 memcpy(&(threshold->low), &(spydata->spy_thr_low), 1430 2 * sizeof(struct iw_quality)); 1431 1432 return 0; 1433} 1434 1435/*------------------------------------------------------------------*/ 1436/* 1437 * Prepare and send a Spy Threshold event 1438 */ 1439static void iw_send_thrspy_event(struct net_device * dev, 1440 struct iw_spy_data * spydata, 1441 unsigned char * address, 1442 struct iw_quality * wstats) 1443{ 1444 union iwreq_data wrqu; 1445 struct iw_thrspy threshold; 1446 1447 /* Init */ 1448 wrqu.data.length = 1; 1449 wrqu.data.flags = 0; 1450 /* Copy address */ 1451 memcpy(threshold.addr.sa_data, address, ETH_ALEN); 1452 threshold.addr.sa_family = ARPHRD_ETHER; 1453 /* Copy stats */ 1454 memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality)); 1455 /* Copy also thresholds */ 1456 memcpy(&(threshold.low), &(spydata->spy_thr_low), 1457 2 * sizeof(struct iw_quality)); 1458 1459#ifdef WE_SPY_DEBUG 1460 printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n", 1461 threshold.addr.sa_data[0], 1462 threshold.addr.sa_data[1], 1463 threshold.addr.sa_data[2], 1464 threshold.addr.sa_data[3], 1465 threshold.addr.sa_data[4], 1466 threshold.addr.sa_data[5], threshold.qual.level); 1467#endif /* WE_SPY_DEBUG */ 1468 1469 /* Send event to user space */ 1470 wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold); 1471} 1472 1473/* ---------------------------------------------------------------- */ 1474/* 1475 * Call for the driver to update the spy data. 1476 * For now, the spy data is a simple array. As the size of the array is 1477 * small, this is good enough. If we wanted to support larger number of 1478 * spy addresses, we should use something more efficient... 1479 */ 1480void wireless_spy_update(struct net_device * dev, 1481 unsigned char * address, 1482 struct iw_quality * wstats) 1483{ 1484 struct iw_spy_data * spydata = get_spydata(dev); 1485 int i; 1486 int match = -1; 1487 1488 /* Make sure driver is not buggy or using the old API */ 1489 if(!spydata) 1490 return; 1491 1492#ifdef WE_SPY_DEBUG 1493 printk(KERN_DEBUG "wireless_spy_update() : offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]); 1494#endif /* WE_SPY_DEBUG */ 1495 1496 /* Update all records that match */ 1497 for(i = 0; i < spydata->spy_number; i++) 1498 if(!memcmp(address, spydata->spy_address[i], ETH_ALEN)) { 1499 memcpy(&(spydata->spy_stat[i]), wstats, 1500 sizeof(struct iw_quality)); 1501 match = i; 1502 } 1503 1504 /* Generate an event if we cross the spy threshold. 1505 * To avoid event storms, we have a simple hysteresis : we generate 1506 * event only when we go under the low threshold or above the 1507 * high threshold. */ 1508 if(match >= 0) { 1509 if(spydata->spy_thr_under[match]) { 1510 if(wstats->level > spydata->spy_thr_high.level) { 1511 spydata->spy_thr_under[match] = 0; 1512 iw_send_thrspy_event(dev, spydata, 1513 address, wstats); 1514 } 1515 } else { 1516 if(wstats->level < spydata->spy_thr_low.level) { 1517 spydata->spy_thr_under[match] = 1; 1518 iw_send_thrspy_event(dev, spydata, 1519 address, wstats); 1520 } 1521 } 1522 } 1523} 1524 1525EXPORT_SYMBOL(iw_handler_get_spy); 1526EXPORT_SYMBOL(iw_handler_get_thrspy); 1527EXPORT_SYMBOL(iw_handler_set_spy); 1528EXPORT_SYMBOL(iw_handler_set_thrspy); 1529EXPORT_SYMBOL(wireless_send_event); 1530EXPORT_SYMBOL(wireless_spy_update);