|
|
1.1 ! root 1: /* ! 2: * NET3 Protocol independent device support routines. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License ! 6: * as published by the Free Software Foundation; either version ! 7: * 2 of the License, or (at your option) any later version. ! 8: * ! 9: * Derived from the non IP parts of dev.c 1.0.19 ! 10: * Authors: Ross Biro, <[email protected]> ! 11: * Fred N. van Kempen, <[email protected]> ! 12: * Mark Evans, <[email protected]> ! 13: * ! 14: * Additional Authors: ! 15: * Florian la Roche <[email protected]> ! 16: * Alan Cox <[email protected]> ! 17: * David Hinds <[email protected]> ! 18: * ! 19: * Changes: ! 20: * Alan Cox : device private ioctl copies fields back. ! 21: * Alan Cox : Transmit queue code does relevant stunts to ! 22: * keep the queue safe. ! 23: * Alan Cox : Fixed double lock. ! 24: * Alan Cox : Fixed promisc NULL pointer trap ! 25: * ???????? : Support the full private ioctl range ! 26: * Alan Cox : Moved ioctl permission check into drivers ! 27: * Tim Kordas : SIOCADDMULTI/SIOCDELMULTI ! 28: * Alan Cox : 100 backlog just doesn't cut it when ! 29: * you start doing multicast video 8) ! 30: * Alan Cox : Rewrote net_bh and list manager. ! 31: * Alan Cox : Fix ETH_P_ALL echoback lengths. ! 32: * Alan Cox : Took out transmit every packet pass ! 33: * Saved a few bytes in the ioctl handler ! 34: * Alan Cox : Network driver sets packet type before calling netif_rx. Saves ! 35: * a function call a packet. ! 36: * Alan Cox : Hashed net_bh() ! 37: * Richard Kooijman: Timestamp fixes. ! 38: * Alan Cox : Wrong field in SIOCGIFDSTADDR ! 39: * Alan Cox : Device lock protection. ! 40: * Alan Cox : Fixed nasty side effect of device close changes. ! 41: * Rudi Cilibrasi : Pass the right thing to set_mac_address() ! 42: * Dave Miller : 32bit quantity for the device lock to make it work out ! 43: * on a Sparc. ! 44: * Bjorn Ekwall : Added KERNELD hack. ! 45: * Alan Cox : Cleaned up the backlog initialise. ! 46: * Craig Metz : SIOCGIFCONF fix if space for under ! 47: * 1 device. ! 48: * ! 49: */ ! 50: ! 51: #include <asm/segment.h> ! 52: #include <asm/system.h> ! 53: #include <asm/bitops.h> ! 54: #include <linux/config.h> ! 55: #include <linux/types.h> ! 56: #include <linux/kernel.h> ! 57: #include <linux/sched.h> ! 58: #include <linux/string.h> ! 59: #include <linux/mm.h> ! 60: #include <linux/socket.h> ! 61: #include <linux/sockios.h> ! 62: #include <linux/in.h> ! 63: #include <linux/errno.h> ! 64: #include <linux/interrupt.h> ! 65: #include <linux/if_ether.h> ! 66: #include <linux/inet.h> ! 67: #include <linux/netdevice.h> ! 68: #include <linux/etherdevice.h> ! 69: #include <linux/notifier.h> ! 70: #include <net/ip.h> ! 71: #include <net/route.h> ! 72: #include <linux/skbuff.h> ! 73: #include <net/sock.h> ! 74: #include <net/arp.h> ! 75: #include <net/slhc.h> ! 76: #include <linux/proc_fs.h> ! 77: #include <linux/stat.h> ! 78: #ifdef CONFIG_NET_ALIAS ! 79: #include <linux/net_alias.h> ! 80: #endif ! 81: #ifdef CONFIG_KERNELD ! 82: #include <linux/kerneld.h> ! 83: #endif ! 84: ! 85: #ifndef MACH ! 86: /* ! 87: * The list of packet types we will receive (as opposed to discard) ! 88: * and the routines to invoke. ! 89: */ ! 90: ! 91: struct packet_type *ptype_base[16]; ! 92: struct packet_type *ptype_all = NULL; /* Taps */ ! 93: ! 94: /* ! 95: * Device list lock ! 96: */ ! 97: ! 98: int dev_lockct=0; ! 99: ! 100: /* ! 101: * Our notifier list ! 102: */ ! 103: ! 104: struct notifier_block *netdev_chain=NULL; ! 105: ! 106: /* ! 107: * Device drivers call our routines to queue packets here. We empty the ! 108: * queue in the bottom half handler. ! 109: */ ! 110: ! 111: static struct sk_buff_head backlog; ! 112: ! 113: /* ! 114: * We don't overdo the queue or we will thrash memory badly. ! 115: */ ! 116: ! 117: static int backlog_size = 0; ! 118: ! 119: /* ! 120: * Return the lesser of the two values. ! 121: */ ! 122: ! 123: static __inline__ unsigned long min(unsigned long a, unsigned long b) ! 124: { ! 125: return (a < b)? a : b; ! 126: } ! 127: ! 128: ! 129: /****************************************************************************************** ! 130: ! 131: Protocol management and registration routines ! 132: ! 133: *******************************************************************************************/ ! 134: ! 135: /* ! 136: * For efficiency ! 137: */ ! 138: ! 139: static int dev_nit=0; ! 140: ! 141: /* ! 142: * Add a protocol ID to the list. Now that the input handler is ! 143: * smarter we can dispense with all the messy stuff that used to be ! 144: * here. ! 145: */ ! 146: ! 147: void dev_add_pack(struct packet_type *pt) ! 148: { ! 149: int hash; ! 150: if(pt->type==htons(ETH_P_ALL)) ! 151: { ! 152: dev_nit++; ! 153: pt->next=ptype_all; ! 154: ptype_all=pt; ! 155: } ! 156: else ! 157: { ! 158: hash=ntohs(pt->type)&15; ! 159: pt->next = ptype_base[hash]; ! 160: ptype_base[hash] = pt; ! 161: } ! 162: } ! 163: ! 164: ! 165: /* ! 166: * Remove a protocol ID from the list. ! 167: */ ! 168: ! 169: void dev_remove_pack(struct packet_type *pt) ! 170: { ! 171: struct packet_type **pt1; ! 172: if(pt->type==htons(ETH_P_ALL)) ! 173: { ! 174: dev_nit--; ! 175: pt1=&ptype_all; ! 176: } ! 177: else ! 178: pt1=&ptype_base[ntohs(pt->type)&15]; ! 179: for(; (*pt1)!=NULL; pt1=&((*pt1)->next)) ! 180: { ! 181: if(pt==(*pt1)) ! 182: { ! 183: *pt1=pt->next; ! 184: return; ! 185: } ! 186: } ! 187: printk("dev_remove_pack: %p not found.\n", pt); ! 188: } ! 189: ! 190: /***************************************************************************************** ! 191: ! 192: Device Interface Subroutines ! 193: ! 194: ******************************************************************************************/ ! 195: ! 196: /* ! 197: * Find an interface by name. ! 198: */ ! 199: ! 200: struct device *dev_get(const char *name) ! 201: { ! 202: struct device *dev; ! 203: ! 204: for (dev = dev_base; dev != NULL; dev = dev->next) ! 205: { ! 206: if (strcmp(dev->name, name) == 0) ! 207: return(dev); ! 208: } ! 209: return NULL; ! 210: } ! 211: ! 212: /* ! 213: * Find and possibly load an interface. ! 214: */ ! 215: ! 216: #ifdef CONFIG_KERNELD ! 217: ! 218: extern __inline__ void dev_load(const char *name) ! 219: { ! 220: char *sptr; ! 221: ! 222: if(!dev_get(name)) { ! 223: #ifdef CONFIG_NET_ALIAS ! 224: for (sptr=name ; *sptr ; sptr++) if(*sptr==':') break; ! 225: if (!(*sptr && *(sptr+1))) ! 226: #endif ! 227: request_module(name); ! 228: } ! 229: } ! 230: ! 231: #endif ! 232: ! 233: /* ! 234: * Prepare an interface for use. ! 235: */ ! 236: ! 237: int dev_open(struct device *dev) ! 238: { ! 239: int ret = 0; ! 240: ! 241: /* ! 242: * Call device private open method ! 243: */ ! 244: if (dev->open) ! 245: ret = dev->open(dev); ! 246: ! 247: /* ! 248: * If it went open OK then set the flags ! 249: */ ! 250: ! 251: if (ret == 0) ! 252: { ! 253: dev->flags |= (IFF_UP | IFF_RUNNING); ! 254: /* ! 255: * Initialise multicasting status ! 256: */ ! 257: dev_mc_upload(dev); ! 258: notifier_call_chain(&netdev_chain, NETDEV_UP, dev); ! 259: } ! 260: return(ret); ! 261: } ! 262: ! 263: ! 264: /* ! 265: * Completely shutdown an interface. ! 266: */ ! 267: ! 268: int dev_close(struct device *dev) ! 269: { ! 270: int ct=0; ! 271: ! 272: /* ! 273: * Call the device specific close. This cannot fail. ! 274: * Only if device is UP ! 275: */ ! 276: ! 277: if ((dev->flags & IFF_UP) && dev->stop) ! 278: dev->stop(dev); ! 279: ! 280: /* ! 281: * Device is now down. ! 282: */ ! 283: ! 284: dev->flags&=~(IFF_UP|IFF_RUNNING); ! 285: ! 286: /* ! 287: * Tell people we are going down ! 288: */ ! 289: notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev); ! 290: /* ! 291: * Flush the multicast chain ! 292: */ ! 293: dev_mc_discard(dev); ! 294: /* ! 295: * Blank the IP addresses ! 296: */ ! 297: dev->pa_addr = 0; ! 298: dev->pa_dstaddr = 0; ! 299: dev->pa_brdaddr = 0; ! 300: dev->pa_mask = 0; ! 301: /* ! 302: * Purge any queued packets when we down the link ! 303: */ ! 304: while(ct<DEV_NUMBUFFS) ! 305: { ! 306: struct sk_buff *skb; ! 307: while((skb=skb_dequeue(&dev->buffs[ct]))!=NULL) ! 308: if(skb->free) ! 309: kfree_skb(skb,FREE_WRITE); ! 310: ct++; ! 311: } ! 312: return(0); ! 313: } ! 314: ! 315: ! 316: /* ! 317: * Device change register/unregister. These are not inline or static ! 318: * as we export them to the world. ! 319: */ ! 320: ! 321: int register_netdevice_notifier(struct notifier_block *nb) ! 322: { ! 323: return notifier_chain_register(&netdev_chain, nb); ! 324: } ! 325: ! 326: int unregister_netdevice_notifier(struct notifier_block *nb) ! 327: { ! 328: return notifier_chain_unregister(&netdev_chain,nb); ! 329: } ! 330: ! 331: /* ! 332: * Send (or queue for sending) a packet. ! 333: * ! 334: * IMPORTANT: When this is called to resend frames. The caller MUST ! 335: * already have locked the sk_buff. Apart from that we do the ! 336: * rest of the magic. ! 337: */ ! 338: ! 339: void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) ! 340: { ! 341: unsigned long flags; ! 342: struct sk_buff_head *list; ! 343: int retransmission = 0; /* used to say if the packet should go */ ! 344: /* at the front or the back of the */ ! 345: /* queue - front is a retransmit try */ ! 346: ! 347: if(pri>=0 && !skb_device_locked(skb)) ! 348: skb_device_lock(skb); /* Shove a lock on the frame */ ! 349: #if CONFIG_SKB_CHECK ! 350: IS_SKB(skb); ! 351: #endif ! 352: skb->dev = dev; ! 353: ! 354: /* ! 355: * Negative priority is used to flag a frame that is being pulled from the ! 356: * queue front as a retransmit attempt. It therefore goes back on the queue ! 357: * start on a failure. ! 358: */ ! 359: ! 360: if (pri < 0) ! 361: { ! 362: pri = -pri-1; ! 363: retransmission = 1; ! 364: } ! 365: ! 366: #ifdef CONFIG_NET_DEBUG ! 367: if (pri >= DEV_NUMBUFFS) ! 368: { ! 369: printk("bad priority in dev_queue_xmit.\n"); ! 370: pri = 1; ! 371: } ! 372: #endif ! 373: ! 374: /* ! 375: * If the address has not been resolved. Call the device header rebuilder. ! 376: * This can cover all protocols and technically not just ARP either. ! 377: */ ! 378: ! 379: if (!skb->arp && dev->rebuild_header(skb->data, dev, skb->raddr, skb)) { ! 380: return; ! 381: } ! 382: ! 383: /* ! 384: * ! 385: * If dev is an alias, switch to its main device. ! 386: * "arp" resolution has been made with alias device, so ! 387: * arp entries refer to alias, not main. ! 388: * ! 389: */ ! 390: ! 391: #ifdef CONFIG_NET_ALIAS ! 392: if (net_alias_is(dev)) ! 393: skb->dev = dev = net_alias_main_dev(dev); ! 394: #endif ! 395: list = dev->buffs + pri; ! 396: ! 397: save_flags(flags); ! 398: /* if this isn't a retransmission, use the first packet instead... */ ! 399: if (!retransmission) { ! 400: if (skb_queue_len(list)) { ! 401: /* avoid overrunning the device queue.. */ ! 402: if (skb_queue_len(list) > dev->tx_queue_len) { ! 403: dev_kfree_skb(skb, FREE_WRITE); ! 404: return; ! 405: } ! 406: cli(); ! 407: skb_device_unlock(skb); /* Buffer is on the device queue and can be freed safely */ ! 408: __skb_queue_tail(list, skb); ! 409: skb = __skb_dequeue(list); ! 410: skb_device_lock(skb); /* New buffer needs locking down */ ! 411: restore_flags(flags); ! 412: } ! 413: ! 414: /* copy outgoing packets to any sniffer packet handlers */ ! 415: if (dev_nit) { ! 416: struct packet_type *ptype; ! 417: skb->stamp=xtime; ! 418: for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) ! 419: { ! 420: /* Never send packets back to the socket ! 421: * they originated from - MvS ([email protected]) ! 422: */ ! 423: if ((ptype->dev == dev || !ptype->dev) && ! 424: ((struct sock *)ptype->data != skb->sk)) ! 425: { ! 426: struct sk_buff *skb2; ! 427: if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) ! 428: break; ! 429: skb2->h.raw = skb2->data + dev->hard_header_len; ! 430: skb2->mac.raw = skb2->data; ! 431: ptype->func(skb2, skb->dev, ptype); ! 432: } ! 433: } ! 434: } ! 435: } ! 436: start_bh_atomic(); ! 437: if (dev->hard_start_xmit(skb, dev) == 0) { ! 438: /* ! 439: * Packet is now solely the responsibility of the driver ! 440: */ ! 441: end_bh_atomic(); ! 442: return; ! 443: } ! 444: end_bh_atomic(); ! 445: ! 446: /* ! 447: * Transmission failed, put skb back into a list. Once on the list it's safe and ! 448: * no longer device locked (it can be freed safely from the device queue) ! 449: */ ! 450: cli(); ! 451: skb_device_unlock(skb); ! 452: __skb_queue_head(list,skb); ! 453: restore_flags(flags); ! 454: } ! 455: ! 456: /* ! 457: * Receive a packet from a device driver and queue it for the upper ! 458: * (protocol) levels. It always succeeds. This is the recommended ! 459: * interface to use. ! 460: */ ! 461: ! 462: void netif_rx(struct sk_buff *skb) ! 463: { ! 464: static int dropping = 0; ! 465: ! 466: /* ! 467: * Any received buffers are un-owned and should be discarded ! 468: * when freed. These will be updated later as the frames get ! 469: * owners. ! 470: */ ! 471: ! 472: skb->sk = NULL; ! 473: skb->free = 1; ! 474: if(skb->stamp.tv_sec==0) ! 475: skb->stamp = xtime; ! 476: ! 477: /* ! 478: * Check that we aren't overdoing things. ! 479: */ ! 480: ! 481: if (!backlog_size) ! 482: dropping = 0; ! 483: else if (backlog_size > 300) ! 484: dropping = 1; ! 485: ! 486: if (dropping) ! 487: { ! 488: kfree_skb(skb, FREE_READ); ! 489: return; ! 490: } ! 491: ! 492: /* ! 493: * Add it to the "backlog" queue. ! 494: */ ! 495: #if CONFIG_SKB_CHECK ! 496: IS_SKB(skb); ! 497: #endif ! 498: skb_queue_tail(&backlog,skb); ! 499: backlog_size++; ! 500: ! 501: /* ! 502: * If any packet arrived, mark it for processing after the ! 503: * hardware interrupt returns. ! 504: */ ! 505: ! 506: #ifdef CONFIG_NET_RUNONIRQ /* Dont enable yet, needs some driver mods */ ! 507: net_bh(); ! 508: #else ! 509: mark_bh(NET_BH); ! 510: #endif ! 511: return; ! 512: } ! 513: ! 514: /* ! 515: * This routine causes all interfaces to try to send some data. ! 516: */ ! 517: ! 518: void dev_transmit(void) ! 519: { ! 520: struct device *dev; ! 521: ! 522: for (dev = dev_base; dev != NULL; dev = dev->next) ! 523: { ! 524: if (dev->flags != 0 && !dev->tbusy) { ! 525: /* ! 526: * Kick the device ! 527: */ ! 528: dev_tint(dev); ! 529: } ! 530: } ! 531: } ! 532: ! 533: ! 534: /********************************************************************************** ! 535: ! 536: Receive Queue Processor ! 537: ! 538: ***********************************************************************************/ ! 539: ! 540: /* ! 541: * This is a single non-reentrant routine which takes the received packet ! 542: * queue and throws it at the networking layers in the hope that something ! 543: * useful will emerge. ! 544: */ ! 545: ! 546: volatile unsigned long in_bh = 0; /* Non-reentrant remember */ ! 547: ! 548: int in_net_bh() /* Used by timer.c */ ! 549: { ! 550: return(in_bh==0?0:1); ! 551: } ! 552: ! 553: /* ! 554: * When we are called the queue is ready to grab, the interrupts are ! 555: * on and hardware can interrupt and queue to the receive queue a we ! 556: * run with no problems. ! 557: * This is run as a bottom half after an interrupt handler that does ! 558: * mark_bh(NET_BH); ! 559: */ ! 560: ! 561: void net_bh(void *tmp) ! 562: { ! 563: struct sk_buff *skb; ! 564: struct packet_type *ptype; ! 565: struct packet_type *pt_prev; ! 566: unsigned short type; ! 567: ! 568: /* ! 569: * Atomically check and mark our BUSY state. ! 570: */ ! 571: ! 572: if (set_bit(1, (void*)&in_bh)) ! 573: return; ! 574: ! 575: /* ! 576: * Can we send anything now? We want to clear the ! 577: * decks for any more sends that get done as we ! 578: * process the input. This also minimises the ! 579: * latency on a transmit interrupt bh. ! 580: */ ! 581: ! 582: dev_transmit(); ! 583: ! 584: /* ! 585: * Any data left to process. This may occur because a ! 586: * mark_bh() is done after we empty the queue including ! 587: * that from the device which does a mark_bh() just after ! 588: */ ! 589: ! 590: cli(); ! 591: ! 592: /* ! 593: * While the queue is not empty ! 594: */ ! 595: ! 596: while((skb=__skb_dequeue(&backlog))!=NULL) ! 597: { ! 598: /* ! 599: * We have a packet. Therefore the queue has shrunk ! 600: */ ! 601: backlog_size--; ! 602: ! 603: sti(); ! 604: ! 605: /* ! 606: * Bump the pointer to the next structure. ! 607: * ! 608: * On entry to the protocol layer. skb->data and ! 609: * skb->h.raw point to the MAC and encapsulated data ! 610: */ ! 611: ! 612: skb->h.raw = skb->data; ! 613: ! 614: /* ! 615: * Fetch the packet protocol ID. ! 616: */ ! 617: ! 618: type = skb->protocol; ! 619: ! 620: /* ! 621: * We got a packet ID. Now loop over the "known protocols" ! 622: * list. There are two lists. The ptype_all list of taps (normally empty) ! 623: * and the main protocol list which is hashed perfectly for normal protocols. ! 624: */ ! 625: pt_prev = NULL; ! 626: for (ptype = ptype_all; ptype!=NULL; ptype=ptype->next) ! 627: { ! 628: if(pt_prev) ! 629: { ! 630: struct sk_buff *skb2=skb_clone(skb, GFP_ATOMIC); ! 631: if(skb2) ! 632: pt_prev->func(skb2,skb->dev, pt_prev); ! 633: } ! 634: pt_prev=ptype; ! 635: } ! 636: ! 637: for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next) ! 638: { ! 639: if (ptype->type == type && (!ptype->dev || ptype->dev==skb->dev)) ! 640: { ! 641: /* ! 642: * We already have a match queued. Deliver ! 643: * to it and then remember the new match ! 644: */ ! 645: if(pt_prev) ! 646: { ! 647: struct sk_buff *skb2; ! 648: ! 649: skb2=skb_clone(skb, GFP_ATOMIC); ! 650: ! 651: /* ! 652: * Kick the protocol handler. This should be fast ! 653: * and efficient code. ! 654: */ ! 655: ! 656: if(skb2) ! 657: pt_prev->func(skb2, skb->dev, pt_prev); ! 658: } ! 659: /* Remember the current last to do */ ! 660: pt_prev=ptype; ! 661: } ! 662: } /* End of protocol list loop */ ! 663: ! 664: /* ! 665: * Is there a last item to send to ? ! 666: */ ! 667: ! 668: if(pt_prev) ! 669: pt_prev->func(skb, skb->dev, pt_prev); ! 670: /* ! 671: * Has an unknown packet has been received ? ! 672: */ ! 673: ! 674: else ! 675: kfree_skb(skb, FREE_WRITE); ! 676: ! 677: /* ! 678: * Again, see if we can transmit anything now. ! 679: * [Ought to take this out judging by tests it slows ! 680: * us down not speeds us up] ! 681: */ ! 682: #ifdef XMIT_EVERY ! 683: dev_transmit(); ! 684: #endif ! 685: cli(); ! 686: } /* End of queue loop */ ! 687: ! 688: /* ! 689: * We have emptied the queue ! 690: */ ! 691: ! 692: in_bh = 0; ! 693: sti(); ! 694: ! 695: /* ! 696: * One last output flush. ! 697: */ ! 698: ! 699: #ifdef XMIT_AFTER ! 700: dev_transmit(); ! 701: #endif ! 702: } ! 703: ! 704: ! 705: /* ! 706: * This routine is called when an device driver (i.e. an ! 707: * interface) is ready to transmit a packet. ! 708: */ ! 709: ! 710: void dev_tint(struct device *dev) ! 711: { ! 712: int i; ! 713: unsigned long flags; ! 714: struct sk_buff_head * head; ! 715: ! 716: /* ! 717: * aliases do not transmit (for now :) ) ! 718: */ ! 719: ! 720: #ifdef CONFIG_NET_ALIAS ! 721: if (net_alias_is(dev)) return; ! 722: #endif ! 723: head = dev->buffs; ! 724: save_flags(flags); ! 725: cli(); ! 726: ! 727: /* ! 728: * Work the queues in priority order ! 729: */ ! 730: for(i = 0;i < DEV_NUMBUFFS; i++,head++) ! 731: { ! 732: struct sk_buff *skb = skb_peek(head); ! 733: ! 734: if (skb) { ! 735: __skb_unlink(skb, head); ! 736: /* ! 737: * Stop anyone freeing the buffer while we retransmit it ! 738: */ ! 739: skb_device_lock(skb); ! 740: restore_flags(flags); ! 741: /* ! 742: * Feed them to the output stage and if it fails ! 743: * indicate they re-queue at the front. ! 744: */ ! 745: dev_queue_xmit(skb,dev,-i - 1); ! 746: /* ! 747: * If we can take no more then stop here. ! 748: */ ! 749: if (dev->tbusy) ! 750: return; ! 751: cli(); ! 752: } ! 753: } ! 754: restore_flags(flags); ! 755: } ! 756: ! 757: ! 758: /* ! 759: * Perform a SIOCGIFCONF call. This structure will change ! 760: * size shortly, and there is nothing I can do about it. ! 761: * Thus we will need a 'compatibility mode'. ! 762: */ ! 763: ! 764: static int dev_ifconf(char *arg) ! 765: { ! 766: struct ifconf ifc; ! 767: struct ifreq ifr; ! 768: struct device *dev; ! 769: char *pos; ! 770: int len; ! 771: int err; ! 772: ! 773: /* ! 774: * Fetch the caller's info block. ! 775: */ ! 776: ! 777: err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf)); ! 778: if(err) ! 779: return err; ! 780: memcpy_fromfs(&ifc, arg, sizeof(struct ifconf)); ! 781: len = ifc.ifc_len; ! 782: pos = ifc.ifc_buf; ! 783: ! 784: /* ! 785: * We now walk the device list filling each active device ! 786: * into the array. ! 787: */ ! 788: ! 789: err=verify_area(VERIFY_WRITE,pos,len); ! 790: if(err) ! 791: return err; ! 792: ! 793: /* ! 794: * Loop over the interfaces, and write an info block for each. ! 795: */ ! 796: ! 797: for (dev = dev_base; dev != NULL; dev = dev->next) ! 798: { ! 799: if(!(dev->flags & IFF_UP)) /* Downed devices don't count */ ! 800: continue; ! 801: /* ! 802: * Have we run out of space here ? ! 803: */ ! 804: ! 805: if (len < sizeof(struct ifreq)) ! 806: break; ! 807: ! 808: memset(&ifr, 0, sizeof(struct ifreq)); ! 809: strcpy(ifr.ifr_name, dev->name); ! 810: (*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family; ! 811: (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; ! 812: ! 813: ! 814: /* ! 815: * Write this block to the caller's space. ! 816: */ ! 817: ! 818: memcpy_tofs(pos, &ifr, sizeof(struct ifreq)); ! 819: pos += sizeof(struct ifreq); ! 820: len -= sizeof(struct ifreq); ! 821: } ! 822: ! 823: /* ! 824: * All done. Write the updated control block back to the caller. ! 825: */ ! 826: ! 827: ifc.ifc_len = (pos - ifc.ifc_buf); ! 828: ifc.ifc_req = (struct ifreq *) ifc.ifc_buf; ! 829: memcpy_tofs(arg, &ifc, sizeof(struct ifconf)); ! 830: ! 831: /* ! 832: * Report how much was filled in ! 833: */ ! 834: ! 835: return(pos - arg); ! 836: } ! 837: ! 838: ! 839: /* ! 840: * This is invoked by the /proc filesystem handler to display a device ! 841: * in detail. ! 842: */ ! 843: ! 844: #ifdef CONFIG_PROC_FS ! 845: static int sprintf_stats(char *buffer, struct device *dev) ! 846: { ! 847: struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL); ! 848: int size; ! 849: ! 850: if (stats) ! 851: size = sprintf(buffer, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n", ! 852: dev->name, ! 853: stats->rx_packets, stats->rx_errors, ! 854: stats->rx_dropped + stats->rx_missed_errors, ! 855: stats->rx_fifo_errors, ! 856: stats->rx_length_errors + stats->rx_over_errors ! 857: + stats->rx_crc_errors + stats->rx_frame_errors, ! 858: stats->tx_packets, stats->tx_errors, stats->tx_dropped, ! 859: stats->tx_fifo_errors, stats->collisions, ! 860: stats->tx_carrier_errors + stats->tx_aborted_errors ! 861: + stats->tx_window_errors + stats->tx_heartbeat_errors); ! 862: else ! 863: size = sprintf(buffer, "%6s: No statistics available.\n", dev->name); ! 864: ! 865: return size; ! 866: } ! 867: ! 868: /* ! 869: * Called from the PROCfs module. This now uses the new arbitrary sized /proc/net interface ! 870: * to create /proc/net/dev ! 871: */ ! 872: ! 873: int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy) ! 874: { ! 875: int len=0; ! 876: off_t begin=0; ! 877: off_t pos=0; ! 878: int size; ! 879: ! 880: struct device *dev; ! 881: ! 882: ! 883: size = sprintf(buffer, "Inter-| Receive | Transmit\n" ! 884: " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n"); ! 885: ! 886: pos+=size; ! 887: len+=size; ! 888: ! 889: ! 890: for (dev = dev_base; dev != NULL; dev = dev->next) ! 891: { ! 892: size = sprintf_stats(buffer+len, dev); ! 893: len+=size; ! 894: pos=begin+len; ! 895: ! 896: if(pos<offset) ! 897: { ! 898: len=0; ! 899: begin=pos; ! 900: } ! 901: if(pos>offset+length) ! 902: break; ! 903: } ! 904: ! 905: *start=buffer+(offset-begin); /* Start of wanted data */ ! 906: len-=(offset-begin); /* Start slop */ ! 907: if(len>length) ! 908: len=length; /* Ending slop */ ! 909: return len; ! 910: } ! 911: #endif /* CONFIG_PROC_FS */ ! 912: ! 913: ! 914: /* ! 915: * This checks bitmasks for the ioctl calls for devices. ! 916: */ ! 917: ! 918: static inline int bad_mask(unsigned long mask, unsigned long addr) ! 919: { ! 920: if (addr & (mask = ~mask)) ! 921: return 1; ! 922: mask = ntohl(mask); ! 923: if (mask & (mask+1)) ! 924: return 1; ! 925: return 0; ! 926: } ! 927: ! 928: /* ! 929: * Perform the SIOCxIFxxx calls. ! 930: * ! 931: * The socket layer has seen an ioctl the address family thinks is ! 932: * for the device. At this point we get invoked to make a decision ! 933: */ ! 934: ! 935: static int dev_ifsioc(void *arg, unsigned int getset) ! 936: { ! 937: struct ifreq ifr; ! 938: struct device *dev; ! 939: int ret; ! 940: ! 941: /* ! 942: * Fetch the caller's info block into kernel space ! 943: */ ! 944: ! 945: int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq)); ! 946: if(err) ! 947: return err; ! 948: ! 949: memcpy_fromfs(&ifr, arg, sizeof(struct ifreq)); ! 950: ! 951: /* ! 952: * See which interface the caller is talking about. ! 953: */ ! 954: ! 955: /* ! 956: * ! 957: * net_alias_dev_get(): dev_get() with added alias naming magic. ! 958: * only allow alias creation/deletion if (getset==SIOCSIFADDR) ! 959: * ! 960: */ ! 961: ! 962: #ifdef CONFIG_KERNELD ! 963: dev_load(ifr.ifr_name); ! 964: #endif ! 965: ! 966: #ifdef CONFIG_NET_ALIAS ! 967: if ((dev = net_alias_dev_get(ifr.ifr_name, getset == SIOCSIFADDR, &err, NULL, NULL)) == NULL) ! 968: return(err); ! 969: #else ! 970: if ((dev = dev_get(ifr.ifr_name)) == NULL) ! 971: return(-ENODEV); ! 972: #endif ! 973: switch(getset) ! 974: { ! 975: case SIOCGIFFLAGS: /* Get interface flags */ ! 976: ifr.ifr_flags = dev->flags; ! 977: goto rarok; ! 978: ! 979: case SIOCSIFFLAGS: /* Set interface flags */ ! 980: { ! 981: int old_flags = dev->flags; ! 982: ! 983: /* ! 984: * We are not allowed to potentially close/unload ! 985: * a device until we get this lock. ! 986: */ ! 987: ! 988: dev_lock_wait(); ! 989: ! 990: /* ! 991: * Set the flags on our device. ! 992: */ ! 993: ! 994: dev->flags = (ifr.ifr_flags & ( ! 995: IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK | ! 996: IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING | ! 997: IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI | IFF_SLAVE | IFF_MASTER ! 998: | IFF_MULTICAST)) | (dev->flags & IFF_UP); ! 999: /* ! 1000: * Load in the correct multicast list now the flags have changed. ! 1001: */ ! 1002: ! 1003: dev_mc_upload(dev); ! 1004: ! 1005: /* ! 1006: * Have we downed the interface. We handle IFF_UP ourselves ! 1007: * according to user attempts to set it, rather than blindly ! 1008: * setting it. ! 1009: */ ! 1010: ! 1011: if ((old_flags^ifr.ifr_flags)&IFF_UP) /* Bit is different ? */ ! 1012: { ! 1013: if(old_flags&IFF_UP) /* Gone down */ ! 1014: ret=dev_close(dev); ! 1015: else /* Come up */ ! 1016: { ! 1017: ret=dev_open(dev); ! 1018: if(ret<0) ! 1019: dev->flags&=~IFF_UP; /* Open failed */ ! 1020: } ! 1021: } ! 1022: else ! 1023: ret=0; ! 1024: /* ! 1025: * Load in the correct multicast list now the flags have changed. ! 1026: */ ! 1027: ! 1028: dev_mc_upload(dev); ! 1029: } ! 1030: break; ! 1031: ! 1032: case SIOCGIFADDR: /* Get interface address (and family) */ ! 1033: if(ifr.ifr_addr.sa_family==AF_UNSPEC) ! 1034: { ! 1035: memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); ! 1036: ifr.ifr_hwaddr.sa_family=dev->type; ! 1037: goto rarok; ! 1038: } ! 1039: else ! 1040: { ! 1041: (*(struct sockaddr_in *) ! 1042: &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; ! 1043: (*(struct sockaddr_in *) ! 1044: &ifr.ifr_addr).sin_family = dev->family; ! 1045: (*(struct sockaddr_in *) ! 1046: &ifr.ifr_addr).sin_port = 0; ! 1047: } ! 1048: goto rarok; ! 1049: ! 1050: case SIOCSIFADDR: /* Set interface address (and family) */ ! 1051: ! 1052: /* ! 1053: * BSDism. SIOCSIFADDR family=AF_UNSPEC sets the ! 1054: * physical address. We can cope with this now. ! 1055: */ ! 1056: ! 1057: if(ifr.ifr_addr.sa_family==AF_UNSPEC) ! 1058: { ! 1059: if(dev->set_mac_address==NULL) ! 1060: return -EOPNOTSUPP; ! 1061: ret=dev->set_mac_address(dev,&ifr.ifr_addr); ! 1062: } ! 1063: else ! 1064: { ! 1065: ! 1066: /* ! 1067: * if dev is an alias, must rehash to update ! 1068: * address change ! 1069: */ ! 1070: ! 1071: #ifdef CONFIG_NET_ALIAS ! 1072: if (net_alias_is(dev)) ! 1073: net_alias_dev_rehash(dev ,&ifr.ifr_addr); ! 1074: #endif ! 1075: dev->pa_addr = (*(struct sockaddr_in *) ! 1076: &ifr.ifr_addr).sin_addr.s_addr; ! 1077: dev->family = ifr.ifr_addr.sa_family; ! 1078: ! 1079: #ifdef CONFIG_INET ! 1080: /* This is naughty. When net-032e comes out It wants moving into the net032 ! 1081: code not the kernel. Till then it can sit here (SIGH) */ ! 1082: dev->pa_mask = ip_get_mask(dev->pa_addr); ! 1083: #endif ! 1084: dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; ! 1085: ret = 0; ! 1086: } ! 1087: break; ! 1088: ! 1089: case SIOCGIFBRDADDR: /* Get the broadcast address */ ! 1090: (*(struct sockaddr_in *) ! 1091: &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr; ! 1092: (*(struct sockaddr_in *) ! 1093: &ifr.ifr_broadaddr).sin_family = dev->family; ! 1094: (*(struct sockaddr_in *) ! 1095: &ifr.ifr_broadaddr).sin_port = 0; ! 1096: goto rarok; ! 1097: ! 1098: case SIOCSIFBRDADDR: /* Set the broadcast address */ ! 1099: dev->pa_brdaddr = (*(struct sockaddr_in *) ! 1100: &ifr.ifr_broadaddr).sin_addr.s_addr; ! 1101: ret = 0; ! 1102: break; ! 1103: ! 1104: case SIOCGIFDSTADDR: /* Get the destination address (for point-to-point links) */ ! 1105: (*(struct sockaddr_in *) ! 1106: &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr; ! 1107: (*(struct sockaddr_in *) ! 1108: &ifr.ifr_dstaddr).sin_family = dev->family; ! 1109: (*(struct sockaddr_in *) ! 1110: &ifr.ifr_dstaddr).sin_port = 0; ! 1111: goto rarok; ! 1112: ! 1113: case SIOCSIFDSTADDR: /* Set the destination address (for point-to-point links) */ ! 1114: dev->pa_dstaddr = (*(struct sockaddr_in *) ! 1115: &ifr.ifr_dstaddr).sin_addr.s_addr; ! 1116: ret = 0; ! 1117: break; ! 1118: ! 1119: case SIOCGIFNETMASK: /* Get the netmask for the interface */ ! 1120: (*(struct sockaddr_in *) ! 1121: &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask; ! 1122: (*(struct sockaddr_in *) ! 1123: &ifr.ifr_netmask).sin_family = dev->family; ! 1124: (*(struct sockaddr_in *) ! 1125: &ifr.ifr_netmask).sin_port = 0; ! 1126: goto rarok; ! 1127: ! 1128: case SIOCSIFNETMASK: /* Set the netmask for the interface */ ! 1129: { ! 1130: unsigned long mask = (*(struct sockaddr_in *) ! 1131: &ifr.ifr_netmask).sin_addr.s_addr; ! 1132: ret = -EINVAL; ! 1133: /* ! 1134: * The mask we set must be legal. ! 1135: */ ! 1136: if (bad_mask(mask,0)) ! 1137: break; ! 1138: dev->pa_mask = mask; ! 1139: ret = 0; ! 1140: } ! 1141: break; ! 1142: ! 1143: case SIOCGIFMETRIC: /* Get the metric on the interface (currently unused) */ ! 1144: ! 1145: ifr.ifr_metric = dev->metric; ! 1146: goto rarok; ! 1147: ! 1148: case SIOCSIFMETRIC: /* Set the metric on the interface (currently unused) */ ! 1149: dev->metric = ifr.ifr_metric; ! 1150: ret=0; ! 1151: break; ! 1152: ! 1153: case SIOCGIFMTU: /* Get the MTU of a device */ ! 1154: ifr.ifr_mtu = dev->mtu; ! 1155: goto rarok; ! 1156: ! 1157: case SIOCSIFMTU: /* Set the MTU of a device */ ! 1158: ! 1159: /* ! 1160: * MTU must be positive. ! 1161: */ ! 1162: ! 1163: if(ifr.ifr_mtu<68) ! 1164: return -EINVAL; ! 1165: dev->mtu = ifr.ifr_mtu; ! 1166: ret = 0; ! 1167: break; ! 1168: ! 1169: case SIOCGIFMEM: /* Get the per device memory space. We can add this but currently ! 1170: do not support it */ ! 1171: ret = -EINVAL; ! 1172: break; ! 1173: ! 1174: case SIOCSIFMEM: /* Set the per device memory buffer space. Not applicable in our case */ ! 1175: ret = -EINVAL; ! 1176: break; ! 1177: ! 1178: case SIOCGIFHWADDR: ! 1179: memcpy(ifr.ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN); ! 1180: ifr.ifr_hwaddr.sa_family=dev->type; ! 1181: goto rarok; ! 1182: ! 1183: case SIOCSIFHWADDR: ! 1184: if(dev->set_mac_address==NULL) ! 1185: return -EOPNOTSUPP; ! 1186: if(ifr.ifr_hwaddr.sa_family!=dev->type) ! 1187: return -EINVAL; ! 1188: ret=dev->set_mac_address(dev,&ifr.ifr_hwaddr); ! 1189: break; ! 1190: ! 1191: case SIOCGIFMAP: ! 1192: ifr.ifr_map.mem_start=dev->mem_start; ! 1193: ifr.ifr_map.mem_end=dev->mem_end; ! 1194: ifr.ifr_map.base_addr=dev->base_addr; ! 1195: ifr.ifr_map.irq=dev->irq; ! 1196: ifr.ifr_map.dma=dev->dma; ! 1197: ifr.ifr_map.port=dev->if_port; ! 1198: goto rarok; ! 1199: ! 1200: case SIOCSIFMAP: ! 1201: if(dev->set_config==NULL) ! 1202: return -EOPNOTSUPP; ! 1203: return dev->set_config(dev,&ifr.ifr_map); ! 1204: ! 1205: case SIOCADDMULTI: ! 1206: if(dev->set_multicast_list==NULL) ! 1207: return -EINVAL; ! 1208: if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC) ! 1209: return -EINVAL; ! 1210: dev_mc_add(dev,ifr.ifr_hwaddr.sa_data, dev->addr_len, 1); ! 1211: return 0; ! 1212: ! 1213: case SIOCDELMULTI: ! 1214: if(dev->set_multicast_list==NULL) ! 1215: return -EINVAL; ! 1216: if(ifr.ifr_hwaddr.sa_family!=AF_UNSPEC) ! 1217: return -EINVAL; ! 1218: dev_mc_delete(dev,ifr.ifr_hwaddr.sa_data,dev->addr_len, 1); ! 1219: return 0; ! 1220: /* ! 1221: * Unknown or private ioctl ! 1222: */ ! 1223: ! 1224: default: ! 1225: if((getset >= SIOCDEVPRIVATE) && ! 1226: (getset <= (SIOCDEVPRIVATE + 15))) { ! 1227: if(dev->do_ioctl==NULL) ! 1228: return -EOPNOTSUPP; ! 1229: ret=dev->do_ioctl(dev, &ifr, getset); ! 1230: memcpy_tofs(arg,&ifr,sizeof(struct ifreq)); ! 1231: break; ! 1232: } ! 1233: ! 1234: ret = -EINVAL; ! 1235: } ! 1236: return(ret); ! 1237: /* ! 1238: * The load of calls that return an ifreq and ok (saves memory). ! 1239: */ ! 1240: rarok: ! 1241: memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); ! 1242: return 0; ! 1243: } ! 1244: ! 1245: ! 1246: /* ! 1247: * This function handles all "interface"-type I/O control requests. The actual ! 1248: * 'doing' part of this is dev_ifsioc above. ! 1249: */ ! 1250: ! 1251: int dev_ioctl(unsigned int cmd, void *arg) ! 1252: { ! 1253: switch(cmd) ! 1254: { ! 1255: case SIOCGIFCONF: ! 1256: (void) dev_ifconf((char *) arg); ! 1257: return 0; ! 1258: ! 1259: /* ! 1260: * Ioctl calls that can be done by all. ! 1261: */ ! 1262: ! 1263: case SIOCGIFFLAGS: ! 1264: case SIOCGIFADDR: ! 1265: case SIOCGIFDSTADDR: ! 1266: case SIOCGIFBRDADDR: ! 1267: case SIOCGIFNETMASK: ! 1268: case SIOCGIFMETRIC: ! 1269: case SIOCGIFMTU: ! 1270: case SIOCGIFMEM: ! 1271: case SIOCGIFHWADDR: ! 1272: case SIOCSIFHWADDR: ! 1273: case SIOCGIFSLAVE: ! 1274: case SIOCGIFMAP: ! 1275: return dev_ifsioc(arg, cmd); ! 1276: ! 1277: /* ! 1278: * Ioctl calls requiring the power of a superuser ! 1279: */ ! 1280: ! 1281: case SIOCSIFFLAGS: ! 1282: case SIOCSIFADDR: ! 1283: case SIOCSIFDSTADDR: ! 1284: case SIOCSIFBRDADDR: ! 1285: case SIOCSIFNETMASK: ! 1286: case SIOCSIFMETRIC: ! 1287: case SIOCSIFMTU: ! 1288: case SIOCSIFMEM: ! 1289: case SIOCSIFMAP: ! 1290: case SIOCSIFSLAVE: ! 1291: case SIOCADDMULTI: ! 1292: case SIOCDELMULTI: ! 1293: if (!suser()) ! 1294: return -EPERM; ! 1295: return dev_ifsioc(arg, cmd); ! 1296: ! 1297: case SIOCSIFLINK: ! 1298: return -EINVAL; ! 1299: ! 1300: /* ! 1301: * Unknown or private ioctl. ! 1302: */ ! 1303: ! 1304: default: ! 1305: if((cmd >= SIOCDEVPRIVATE) && ! 1306: (cmd <= (SIOCDEVPRIVATE + 15))) { ! 1307: return dev_ifsioc(arg, cmd); ! 1308: } ! 1309: return -EINVAL; ! 1310: } ! 1311: } ! 1312: #endif /* ! MACH */ ! 1313: ! 1314: /* ! 1315: * Initialize the DEV module. At boot time this walks the device list and ! 1316: * unhooks any devices that fail to initialise (normally hardware not ! 1317: * present) and leaves us with a valid list of present and active devices. ! 1318: * ! 1319: */ ! 1320: extern int lance_init(void); ! 1321: extern int pi_init(void); ! 1322: extern int dec21040_init(void); ! 1323: ! 1324: int net_dev_init(void) ! 1325: { ! 1326: struct device *dev, **dp; ! 1327: ! 1328: #ifndef MACH ! 1329: /* ! 1330: * Initialise the packet receive queue. ! 1331: */ ! 1332: ! 1333: skb_queue_head_init(&backlog); ! 1334: #endif ! 1335: ! 1336: /* ! 1337: * This is VeryUgly(tm). ! 1338: * ! 1339: * Some devices want to be initialized eary.. ! 1340: */ ! 1341: #if defined(CONFIG_LANCE) ! 1342: lance_init(); ! 1343: #endif ! 1344: #if defined(CONFIG_PI) ! 1345: pi_init(); ! 1346: #endif ! 1347: #if defined(CONFIG_PT) ! 1348: pt_init(); ! 1349: #endif ! 1350: #if defined(CONFIG_DEC_ELCP) ! 1351: dec21040_init(); ! 1352: #endif ! 1353: /* ! 1354: * SLHC if present needs attaching so other people see it ! 1355: * even if not opened. ! 1356: */ ! 1357: #if (defined(CONFIG_SLIP_COMPRESSED) || defined(CONFIG_PPP)) && defined(CONFIG_SLHC_BUILTIN) ! 1358: slhc_install(); ! 1359: #endif ! 1360: ! 1361: /* ! 1362: * Add the devices. ! 1363: * If the call to dev->init fails, the dev is removed ! 1364: * from the chain disconnecting the device until the ! 1365: * next reboot. ! 1366: */ ! 1367: ! 1368: dp = &dev_base; ! 1369: while ((dev = *dp) != NULL) ! 1370: { ! 1371: int i; ! 1372: for (i = 0; i < DEV_NUMBUFFS; i++) { ! 1373: skb_queue_head_init(dev->buffs + i); ! 1374: } ! 1375: ! 1376: if (dev->init && dev->init(dev)) ! 1377: { ! 1378: /* ! 1379: * It failed to come up. Unhook it. ! 1380: */ ! 1381: *dp = dev->next; ! 1382: } ! 1383: else ! 1384: { ! 1385: dp = &dev->next; ! 1386: } ! 1387: } ! 1388: ! 1389: #ifdef CONFIG_PROC_FS ! 1390: proc_net_register(&(struct proc_dir_entry) { ! 1391: PROC_NET_DEV, 3, "dev", ! 1392: S_IFREG | S_IRUGO, 1, 0, 0, ! 1393: 0, &proc_net_inode_operations, ! 1394: dev_get_info ! 1395: }); ! 1396: #endif ! 1397: ! 1398: /* ! 1399: * Initialise net_alias engine ! 1400: * ! 1401: * - register net_alias device notifier ! 1402: * - register proc entries: /proc/net/alias_types ! 1403: * /proc/net/aliases ! 1404: */ ! 1405: ! 1406: #ifdef CONFIG_NET_ALIAS ! 1407: net_alias_init(); ! 1408: #endif ! 1409: ! 1410: bh_base[NET_BH].routine = net_bh; ! 1411: enable_bh(NET_BH); ! 1412: return 0; ! 1413: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.