Annotation of Gnu-Mach/i386/i386at/gpl/linux/linux_net.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Linux network driver support.
                      3:  *
                      4:  * Copyright (C) 1996 The University of Utah and the Computer Systems
                      5:  * Laboratory at the University of Utah (CSL)
                      6:  *
                      7:  * This program is free software; you can redistribute it and/or modify
                      8:  * it under the terms of the GNU General Public License as published by
                      9:  * the Free Software Foundation; either version 2, or (at your option)
                     10:  * any later version.
                     11:  *
                     12:  * This program is distributed in the hope that it will be useful,
                     13:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     15:  * GNU General Public License for more details.
                     16:  *
                     17:  * You should have received a copy of the GNU General Public License
                     18:  * along with this program; if not, write to the Free Software
                     19:  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
                     20:  *
                     21:  *      Author: Shantanu Goel, University of Utah CSL
                     22:  */
                     23: 
                     24: /*
                     25:  * INET                An implementation of the TCP/IP protocol suite for the LINUX
                     26:  *             operating system.  INET is implemented using the  BSD Socket
                     27:  *             interface as the means of communication with the user level.
                     28:  *
                     29:  *             Ethernet-type device handling.
                     30:  *
                     31:  * Version:    @(#)eth.c       1.0.7   05/25/93
                     32:  *
                     33:  * Authors:    Ross Biro, <[email protected]>
                     34:  *             Fred N. van Kempen, <[email protected]>
                     35:  *             Mark Evans, <[email protected]>
                     36:  *             Florian  La Roche, <[email protected]>
                     37:  *             Alan Cox, <[email protected]>
                     38:  * 
                     39:  * Fixes:
                     40:  *             Mr Linux        : Arp problems
                     41:  *             Alan Cox        : Generic queue tidyup (very tiny here)
                     42:  *             Alan Cox        : eth_header ntohs should be htons
                     43:  *             Alan Cox        : eth_rebuild_header missing an htons and
                     44:  *                               minor other things.
                     45:  *             Tegge           : Arp bug fixes. 
                     46:  *             Florian         : Removed many unnecessary functions, code cleanup
                     47:  *                               and changes for new arp and skbuff.
                     48:  *             Alan Cox        : Redid header building to reflect new format.
                     49:  *             Alan Cox        : ARP only when compiled with CONFIG_INET
                     50:  *             Greg Page       : 802.2 and SNAP stuff.
                     51:  *             Alan Cox        : MAC layer pointers/new format.
                     52:  *             Paul Gortmaker  : eth_copy_and_sum shouldn't csum padding.
                     53:  *             Alan Cox        : Protect against forwarding explosions with
                     54:  *                               older network drivers and IFF_ALLMULTI
                     55:  *
                     56:  *             This program is free software; you can redistribute it and/or
                     57:  *             modify it under the terms of the GNU General Public License
                     58:  *             as published by the Free Software Foundation; either version
                     59:  *             2 of the License, or (at your option) any later version.
                     60:  */
                     61: 
                     62: #include <sys/types.h>
                     63: 
                     64: #include <mach/mach_types.h>
                     65: #include <mach/kern_return.h>
                     66: #include <mach/mig_errors.h>
                     67: #include <mach/port.h>
                     68: #include <mach/vm_param.h>
                     69: #include <mach/notify.h>
                     70: 
                     71: #include <ipc/ipc_port.h>
                     72: #include <ipc/ipc_space.h>
                     73: 
                     74: #include <vm/vm_map.h>
                     75: #include <vm/vm_kern.h>
                     76: #include <vm/vm_page.h>
                     77: 
                     78: #include <device/device_types.h>
                     79: #include <device/device_port.h>
                     80: #include <device/if_hdr.h>
                     81: #include <device/if_ether.h>
                     82: #include <device/if_hdr.h>
                     83: #include <device/net_io.h>
                     84: #include "device_reply.h"
                     85: 
                     86: #include <i386at/dev_hdr.h>
                     87: #include <i386at/device_emul.h>
                     88: 
                     89: #include <i386at/gpl/linux/linux_emul.h>
                     90: 
                     91: #define MACH_INCLUDE
                     92: #include <linux/kernel.h>
                     93: #include <linux/sched.h>
                     94: #include <linux/string.h>
                     95: #include <linux/errno.h>
                     96: #include <linux/delay.h>
                     97: #include <linux/interrupt.h>
                     98: #include <linux/malloc.h>
                     99: #include <linux/netdevice.h>
                    100: #include <linux/etherdevice.h>
                    101: 
                    102: /* One of these is associated with each instance of a device.  */
                    103: struct net_data
                    104: {
                    105:   ipc_port_t port;             /* device port */
                    106:   struct ifnet ifnet;          /* Mach ifnet structure (needed for filters) */
                    107:   struct device device;                /* generic device structure */
                    108:   struct linux_device *dev;    /* Linux network device structure */
                    109: };
                    110: 
                    111: /* List of sk_buffs waiting to be freed.  */
                    112: static struct sk_buff_head skb_done_list;
                    113: 
                    114: /* Forward declarations.  */
                    115: 
                    116: extern struct device_emulation_ops linux_net_emulation_ops;
                    117: 
                    118: static int print_packet_size = 0;
                    119: 
                    120: /* Linux kernel network support routines.  */
                    121: 
                    122: /* Requeue packet SKB for transmission after the interface DEV
                    123:    has timed out.  The priority of the packet is PRI.
                    124:    In Mach, we simply drop the packet like the native drivers.  */
                    125: void
                    126: dev_queue_xmit (struct sk_buff *skb, struct linux_device *dev, int pri)
                    127: {
                    128:   dev_kfree_skb (skb, FREE_WRITE);
                    129: }
                    130: 
                    131: /* Close the device DEV.  */
                    132: int
                    133: dev_close (struct linux_device *dev)
                    134: {
                    135:   return 0;
                    136: }
                    137: 
                    138: /* Network software interrupt handler.  */
                    139: void
                    140: net_bh (void *xxx)
                    141: {
                    142:   int len;
                    143:   struct sk_buff *skb;
                    144:   struct linux_device *dev;
                    145: 
                    146:   /* Start transmission on interfaces.  */
                    147:   for (dev = dev_base; dev; dev = dev->next)
                    148:     {
                    149:       if (dev->base_addr && dev->base_addr != 0xffe0)
                    150:        while (1)
                    151:          {
                    152:            skb = skb_dequeue (&dev->buffs[0]);
                    153:            if (skb)
                    154:              {
                    155:                len = skb->len;
                    156:                if ((*dev->hard_start_xmit) (skb, dev))
                    157:                  {
                    158:                    skb_queue_head (&dev->buffs[0], skb);
                    159:                    mark_bh (NET_BH);
                    160:                    break;
                    161:                  }
                    162:                else if (print_packet_size)
                    163:                  printf ("net_bh: length %d\n", len);
                    164:              }
                    165:            else
                    166:              break;
                    167:          }
                    168:     }
                    169: }
                    170: 
                    171: /* Free all sk_buffs on the done list.
                    172:    This routine is called by the iodone thread in ds_routines.c.  */
                    173: void
                    174: free_skbuffs ()
                    175: {
                    176:   struct sk_buff *skb;
                    177: 
                    178:   while (1)
                    179:     {
                    180:       skb = skb_dequeue (&skb_done_list);
                    181:       if (skb)
                    182:        {
                    183:          if (skb->copy)
                    184:            {
                    185:              vm_map_copy_discard (skb->copy);
                    186:              skb->copy = NULL;
                    187:            }
                    188:          if (IP_VALID (skb->reply))
                    189:            {
                    190:              ds_device_write_reply (skb->reply, skb->reply_type, 0, skb->len);
                    191:              skb->reply = IP_NULL;
                    192:            }
                    193:          dev_kfree_skb (skb, FREE_WRITE);
                    194:        }
                    195:       else
                    196:        break;
                    197:     }
                    198: }
                    199: 
                    200: /* Allocate an sk_buff with SIZE bytes of data space.  */
                    201: struct sk_buff *
                    202: alloc_skb (unsigned int size, int priority)
                    203: {
                    204:   return dev_alloc_skb (size);
                    205: }
                    206: 
                    207: /* Free SKB.  */
                    208: void
                    209: kfree_skb (struct sk_buff *skb, int priority)
                    210: {
                    211:   dev_kfree_skb (skb, priority);
                    212: }
                    213: 
                    214: /* Allocate an sk_buff with SIZE bytes of data space.  */
                    215: struct sk_buff *
                    216: dev_alloc_skb (unsigned int size)
                    217: {
                    218:   struct sk_buff *skb;
                    219: 
                    220:   skb = linux_kmalloc (sizeof (struct sk_buff) + size, GFP_KERNEL);
                    221:   if (skb)
                    222:     {
                    223:       skb->dev = NULL;
                    224:       skb->reply = IP_NULL;
                    225:       skb->copy = NULL;
                    226:       skb->len = size;
                    227:       skb->prev = skb->next = NULL;
                    228:       skb->list = NULL;
                    229:       if (size)
                    230:        {
                    231:          skb->data = (unsigned char *) (skb + 1);
                    232:          skb->tail = skb->data + size;
                    233:        }
                    234:       else
                    235:        skb->data = skb->tail = NULL;
                    236:       skb->head = skb->data;
                    237:     }
                    238:   return skb;
                    239: }
                    240: 
                    241: /* Free the sk_buff SKB.  */
                    242: void
                    243: dev_kfree_skb (struct sk_buff *skb, int mode)
                    244: {
                    245:   unsigned flags;
                    246:   extern void *io_done_list;
                    247: 
                    248:   /* Queue sk_buff on done list if there is a
                    249:      page list attached or we need to send a reply.
                    250:      Wakeup the iodone thread to process the list.  */
                    251:   if (skb->copy || IP_VALID (skb->reply))
                    252:     {
                    253:       skb_queue_tail (&skb_done_list, skb);
                    254:       save_flags (flags);
                    255:       thread_wakeup ((event_t) &io_done_list);
                    256:       restore_flags (flags);
                    257:       return;
                    258:     }
                    259:   linux_kfree (skb);
                    260: }
                    261: 
                    262: /* Accept packet SKB received on an interface.  */
                    263: void
                    264: netif_rx (struct sk_buff *skb)
                    265: {
                    266:   ipc_kmsg_t kmsg;
                    267:   struct ether_header *eh;
                    268:   struct packet_header *ph;
                    269:   struct linux_device *dev = skb->dev;
                    270: 
                    271:   assert (skb != NULL);
                    272: 
                    273:   if (print_packet_size)
                    274:     printf ("netif_rx: length %d\n", skb->len);
                    275: 
                    276:   /* Allocate a kernel message buffer.  */
                    277:   kmsg = net_kmsg_get ();
                    278:   if (! kmsg)
                    279:     {
                    280:       dev_kfree_skb (skb, FREE_READ);
                    281:       return;
                    282:     }
                    283: 
                    284:   /* Copy packet into message buffer.  */
                    285:   eh = (struct ether_header *) (net_kmsg (kmsg)->header);
                    286:   ph = (struct packet_header *) (net_kmsg (kmsg)->packet);
                    287:   memcpy (eh, skb->data, sizeof (struct ether_header));
                    288:   memcpy (ph + 1, skb->data + sizeof (struct ether_header),
                    289:          skb->len - sizeof (struct ether_header));
                    290:   ph->type = eh->ether_type;
                    291:   ph->length = (skb->len - sizeof (struct ether_header)
                    292:                + sizeof (struct packet_header));
                    293: 
                    294:   dev_kfree_skb (skb, FREE_READ);
                    295: 
                    296:   /* Pass packet up to the microkernel.  */
                    297:   net_packet (&dev->net_data->ifnet, kmsg,
                    298:              ph->length, ethernet_priority (kmsg));
                    299: }
                    300: 
                    301: /* Mach device interface routines.  */
                    302: 
                    303: /* Return a send right associated with network device ND.  */
                    304: static ipc_port_t
                    305: dev_to_port (void *nd)
                    306: {
                    307:   return (nd
                    308:          ? ipc_port_make_send (((struct net_data *) nd)->port)
                    309:          : IP_NULL);
                    310: }
                    311: 
                    312: static io_return_t
                    313: device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
                    314:             dev_mode_t mode, char *name, device_t *devp)
                    315: {
                    316:   io_return_t err = D_SUCCESS;
                    317:   ipc_port_t notify;
                    318:   struct ifnet *ifp;
                    319:   struct linux_device *dev;
                    320:   struct net_data *nd;
                    321: 
                    322:   /* Search for the device.  */
                    323:   for (dev = dev_base; dev; dev = dev->next)
                    324:     if (dev->base_addr
                    325:        && dev->base_addr != 0xffe0
                    326:        && ! strcmp (name, dev->name))
                    327:       break;
                    328:   if (! dev)
                    329:     return D_NO_SUCH_DEVICE;
                    330: 
                    331:   /* Allocate and initialize device data if this is the first open.  */
                    332:   nd = dev->net_data;
                    333:   if (! nd)
                    334:     {
                    335:       dev->net_data = nd = ((struct net_data *)
                    336:                            kalloc (sizeof (struct net_data)));
                    337:       if (! nd)
                    338:        {
                    339:          err = D_NO_MEMORY;
                    340:          goto out;
                    341:        }
                    342:       nd->dev = dev;
                    343:       nd->device.emul_data = nd;
                    344:       nd->device.emul_ops = &linux_net_emulation_ops;
                    345:       nd->port = ipc_port_alloc_kernel ();
                    346:       if (nd->port == IP_NULL)
                    347:        {
                    348:          err = KERN_RESOURCE_SHORTAGE;
                    349:          goto out;
                    350:        }
                    351:       ipc_kobject_set (nd->port, (ipc_kobject_t) &nd->device, IKOT_DEVICE);
                    352:       notify = ipc_port_make_sonce (nd->port);
                    353:       ip_lock (nd->port);
                    354:       ipc_port_nsrequest (nd->port, 1, notify, &notify);
                    355:       assert (notify == IP_NULL);
                    356:          
                    357:       ifp = &nd->ifnet;
                    358:       ifp->if_unit = dev->name[strlen (dev->name) - 1] - '0';
                    359:       ifp->if_flags = IFF_UP|IFF_RUNNING;
                    360:       ifp->if_mtu = dev->mtu;
                    361:       ifp->if_header_size = dev->hard_header_len;
                    362:       ifp->if_header_format = dev->type;
                    363:       ifp->if_address_size = dev->addr_len;
                    364:       ifp->if_address = dev->dev_addr;
                    365:       if_init_queues (ifp);
                    366: 
                    367:       if (dev->open)
                    368:        {
                    369:          linux_intr_pri = SPL6;
                    370:          if ((*dev->open) (dev))
                    371:            err = D_NO_SUCH_DEVICE;
                    372:        }
                    373: 
                    374:     out:
                    375:       if (err)
                    376:        {
                    377:          if (nd)
                    378:            {
                    379:              if (nd->port != IP_NULL)
                    380:                {
                    381:                  ipc_kobject_set (nd->port, IKO_NULL, IKOT_NONE);
                    382:                  ipc_port_dealloc_kernel (nd->port);
                    383:                }
                    384:              kfree ((vm_offset_t) nd, sizeof (struct net_data));
                    385:              nd = NULL;
                    386:              dev->net_data = NULL;
                    387:            }
                    388:        }
                    389:       else
                    390:        {
                    391:          dev->flags |= LINUX_IFF_UP|LINUX_IFF_RUNNING;
                    392:          skb_queue_head_init (&dev->buffs[0]);
                    393:        }
                    394:       if (IP_VALID (reply_port))
                    395:        ds_device_open_reply (reply_port, reply_port_type,
                    396:                              err, dev_to_port (nd));
                    397:       return MIG_NO_REPLY;
                    398:     }
                    399: 
                    400:   *devp = &nd->device;
                    401:   return D_SUCCESS;
                    402: }
                    403: 
                    404: static io_return_t
                    405: device_write (void *d, ipc_port_t reply_port,
                    406:              mach_msg_type_name_t reply_port_type, dev_mode_t mode,
                    407:              recnum_t bn, io_buf_ptr_t data, unsigned int count,
                    408:              int *bytes_written)
                    409: {
                    410:   unsigned char *p;
                    411:   int i, amt, skblen, s;
                    412:   io_return_t err = 0;
                    413:   vm_map_copy_t copy = (vm_map_copy_t) data;
                    414:   struct net_data *nd = d;
                    415:   struct linux_device *dev = nd->dev;
                    416:   struct sk_buff *skb;
                    417: 
                    418:   if (count == 0 || count > dev->mtu + dev->hard_header_len)
                    419:     return D_INVALID_SIZE;
                    420: 
                    421:   /* Allocate a sk_buff.  */
                    422:   amt = PAGE_SIZE - (copy->offset & PAGE_MASK);
                    423:   skblen = (amt >= count) ? 0 : count;
                    424:   skb = dev_alloc_skb (skblen);
                    425:   if (! skb)
                    426:     return D_NO_MEMORY;
                    427: 
                    428:   /* Copy user data.  This is only required if it spans multiple pages.  */
                    429:   if (skblen == 0)
                    430:     {
                    431:       assert (copy->cpy_npages == 1);
                    432: 
                    433:       skb->copy = copy;
                    434:       skb->data = ((void *) copy->cpy_page_list[0]->phys_addr
                    435:                   + (copy->offset & PAGE_MASK));
                    436:       skb->len = count;
                    437:       skb->head = skb->data;
                    438:       skb->tail = skb->data + skb->len;
                    439:     }
                    440:   else
                    441:     {
                    442:       memcpy (skb->data,
                    443:              ((void *) copy->cpy_page_list[0]->phys_addr
                    444:               + (copy->offset & PAGE_MASK)),
                    445:              amt);
                    446:       count -= amt;
                    447:       p = skb->data + amt;
                    448:       for (i = 1; count > 0 && i < copy->cpy_npages; i++)
                    449:        {
                    450:          amt = PAGE_SIZE;
                    451:          if (amt > count)
                    452:            amt = count;
                    453:          memcpy (p, (void *) copy->cpy_page_list[i]->phys_addr, amt);
                    454:          count -= amt;
                    455:          p += amt;
                    456:        }
                    457: 
                    458:       assert (count == 0);
                    459: 
                    460:       vm_map_copy_discard (copy);
                    461:     }
                    462: 
                    463:   skb->dev = dev;
                    464:   skb->reply = reply_port;
                    465:   skb->reply_type = reply_port_type;
                    466: 
                    467:   /* Queue packet for transmission and schedule a software interrupt.  */
                    468:   s = splimp ();
                    469:   if (dev->buffs[0].next != (struct sk_buff *) &dev->buffs[0]
                    470:       || (*dev->hard_start_xmit) (skb, dev))
                    471:     {
                    472:       __skb_queue_tail (&dev->buffs[0], skb);
                    473:       mark_bh (NET_BH);
                    474:     }
                    475:   splx (s);
                    476: 
                    477:   return MIG_NO_REPLY;
                    478: }
                    479: 
                    480: static io_return_t
                    481: device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
                    482:                   mach_msg_type_number_t *count)
                    483: {
                    484:   return net_getstat (&((struct net_data *) d)->ifnet, flavor, status, count);
                    485: }
                    486: 
                    487: static io_return_t
                    488: device_set_filter (void *d, ipc_port_t port, int priority,
                    489:                   filter_t *filter, unsigned filter_count)
                    490: {
                    491:   return net_set_filter (&((struct net_data *) d)->ifnet,
                    492:                         port, priority, filter, filter_count);
                    493: }
                    494: 
                    495: struct device_emulation_ops linux_net_emulation_ops =
                    496: {
                    497:   NULL,
                    498:   NULL,
                    499:   dev_to_port,
                    500:   device_open,
                    501:   NULL,
                    502:   device_write,
                    503:   NULL,
                    504:   NULL,
                    505:   NULL,
                    506:   NULL,
                    507:   device_get_status,
                    508:   device_set_filter,
                    509:   NULL,
                    510:   NULL,
                    511:   NULL,
                    512:   NULL
                    513: };
                    514: 
                    515: /* Do any initialization required for network devices.  */
                    516: void
                    517: linux_net_emulation_init ()
                    518: {
                    519:   skb_queue_head_init (&skb_done_list);
                    520: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.