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