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