Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.24-rc5 822 lines 20 kB view raw
1/***************************************************************************** 2* wanmain.c WAN Multiprotocol Router Module. Main code. 3* 4* This module is completely hardware-independent and provides 5* the following common services for the WAN Link Drivers: 6* o WAN device management (registering, unregistering) 7* o Network interface management 8* o Physical connection management (dial-up, incoming calls) 9* o Logical connection management (switched virtual circuits) 10* o Protocol encapsulation/decapsulation 11* 12* Author: Gideon Hack 13* 14* Copyright: (c) 1995-1999 Sangoma Technologies Inc. 15* 16* This program is free software; you can redistribute it and/or 17* modify it under the terms of the GNU General Public License 18* as published by the Free Software Foundation; either version 19* 2 of the License, or (at your option) any later version. 20* ============================================================================ 21* Nov 24, 2000 Nenad Corbic Updated for 2.4.X kernels 22* Nov 07, 2000 Nenad Corbic Fixed the Mulit-Port PPP for kernels 2.2.16 and 23* greater. 24* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on 25* kernels 2.2.16 or greater. The SyncPPP 26* has changed. 27* Jul 13, 2000 Nenad Corbic Added SyncPPP support 28* Added extra debugging in device_setup(). 29* Oct 01, 1999 Gideon Hack Update for s514 PCI card 30* Dec 27, 1996 Gene Kozin Initial version (based on Sangoma's WANPIPE) 31* Jan 16, 1997 Gene Kozin router_devlist made public 32* Jan 31, 1997 Alan Cox Hacked it about a bit for 2.1 33* Jun 27, 1997 Alan Cox realigned with vendor code 34* Oct 15, 1997 Farhan Thawar changed wan_encapsulate to add a pad byte of 0 35* Apr 20, 1998 Alan Cox Fixed 2.1 symbols 36* May 17, 1998 K. Baranowski Fixed SNAP encapsulation in wan_encapsulate 37* Dec 15, 1998 Arnaldo Melo support for firmwares of up to 128000 bytes 38* check wandev->setup return value 39* Dec 22, 1998 Arnaldo Melo vmalloc/vfree used in device_setup to allocate 40* kernel memory and copy configuration data to 41* kernel space (for big firmwares) 42* Jun 02, 1999 Gideon Hack Updates for Linux 2.0.X and 2.2.X kernels. 43*****************************************************************************/ 44 45#include <linux/stddef.h> /* offsetof(), etc. */ 46#include <linux/capability.h> 47#include <linux/errno.h> /* return codes */ 48#include <linux/kernel.h> 49#include <linux/module.h> /* support for loadable modules */ 50#include <linux/slab.h> /* kmalloc(), kfree() */ 51#include <linux/mm.h> 52#include <linux/string.h> /* inline mem*, str* functions */ 53 54#include <asm/byteorder.h> /* htons(), etc. */ 55#include <linux/wanrouter.h> /* WAN router API definitions */ 56 57#include <linux/vmalloc.h> /* vmalloc, vfree */ 58#include <asm/uaccess.h> /* copy_to/from_user */ 59#include <linux/init.h> /* __initfunc et al. */ 60#include <net/syncppp.h> 61 62#define KMEM_SAFETYZONE 8 63 64/* 65 * Function Prototypes 66 */ 67 68/* 69 * WAN device IOCTL handlers 70 */ 71 72static int wanrouter_device_setup(struct wan_device *wandev, 73 wandev_conf_t __user *u_conf); 74static int wanrouter_device_stat(struct wan_device *wandev, 75 wandev_stat_t __user *u_stat); 76static int wanrouter_device_shutdown(struct wan_device *wandev); 77static int wanrouter_device_new_if(struct wan_device *wandev, 78 wanif_conf_t __user *u_conf); 79static int wanrouter_device_del_if(struct wan_device *wandev, 80 char __user *u_name); 81 82/* 83 * Miscellaneous 84 */ 85 86static struct wan_device *wanrouter_find_device(char *name); 87static int wanrouter_delete_interface(struct wan_device *wandev, char *name); 88static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); 89static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags); 90 91 92 93/* 94 * Global Data 95 */ 96 97static char wanrouter_fullname[] = "Sangoma WANPIPE Router"; 98static char wanrouter_copyright[] = "(c) 1995-2000 Sangoma Technologies Inc."; 99static char wanrouter_modname[] = ROUTER_NAME; /* short module name */ 100struct wan_device* wanrouter_router_devlist; /* list of registered devices */ 101 102/* 103 * Organize Unique Identifiers for encapsulation/decapsulation 104 */ 105 106#if 0 107static unsigned char wanrouter_oui_ether[] = { 0x00, 0x00, 0x00 }; 108static unsigned char wanrouter_oui_802_2[] = { 0x00, 0x80, 0xC2 }; 109#endif 110 111static int __init wanrouter_init(void) 112{ 113 int err; 114 115 printk(KERN_INFO "%s v%u.%u %s\n", 116 wanrouter_fullname, ROUTER_VERSION, ROUTER_RELEASE, 117 wanrouter_copyright); 118 119 err = wanrouter_proc_init(); 120 if (err) 121 printk(KERN_INFO "%s: can't create entry in proc filesystem!\n", 122 wanrouter_modname); 123 124 return err; 125} 126 127static void __exit wanrouter_cleanup (void) 128{ 129 wanrouter_proc_cleanup(); 130} 131 132/* 133 * This is just plain dumb. We should move the bugger to drivers/net/wan, 134 * slap it first in directory and make it module_init(). The only reason 135 * for subsys_initcall() here is that net goes after drivers (why, BTW?) 136 */ 137subsys_initcall(wanrouter_init); 138module_exit(wanrouter_cleanup); 139 140/* 141 * Kernel APIs 142 */ 143 144/* 145 * Register WAN device. 146 * o verify device credentials 147 * o create an entry for the device in the /proc/net/router directory 148 * o initialize internally maintained fields of the wan_device structure 149 * o link device data space to a singly-linked list 150 * o if it's the first device, then start kernel 'thread' 151 * o increment module use count 152 * 153 * Return: 154 * 0 Ok 155 * < 0 error. 156 * 157 * Context: process 158 */ 159 160 161int register_wan_device(struct wan_device *wandev) 162{ 163 int err, namelen; 164 165 if ((wandev == NULL) || (wandev->magic != ROUTER_MAGIC) || 166 (wandev->name == NULL)) 167 return -EINVAL; 168 169 namelen = strlen(wandev->name); 170 if (!namelen || (namelen > WAN_DRVNAME_SZ)) 171 return -EINVAL; 172 173 if (wanrouter_find_device(wandev->name)) 174 return -EEXIST; 175 176#ifdef WANDEBUG 177 printk(KERN_INFO "%s: registering WAN device %s\n", 178 wanrouter_modname, wandev->name); 179#endif 180 181 /* 182 * Register /proc directory entry 183 */ 184 err = wanrouter_proc_add(wandev); 185 if (err) { 186 printk(KERN_INFO 187 "%s: can't create /proc/net/router/%s entry!\n", 188 wanrouter_modname, wandev->name); 189 return err; 190 } 191 192 /* 193 * Initialize fields of the wan_device structure maintained by the 194 * router and update local data. 195 */ 196 197 wandev->ndev = 0; 198 wandev->dev = NULL; 199 wandev->next = wanrouter_router_devlist; 200 wanrouter_router_devlist = wandev; 201 return 0; 202} 203 204/* 205 * Unregister WAN device. 206 * o shut down device 207 * o unlink device data space from the linked list 208 * o delete device entry in the /proc/net/router directory 209 * o decrement module use count 210 * 211 * Return: 0 Ok 212 * <0 error. 213 * Context: process 214 */ 215 216 217int unregister_wan_device(char *name) 218{ 219 struct wan_device *wandev, *prev; 220 221 if (name == NULL) 222 return -EINVAL; 223 224 for (wandev = wanrouter_router_devlist, prev = NULL; 225 wandev && strcmp(wandev->name, name); 226 prev = wandev, wandev = wandev->next) 227 ; 228 if (wandev == NULL) 229 return -ENODEV; 230 231#ifdef WANDEBUG 232 printk(KERN_INFO "%s: unregistering WAN device %s\n", 233 wanrouter_modname, name); 234#endif 235 236 if (wandev->state != WAN_UNCONFIGURED) 237 wanrouter_device_shutdown(wandev); 238 239 if (prev) 240 prev->next = wandev->next; 241 else 242 wanrouter_router_devlist = wandev->next; 243 244 wanrouter_proc_delete(wandev); 245 return 0; 246} 247 248#if 0 249 250/* 251 * Encapsulate packet. 252 * 253 * Return: encapsulation header size 254 * < 0 - unsupported Ethertype 255 * 256 * Notes: 257 * 1. This function may be called on interrupt context. 258 */ 259 260 261int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev, 262 unsigned short type) 263{ 264 int hdr_len = 0; 265 266 switch (type) { 267 case ETH_P_IP: /* IP datagram encapsulation */ 268 hdr_len += 1; 269 skb_push(skb, 1); 270 skb->data[0] = NLPID_IP; 271 break; 272 273 case ETH_P_IPX: /* SNAP encapsulation */ 274 case ETH_P_ARP: 275 hdr_len += 7; 276 skb_push(skb, 7); 277 skb->data[0] = 0; 278 skb->data[1] = NLPID_SNAP; 279 skb_copy_to_linear_data_offset(skb, 2, wanrouter_oui_ether, 280 sizeof(wanrouter_oui_ether)); 281 *((unsigned short*)&skb->data[5]) = htons(type); 282 break; 283 284 default: /* Unknown packet type */ 285 printk(KERN_INFO 286 "%s: unsupported Ethertype 0x%04X on interface %s!\n", 287 wanrouter_modname, type, dev->name); 288 hdr_len = -EINVAL; 289 } 290 return hdr_len; 291} 292 293 294/* 295 * Decapsulate packet. 296 * 297 * Return: Ethertype (in network order) 298 * 0 unknown encapsulation 299 * 300 * Notes: 301 * 1. This function may be called on interrupt context. 302 */ 303 304 305__be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev) 306{ 307 int cnt = skb->data[0] ? 0 : 1; /* there may be a pad present */ 308 __be16 ethertype; 309 310 switch (skb->data[cnt]) { 311 case NLPID_IP: /* IP datagramm */ 312 ethertype = htons(ETH_P_IP); 313 cnt += 1; 314 break; 315 316 case NLPID_SNAP: /* SNAP encapsulation */ 317 if (memcmp(&skb->data[cnt + 1], wanrouter_oui_ether, 318 sizeof(wanrouter_oui_ether))){ 319 printk(KERN_INFO 320 "%s: unsupported SNAP OUI %02X-%02X-%02X " 321 "on interface %s!\n", wanrouter_modname, 322 skb->data[cnt+1], skb->data[cnt+2], 323 skb->data[cnt+3], dev->name); 324 return 0; 325 } 326 ethertype = *((__be16*)&skb->data[cnt+4]); 327 cnt += 6; 328 break; 329 330 /* add other protocols, e.g. CLNP, ESIS, ISIS, if needed */ 331 332 default: 333 printk(KERN_INFO 334 "%s: unsupported NLPID 0x%02X on interface %s!\n", 335 wanrouter_modname, skb->data[cnt], dev->name); 336 return 0; 337 } 338 skb->protocol = ethertype; 339 skb->pkt_type = PACKET_HOST; /* Physically point to point */ 340 skb_pull(skb, cnt); 341 skb_reset_mac_header(skb); 342 return ethertype; 343} 344 345#endif /* 0 */ 346 347/* 348 * WAN device IOCTL. 349 * o find WAN device associated with this node 350 * o execute requested action or pass command to the device driver 351 */ 352 353int wanrouter_ioctl(struct inode *inode, struct file *file, 354 unsigned int cmd, unsigned long arg) 355{ 356 int err = 0; 357 struct proc_dir_entry *dent; 358 struct wan_device *wandev; 359 void __user *data = (void __user *)arg; 360 361 if (!capable(CAP_NET_ADMIN)) 362 return -EPERM; 363 364 if ((cmd >> 8) != ROUTER_IOCTL) 365 return -EINVAL; 366 367 dent = PDE(inode); 368 if ((dent == NULL) || (dent->data == NULL)) 369 return -EINVAL; 370 371 wandev = dent->data; 372 if (wandev->magic != ROUTER_MAGIC) 373 return -EINVAL; 374 375 switch (cmd) { 376 case ROUTER_SETUP: 377 err = wanrouter_device_setup(wandev, data); 378 break; 379 380 case ROUTER_DOWN: 381 err = wanrouter_device_shutdown(wandev); 382 break; 383 384 case ROUTER_STAT: 385 err = wanrouter_device_stat(wandev, data); 386 break; 387 388 case ROUTER_IFNEW: 389 err = wanrouter_device_new_if(wandev, data); 390 break; 391 392 case ROUTER_IFDEL: 393 err = wanrouter_device_del_if(wandev, data); 394 break; 395 396 case ROUTER_IFSTAT: 397 break; 398 399 default: 400 if ((cmd >= ROUTER_USER) && 401 (cmd <= ROUTER_USER_MAX) && 402 wandev->ioctl) 403 err = wandev->ioctl(wandev, cmd, arg); 404 else err = -EINVAL; 405 } 406 return err; 407} 408 409/* 410 * WAN Driver IOCTL Handlers 411 */ 412 413/* 414 * Setup WAN link device. 415 * o verify user address space 416 * o allocate kernel memory and copy configuration data to kernel space 417 * o if configuration data includes extension, copy it to kernel space too 418 * o call driver's setup() entry point 419 */ 420 421static int wanrouter_device_setup(struct wan_device *wandev, 422 wandev_conf_t __user *u_conf) 423{ 424 void *data = NULL; 425 wandev_conf_t *conf; 426 int err = -EINVAL; 427 428 if (wandev->setup == NULL) { /* Nothing to do ? */ 429 printk(KERN_INFO "%s: ERROR, No setup script: wandev->setup()\n", 430 wandev->name); 431 return 0; 432 } 433 434 conf = kmalloc(sizeof(wandev_conf_t), GFP_KERNEL); 435 if (conf == NULL){ 436 printk(KERN_INFO "%s: ERROR, Failed to allocate kernel memory !\n", 437 wandev->name); 438 return -ENOBUFS; 439 } 440 441 if (copy_from_user(conf, u_conf, sizeof(wandev_conf_t))) { 442 printk(KERN_INFO "%s: Failed to copy user config data to kernel space!\n", 443 wandev->name); 444 kfree(conf); 445 return -EFAULT; 446 } 447 448 if (conf->magic != ROUTER_MAGIC) { 449 kfree(conf); 450 printk(KERN_INFO "%s: ERROR, Invalid MAGIC Number\n", 451 wandev->name); 452 return -EINVAL; 453 } 454 455 if (conf->data_size && conf->data) { 456 if (conf->data_size > 128000) { 457 printk(KERN_INFO 458 "%s: ERROR, Invalid firmware data size %i !\n", 459 wandev->name, conf->data_size); 460 kfree(conf); 461 return -EINVAL; 462 } 463 464 data = vmalloc(conf->data_size); 465 if (!data) { 466 printk(KERN_INFO 467 "%s: ERROR, Faild allocate kernel memory !\n", 468 wandev->name); 469 kfree(conf); 470 return -ENOBUFS; 471 } 472 if (!copy_from_user(data, conf->data, conf->data_size)) { 473 conf->data = data; 474 err = wandev->setup(wandev, conf); 475 } else { 476 printk(KERN_INFO 477 "%s: ERROR, Faild to copy from user data !\n", 478 wandev->name); 479 err = -EFAULT; 480 } 481 vfree(data); 482 } else { 483 printk(KERN_INFO 484 "%s: ERROR, No firmware found ! Firmware size = %i !\n", 485 wandev->name, conf->data_size); 486 } 487 488 kfree(conf); 489 return err; 490} 491 492/* 493 * Shutdown WAN device. 494 * o delete all not opened logical channels for this device 495 * o call driver's shutdown() entry point 496 */ 497 498static int wanrouter_device_shutdown(struct wan_device *wandev) 499{ 500 struct net_device *dev; 501 int err=0; 502 503 if (wandev->state == WAN_UNCONFIGURED) 504 return 0; 505 506 printk(KERN_INFO "\n%s: Shutting Down!\n",wandev->name); 507 508 for (dev = wandev->dev; dev;) { 509 err = wanrouter_delete_interface(wandev, dev->name); 510 if (err) 511 return err; 512 /* The above function deallocates the current dev 513 * structure. Therefore, we cannot use dev->priv 514 * as the next element: wandev->dev points to the 515 * next element */ 516 dev = wandev->dev; 517 } 518 519 if (wandev->ndev) 520 return -EBUSY; /* there are opened interfaces */ 521 522 if (wandev->shutdown) 523 err=wandev->shutdown(wandev); 524 525 return err; 526} 527 528/* 529 * Get WAN device status & statistics. 530 */ 531 532static int wanrouter_device_stat(struct wan_device *wandev, 533 wandev_stat_t __user *u_stat) 534{ 535 wandev_stat_t stat; 536 537 memset(&stat, 0, sizeof(stat)); 538 539 /* Ask device driver to update device statistics */ 540 if ((wandev->state != WAN_UNCONFIGURED) && wandev->update) 541 wandev->update(wandev); 542 543 /* Fill out structure */ 544 stat.ndev = wandev->ndev; 545 stat.state = wandev->state; 546 547 if (copy_to_user(u_stat, &stat, sizeof(stat))) 548 return -EFAULT; 549 550 return 0; 551} 552 553/* 554 * Create new WAN interface. 555 * o verify user address space 556 * o copy configuration data to kernel address space 557 * o allocate network interface data space 558 * o call driver's new_if() entry point 559 * o make sure there is no interface name conflict 560 * o register network interface 561 */ 562 563static int wanrouter_device_new_if(struct wan_device *wandev, 564 wanif_conf_t __user *u_conf) 565{ 566 wanif_conf_t *cnf; 567 struct net_device *dev = NULL; 568#ifdef CONFIG_WANPIPE_MULTPPP 569 struct ppp_device *pppdev=NULL; 570#endif 571 int err; 572 573 if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL)) 574 return -ENODEV; 575 576 cnf = kmalloc(sizeof(wanif_conf_t), GFP_KERNEL); 577 if (!cnf) 578 return -ENOBUFS; 579 580 err = -EFAULT; 581 if (copy_from_user(cnf, u_conf, sizeof(wanif_conf_t))) 582 goto out; 583 584 err = -EINVAL; 585 if (cnf->magic != ROUTER_MAGIC) 586 goto out; 587 588 if (cnf->config_id == WANCONFIG_MPPP) { 589#ifdef CONFIG_WANPIPE_MULTPPP 590 pppdev = kzalloc(sizeof(struct ppp_device), GFP_KERNEL); 591 err = -ENOBUFS; 592 if (pppdev == NULL) 593 goto out; 594 pppdev->dev = kzalloc(sizeof(struct net_device), GFP_KERNEL); 595 if (pppdev->dev == NULL) { 596 kfree(pppdev); 597 err = -ENOBUFS; 598 goto out; 599 } 600 err = wandev->new_if(wandev, (struct net_device *)pppdev, cnf); 601 dev = pppdev->dev; 602#else 603 printk(KERN_INFO "%s: Wanpipe Mulit-Port PPP support has not been compiled in!\n", 604 wandev->name); 605 err = -EPROTONOSUPPORT; 606 goto out; 607#endif 608 } else { 609 dev = kzalloc(sizeof(struct net_device), GFP_KERNEL); 610 err = -ENOBUFS; 611 if (dev == NULL) 612 goto out; 613 err = wandev->new_if(wandev, dev, cnf); 614 } 615 616 if (!err) { 617 /* Register network interface. This will invoke init() 618 * function supplied by the driver. If device registered 619 * successfully, add it to the interface list. 620 */ 621 622 if (dev->name == NULL) { 623 err = -EINVAL; 624 } else { 625 626 #ifdef WANDEBUG 627 printk(KERN_INFO "%s: registering interface %s...\n", 628 wanrouter_modname, dev->name); 629 #endif 630 631 err = register_netdev(dev); 632 if (!err) { 633 struct net_device *slave = NULL; 634 unsigned long smp_flags=0; 635 636 lock_adapter_irq(&wandev->lock, &smp_flags); 637 638 if (wandev->dev == NULL) { 639 wandev->dev = dev; 640 } else { 641 for (slave=wandev->dev; 642 *((struct net_device **)slave->priv); 643 slave = *((struct net_device **)slave->priv)); 644 645 *((struct net_device **)slave->priv) = dev; 646 } 647 ++wandev->ndev; 648 649 unlock_adapter_irq(&wandev->lock, &smp_flags); 650 err = 0; /* done !!! */ 651 goto out; 652 } 653 } 654 if (wandev->del_if) 655 wandev->del_if(wandev, dev); 656 } 657 658 /* This code has moved from del_if() function */ 659 kfree(dev->priv); 660 dev->priv = NULL; 661 662#ifdef CONFIG_WANPIPE_MULTPPP 663 if (cnf->config_id == WANCONFIG_MPPP) 664 kfree(pppdev); 665 else 666 kfree(dev); 667#else 668 /* Sync PPP is disabled */ 669 if (cnf->config_id != WANCONFIG_MPPP) 670 kfree(dev); 671#endif 672 673out: 674 kfree(cnf); 675 return err; 676} 677 678 679/* 680 * Delete WAN logical channel. 681 * o verify user address space 682 * o copy configuration data to kernel address space 683 */ 684 685static int wanrouter_device_del_if(struct wan_device *wandev, char __user *u_name) 686{ 687 char name[WAN_IFNAME_SZ + 1]; 688 int err = 0; 689 690 if (wandev->state == WAN_UNCONFIGURED) 691 return -ENODEV; 692 693 memset(name, 0, sizeof(name)); 694 695 if (copy_from_user(name, u_name, WAN_IFNAME_SZ)) 696 return -EFAULT; 697 698 err = wanrouter_delete_interface(wandev, name); 699 if (err) 700 return err; 701 702 /* If last interface being deleted, shutdown card 703 * This helps with administration at leaf nodes 704 * (You can tell if the person at the other end of the phone 705 * has an interface configured) and avoids DoS vulnerabilities 706 * in binary driver files - this fixes a problem with the current 707 * Sangoma driver going into strange states when all the network 708 * interfaces are deleted and the link irrecoverably disconnected. 709 */ 710 711 if (!wandev->ndev && wandev->shutdown) 712 err = wandev->shutdown(wandev); 713 714 return err; 715} 716 717/* 718 * Miscellaneous Functions 719 */ 720 721/* 722 * Find WAN device by name. 723 * Return pointer to the WAN device data space or NULL if device not found. 724 */ 725 726static struct wan_device *wanrouter_find_device(char *name) 727{ 728 struct wan_device *wandev; 729 730 for (wandev = wanrouter_router_devlist; 731 wandev && strcmp(wandev->name, name); 732 wandev = wandev->next); 733 return wandev; 734} 735 736/* 737 * Delete WAN logical channel identified by its name. 738 * o find logical channel by its name 739 * o call driver's del_if() entry point 740 * o unregister network interface 741 * o unlink channel data space from linked list of channels 742 * o release channel data space 743 * 744 * Return: 0 success 745 * -ENODEV channel not found. 746 * -EBUSY interface is open 747 * 748 * Note: If (force != 0), then device will be destroyed even if interface 749 * associated with it is open. It's caller's responsibility to make 750 * sure that opened interfaces are not removed! 751 */ 752 753static int wanrouter_delete_interface(struct wan_device *wandev, char *name) 754{ 755 struct net_device *dev = NULL, *prev = NULL; 756 unsigned long smp_flags=0; 757 758 lock_adapter_irq(&wandev->lock, &smp_flags); 759 dev = wandev->dev; 760 prev = NULL; 761 while (dev && strcmp(name, dev->name)) { 762 struct net_device **slave = dev->priv; 763 prev = dev; 764 dev = *slave; 765 } 766 unlock_adapter_irq(&wandev->lock, &smp_flags); 767 768 if (dev == NULL) 769 return -ENODEV; /* interface not found */ 770 771 if (netif_running(dev)) 772 return -EBUSY; /* interface in use */ 773 774 if (wandev->del_if) 775 wandev->del_if(wandev, dev); 776 777 lock_adapter_irq(&wandev->lock, &smp_flags); 778 if (prev) { 779 struct net_device **prev_slave = prev->priv; 780 struct net_device **slave = dev->priv; 781 782 *prev_slave = *slave; 783 } else { 784 struct net_device **slave = dev->priv; 785 wandev->dev = *slave; 786 } 787 --wandev->ndev; 788 unlock_adapter_irq(&wandev->lock, &smp_flags); 789 790 printk(KERN_INFO "%s: unregistering '%s'\n", wandev->name, dev->name); 791 792 /* Due to new interface linking method using dev->priv, 793 * this code has moved from del_if() function.*/ 794 kfree(dev->priv); 795 dev->priv=NULL; 796 797 unregister_netdev(dev); 798 799 free_netdev(dev); 800 801 return 0; 802} 803 804static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) 805{ 806 spin_lock_irqsave(lock, *smp_flags); 807} 808 809 810static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags) 811{ 812 spin_unlock_irqrestore(lock, *smp_flags); 813} 814 815EXPORT_SYMBOL(register_wan_device); 816EXPORT_SYMBOL(unregister_wan_device); 817 818MODULE_LICENSE("GPL"); 819 820/* 821 * End 822 */