|
|
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: #include <machine/spl.h>
1.1.1.2 ! root 64: #include <machine/vm_param.h>
1.1 root 65:
66: #include <mach/mach_types.h>
67: #include <mach/kern_return.h>
68: #include <mach/mig_errors.h>
69: #include <mach/port.h>
70: #include <mach/vm_param.h>
71: #include <mach/notify.h>
72:
1.1.1.2 ! root 73: #include <kern/kalloc.h>
! 74: #include <kern/printf.h>
! 75:
1.1 root 76: #include <ipc/ipc_port.h>
77: #include <ipc/ipc_space.h>
78:
79: #include <vm/vm_map.h>
80: #include <vm/vm_kern.h>
81: #include <vm/vm_page.h>
82:
83: #include <device/device_types.h>
84: #include <device/device_port.h>
85: #include <device/if_hdr.h>
86: #include <device/if_ether.h>
87: #include <device/if_hdr.h>
88: #include <device/net_io.h>
1.1.1.2 ! root 89: #include <device/device_reply.user.h>
! 90: #include <device/device_emul.h>
! 91: #include <device/ds_routines.h>
1.1 root 92:
93: #define MACH_INCLUDE
94: #include <linux/kernel.h>
95: #include <linux/sched.h>
96: #include <linux/string.h>
97: #include <linux/errno.h>
98: #include <linux/delay.h>
99: #include <linux/interrupt.h>
100: #include <linux/malloc.h>
101: #include <linux/netdevice.h>
102: #include <linux/etherdevice.h>
1.1.1.2 ! root 103: #include <linux/wireless.h>
1.1 root 104:
1.1.1.2 ! root 105: #include <linux/dev/glue/glue.h>
1.1 root 106:
107: /* One of these is associated with each instance of a device. */
108: struct net_data
109: {
110: ipc_port_t port; /* device port */
111: struct ifnet ifnet; /* Mach ifnet structure (needed for filters) */
112: struct device device; /* generic device structure */
113: struct linux_device *dev; /* Linux network device structure */
114: };
115:
116: /* List of sk_buffs waiting to be freed. */
117: static struct sk_buff_head skb_done_list;
118:
119: /* Forward declarations. */
120:
121: extern struct device_emulation_ops linux_net_emulation_ops;
122:
123: static int print_packet_size = 0;
124:
125: /* Linux kernel network support routines. */
126:
127: /* Requeue packet SKB for transmission after the interface DEV
128: has timed out. The priority of the packet is PRI.
129: In Mach, we simply drop the packet like the native drivers. */
130: void
131: dev_queue_xmit (struct sk_buff *skb, struct linux_device *dev, int pri)
132: {
133: dev_kfree_skb (skb, FREE_WRITE);
134: }
135:
136: /* Close the device DEV. */
137: int
138: dev_close (struct linux_device *dev)
139: {
140: return 0;
141: }
142:
143: /* Network software interrupt handler. */
144: void
145: net_bh (void)
146: {
147: int len;
148: struct sk_buff *skb;
149: struct linux_device *dev;
150:
151: /* Start transmission on interfaces. */
152: for (dev = dev_base; dev; dev = dev->next)
153: {
154: if (dev->base_addr && dev->base_addr != 0xffe0)
155: while (1)
156: {
157: skb = skb_dequeue (&dev->buffs[0]);
158: if (skb)
159: {
160: len = skb->len;
161: if ((*dev->hard_start_xmit) (skb, dev))
162: {
163: skb_queue_head (&dev->buffs[0], skb);
164: mark_bh (NET_BH);
165: break;
166: }
167: else if (print_packet_size)
168: printf ("net_bh: length %d\n", len);
169: }
170: else
171: break;
172: }
173: }
174: }
175:
176: /* Free all sk_buffs on the done list.
177: This routine is called by the iodone thread in ds_routines.c. */
178: void
179: free_skbuffs ()
180: {
181: struct sk_buff *skb;
182:
183: while (1)
184: {
185: skb = skb_dequeue (&skb_done_list);
186: if (skb)
187: {
188: if (skb->copy)
189: {
190: vm_map_copy_discard (skb->copy);
191: skb->copy = NULL;
192: }
193: if (IP_VALID (skb->reply))
194: {
195: ds_device_write_reply (skb->reply, skb->reply_type, 0, skb->len);
196: skb->reply = IP_NULL;
197: }
198: dev_kfree_skb (skb, FREE_WRITE);
199: }
200: else
201: break;
202: }
203: }
204:
205: /* Allocate an sk_buff with SIZE bytes of data space. */
206: struct sk_buff *
207: alloc_skb (unsigned int size, int priority)
208: {
209: return dev_alloc_skb (size);
210: }
211:
212: /* Free SKB. */
213: void
214: kfree_skb (struct sk_buff *skb, int priority)
215: {
216: dev_kfree_skb (skb, priority);
217: }
218:
219: /* Allocate an sk_buff with SIZE bytes of data space. */
220: struct sk_buff *
221: dev_alloc_skb (unsigned int size)
222: {
223: struct sk_buff *skb;
224: unsigned char *bptr;
225: int len = size;
226:
227: size = (size + 15) & ~15;
228: size += sizeof (struct sk_buff);
229:
230: bptr = linux_kmalloc (size, GFP_KERNEL);
231: if (bptr == NULL)
232: return NULL;
233:
234: /* XXX: In Mach, a sk_buff is located at the head,
235: while it's located at the tail in Linux. */
236: skb = bptr;
237: skb->dev = NULL;
238: skb->reply = IP_NULL;
239: skb->copy = NULL;
240: skb->len = 0;
241: skb->prev = skb->next = NULL;
242: skb->list = NULL;
243: skb->data = bptr + sizeof (struct sk_buff);
244: skb->tail = skb->data;
245: skb->head = skb->data;
246: skb->end = skb->data + len;
247:
248: return skb;
249: }
250:
251: /* Free the sk_buff SKB. */
252: void
253: dev_kfree_skb (struct sk_buff *skb, int mode)
254: {
255: unsigned flags;
256:
257: /* Queue sk_buff on done list if there is a
258: page list attached or we need to send a reply.
259: Wakeup the iodone thread to process the list. */
260: if (skb->copy || IP_VALID (skb->reply))
261: {
262: skb_queue_tail (&skb_done_list, skb);
263: save_flags (flags);
264: thread_wakeup ((event_t) & io_done_list);
265: restore_flags (flags);
266: return;
267: }
268: linux_kfree (skb);
269: }
270:
271: /* Accept packet SKB received on an interface. */
272: void
273: netif_rx (struct sk_buff *skb)
274: {
275: ipc_kmsg_t kmsg;
276: struct ether_header *eh;
277: struct packet_header *ph;
278: struct linux_device *dev = skb->dev;
279:
280: assert (skb != NULL);
281:
282: if (print_packet_size)
283: printf ("netif_rx: length %ld\n", skb->len);
284:
285: /* Allocate a kernel message buffer. */
286: kmsg = net_kmsg_get ();
287: if (!kmsg)
288: {
289: dev_kfree_skb (skb, FREE_READ);
290: return;
291: }
292:
293: /* Copy packet into message buffer. */
294: eh = (struct ether_header *) (net_kmsg (kmsg)->header);
295: ph = (struct packet_header *) (net_kmsg (kmsg)->packet);
296: memcpy (eh, skb->data, sizeof (struct ether_header));
1.1.1.2 ! root 297:
! 298: /* packet is prefixed with a struct packet_header,
! 299: see include/device/net_status.h. */
1.1 root 300: memcpy (ph + 1, skb->data + sizeof (struct ether_header),
301: skb->len - sizeof (struct ether_header));
302: ph->type = eh->ether_type;
303: ph->length = (skb->len - sizeof (struct ether_header)
304: + sizeof (struct packet_header));
305:
306: dev_kfree_skb (skb, FREE_READ);
307:
1.1.1.2 ! root 308: net_kmsg(kmsg)->sent = FALSE; /* Mark packet as received. */
! 309:
1.1 root 310: /* Pass packet up to the microkernel. */
311: net_packet (&dev->net_data->ifnet, kmsg,
312: ph->length, ethernet_priority (kmsg));
313: }
314:
315: /* Mach device interface routines. */
316:
317: /* Return a send right associated with network device ND. */
318: static ipc_port_t
319: dev_to_port (void *nd)
320: {
321: return (nd
322: ? ipc_port_make_send (((struct net_data *) nd)->port)
323: : IP_NULL);
324: }
325:
326: static io_return_t
327: device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
328: dev_mode_t mode, char *name, device_t *devp)
329: {
330: io_return_t err = D_SUCCESS;
331: ipc_port_t notify;
332: struct ifnet *ifp;
333: struct linux_device *dev;
334: struct net_data *nd;
335:
336: /* Search for the device. */
337: for (dev = dev_base; dev; dev = dev->next)
338: if (dev->base_addr
339: && dev->base_addr != 0xffe0
340: && !strcmp (name, dev->name))
341: break;
342: if (!dev)
343: return D_NO_SUCH_DEVICE;
344:
345: /* Allocate and initialize device data if this is the first open. */
346: nd = dev->net_data;
347: if (!nd)
348: {
349: dev->net_data = nd = ((struct net_data *)
350: kalloc (sizeof (struct net_data)));
351: if (!nd)
352: {
353: err = D_NO_MEMORY;
354: goto out;
355: }
356: nd->dev = dev;
357: nd->device.emul_data = nd;
358: nd->device.emul_ops = &linux_net_emulation_ops;
359: nd->port = ipc_port_alloc_kernel ();
360: if (nd->port == IP_NULL)
361: {
362: err = KERN_RESOURCE_SHORTAGE;
363: goto out;
364: }
365: ipc_kobject_set (nd->port, (ipc_kobject_t) & nd->device, IKOT_DEVICE);
366: notify = ipc_port_make_sonce (nd->port);
367: ip_lock (nd->port);
368: ipc_port_nsrequest (nd->port, 1, notify, ¬ify);
369: assert (notify == IP_NULL);
370:
371: ifp = &nd->ifnet;
372: ifp->if_unit = dev->name[strlen (dev->name) - 1] - '0';
373: ifp->if_flags = IFF_UP | IFF_RUNNING;
374: ifp->if_mtu = dev->mtu;
375: ifp->if_header_size = dev->hard_header_len;
376: ifp->if_header_format = dev->type;
377: ifp->if_address_size = dev->addr_len;
378: ifp->if_address = dev->dev_addr;
379: if_init_queues (ifp);
380:
381: if (dev->open)
382: {
383: linux_intr_pri = SPL6;
384: if ((*dev->open) (dev))
385: err = D_NO_SUCH_DEVICE;
386: }
387:
388: out:
389: if (err)
390: {
391: if (nd)
392: {
393: if (nd->port != IP_NULL)
394: {
395: ipc_kobject_set (nd->port, IKO_NULL, IKOT_NONE);
396: ipc_port_dealloc_kernel (nd->port);
397: }
398: kfree ((vm_offset_t) nd, sizeof (struct net_data));
399: nd = NULL;
400: dev->net_data = NULL;
401: }
402: }
403: else
404: {
1.1.1.2 ! root 405: /* IPv6 heavily relies on multicasting (especially router and
! 406: neighbor solicits and advertisements), so enable reception of
! 407: those multicast packets by setting `LINUX_IFF_ALLMULTI'. */
! 408: dev->flags |= LINUX_IFF_UP | LINUX_IFF_RUNNING | LINUX_IFF_ALLMULTI;
1.1 root 409: skb_queue_head_init (&dev->buffs[0]);
1.1.1.2 ! root 410:
! 411: if (dev->set_multicast_list)
! 412: dev->set_multicast_list (dev);
1.1 root 413: }
414: if (IP_VALID (reply_port))
415: ds_device_open_reply (reply_port, reply_port_type,
416: err, dev_to_port (nd));
417: return MIG_NO_REPLY;
418: }
419:
420: *devp = &nd->device;
421: return D_SUCCESS;
422: }
423:
424: static io_return_t
425: device_write (void *d, ipc_port_t reply_port,
426: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
427: recnum_t bn, io_buf_ptr_t data, unsigned int count,
428: int *bytes_written)
429: {
430: unsigned char *p;
431: int i, amt, skblen, s;
432: vm_map_copy_t copy = (vm_map_copy_t) data;
433: struct net_data *nd = d;
434: struct linux_device *dev = nd->dev;
435: struct sk_buff *skb;
436:
437: if (count == 0 || count > dev->mtu + dev->hard_header_len)
438: return D_INVALID_SIZE;
439:
440: /* Allocate a sk_buff. */
441: amt = PAGE_SIZE - (copy->offset & PAGE_MASK);
442: skblen = (amt >= count) ? 0 : count;
443: skb = dev_alloc_skb (skblen);
444: if (!skb)
445: return D_NO_MEMORY;
446:
447: /* Copy user data. This is only required if it spans multiple pages. */
448: if (skblen == 0)
449: {
450: assert (copy->cpy_npages == 1);
451:
452: skb->copy = copy;
1.1.1.2 ! root 453: skb->data = ((void *) phystokv(copy->cpy_page_list[0]->phys_addr)
1.1 root 454: + (copy->offset & PAGE_MASK));
455: skb->len = count;
456: skb->head = skb->data;
457: skb->tail = skb->data + skb->len;
458: skb->end = skb->tail;
459: }
460: else
461: {
462: skb->len = skblen;
463: skb->tail = skb->data + skblen;
464: skb->end = skb->tail;
465:
466: memcpy (skb->data,
1.1.1.2 ! root 467: ((void *) phystokv(copy->cpy_page_list[0]->phys_addr)
1.1 root 468: + (copy->offset & PAGE_MASK)),
469: amt);
470: count -= amt;
471: p = skb->data + amt;
472: for (i = 1; count > 0 && i < copy->cpy_npages; i++)
473: {
474: amt = PAGE_SIZE;
475: if (amt > count)
476: amt = count;
1.1.1.2 ! root 477: memcpy (p, (void *) phystokv(copy->cpy_page_list[i]->phys_addr), amt);
1.1 root 478: count -= amt;
479: p += amt;
480: }
481:
482: assert (count == 0);
483:
484: vm_map_copy_discard (copy);
485: }
486:
487: skb->dev = dev;
488: skb->reply = reply_port;
489: skb->reply_type = reply_port_type;
490:
491: /* Queue packet for transmission and schedule a software interrupt. */
492: s = splimp ();
493: if (dev->buffs[0].next != (struct sk_buff *) &dev->buffs[0]
494: || (*dev->hard_start_xmit) (skb, dev))
495: {
496: __skb_queue_tail (&dev->buffs[0], skb);
497: mark_bh (NET_BH);
498: }
499: splx (s);
500:
1.1.1.2 ! root 501: /* Send packet to filters. */
! 502: {
! 503: struct packet_header *packet;
! 504: struct ether_header *header;
! 505: ipc_kmsg_t kmsg;
! 506:
! 507: kmsg = net_kmsg_get ();
! 508:
! 509: if (kmsg != IKM_NULL)
! 510: {
! 511: /* Suitable for Ethernet only. */
! 512: header = (struct ether_header *) (net_kmsg (kmsg)->header);
! 513: packet = (struct packet_header *) (net_kmsg (kmsg)->packet);
! 514: memcpy (header, skb->data, sizeof (struct ether_header));
! 515:
! 516: /* packet is prefixed with a struct packet_header,
! 517: see include/device/net_status.h. */
! 518: memcpy (packet + 1, skb->data + sizeof (struct ether_header),
! 519: skb->len - sizeof (struct ether_header));
! 520: packet->length = skb->len - sizeof (struct ether_header)
! 521: + sizeof (struct packet_header);
! 522: packet->type = header->ether_type;
! 523: net_kmsg (kmsg)->sent = TRUE; /* Mark packet as sent. */
! 524: s = splimp ();
! 525: net_packet (&dev->net_data->ifnet, kmsg, packet->length,
! 526: ethernet_priority (kmsg));
! 527: splx (s);
! 528: }
! 529: }
! 530:
1.1 root 531: return MIG_NO_REPLY;
532: }
533:
1.1.1.2 ! root 534:
1.1 root 535: static io_return_t
536: device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
537: mach_msg_type_number_t *count)
538: {
1.1.1.2 ! root 539: if (flavor == NET_FLAGS)
! 540: {
! 541: struct net_data *net = (struct net_data *) d;
! 542:
! 543: if (*count != 1)
! 544: return D_INVALID_SIZE;
! 545:
! 546: status[0] = net->dev->flags;
! 547: return D_SUCCESS;
! 548: }
! 549:
! 550: if(flavor >= SIOCIWFIRST && flavor <= SIOCIWLAST)
! 551: {
! 552: /* handle wireless ioctl */
! 553: if(! IW_IS_GET(flavor))
! 554: return D_INVALID_OPERATION;
! 555:
! 556: if(*count * sizeof(int) < sizeof(struct ifreq))
! 557: return D_INVALID_OPERATION;
! 558:
! 559: struct net_data *nd = d;
! 560: struct linux_device *dev = nd->dev;
! 561:
! 562: if(! dev->do_ioctl)
! 563: return D_INVALID_OPERATION;
! 564:
! 565: int result;
! 566:
! 567: if (flavor == SIOCGIWRANGE || flavor == SIOCGIWENCODE
! 568: || flavor == SIOCGIWESSID || flavor == SIOCGIWNICKN
! 569: || flavor == SIOCGIWSPY)
! 570: {
! 571: /*
! 572: * These ioctls require an `iw_point' as their argument (i.e.
! 573: * they want to return some data to userspace.
! 574: * Therefore supply some sane values and carry the data back
! 575: * to userspace right behind the `struct iwreq'.
! 576: */
! 577: struct iw_point *iwp = &((struct iwreq *) status)->u.data;
! 578: iwp->length = *count * sizeof (dev_status_t) - sizeof (struct ifreq);
! 579: iwp->pointer = (void *) status + sizeof (struct ifreq);
! 580:
! 581: result = dev->do_ioctl (dev, (struct ifreq *) status, flavor);
! 582:
! 583: *count = ((sizeof (struct ifreq) + iwp->length)
! 584: / sizeof (dev_status_t));
! 585: if (iwp->length % sizeof (dev_status_t))
! 586: (*count) ++;
! 587: }
! 588: else
! 589: {
! 590: *count = sizeof(struct ifreq) / sizeof(int);
! 591: result = dev->do_ioctl(dev, (struct ifreq *) status, flavor);
! 592: }
! 593:
! 594: return result ? D_IO_ERROR : D_SUCCESS;
! 595: }
! 596: else
! 597: {
! 598: /* common get_status request */
! 599: return net_getstat (&((struct net_data *) d)->ifnet, flavor,
! 600: status, count);
! 601: }
1.1 root 602: }
603:
1.1.1.2 ! root 604:
! 605: static io_return_t
! 606: device_set_status(void *d, dev_flavor_t flavor, dev_status_t status,
! 607: mach_msg_type_number_t count)
! 608: {
! 609: if (flavor == NET_FLAGS)
! 610: {
! 611: if (count != 1)
! 612: return D_INVALID_SIZE;
! 613:
! 614: short flags = status[0];
! 615: struct net_data *net = (struct net_data *) d;
! 616:
! 617: dev_change_flags (net->dev, flags);
! 618:
! 619: /* Change the flags of the Mach device, too. */
! 620: net->ifnet.if_flags = net->dev->flags;
! 621: return D_SUCCESS;
! 622: }
! 623:
! 624: if(flavor < SIOCIWFIRST || flavor > SIOCIWLAST)
! 625: return D_INVALID_OPERATION;
! 626:
! 627: if(! IW_IS_SET(flavor))
! 628: return D_INVALID_OPERATION;
! 629:
! 630: if(count * sizeof(int) < sizeof(struct ifreq))
! 631: return D_INVALID_OPERATION;
! 632:
! 633: struct net_data *nd = d;
! 634: struct linux_device *dev = nd->dev;
! 635:
! 636: if(! dev->do_ioctl)
! 637: return D_INVALID_OPERATION;
! 638:
! 639: if((flavor == SIOCSIWENCODE || flavor == SIOCSIWESSID
! 640: || flavor == SIOCSIWNICKN || flavor == SIOCSIWSPY)
! 641: && ((struct iwreq *) status)->u.data.pointer)
! 642: {
! 643: struct iw_point *iwp = &((struct iwreq *) status)->u.data;
! 644:
! 645: /* safety check whether the status array is long enough ... */
! 646: if(count * sizeof(int) < sizeof(struct ifreq) + iwp->length)
! 647: return D_INVALID_OPERATION;
! 648:
! 649: /* make sure, iwp->pointer points to the correct address */
! 650: if(iwp->pointer) iwp->pointer = (void *) status + sizeof(struct ifreq);
! 651: }
! 652:
! 653: int result = dev->do_ioctl(dev, (struct ifreq *) status, flavor);
! 654: return result ? D_IO_ERROR : D_SUCCESS;
! 655: }
! 656:
! 657:
1.1 root 658: static io_return_t
659: device_set_filter (void *d, ipc_port_t port, int priority,
660: filter_t * filter, unsigned filter_count)
661: {
662: return net_set_filter (&((struct net_data *) d)->ifnet,
663: port, priority, filter, filter_count);
664: }
665:
666: struct device_emulation_ops linux_net_emulation_ops =
667: {
668: NULL,
669: NULL,
670: dev_to_port,
671: device_open,
672: NULL,
673: device_write,
674: NULL,
675: NULL,
676: NULL,
1.1.1.2 ! root 677: device_set_status,
1.1 root 678: device_get_status,
679: device_set_filter,
680: NULL,
681: NULL,
682: NULL,
683: NULL
684: };
685:
686: /* Do any initialization required for network devices. */
687: void
688: linux_net_emulation_init ()
689: {
690: skb_queue_head_init (&skb_done_list);
691: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.