|
|
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>
64:
65: #include <mach/mach_types.h>
66: #include <mach/kern_return.h>
67: #include <mach/mig_errors.h>
68: #include <mach/port.h>
69: #include <mach/vm_param.h>
70: #include <mach/notify.h>
71:
72: #include <ipc/ipc_port.h>
73: #include <ipc/ipc_space.h>
74:
75: #include <vm/vm_map.h>
76: #include <vm/vm_kern.h>
77: #include <vm/vm_page.h>
78:
79: #include <device/device_types.h>
80: #include <device/device_port.h>
81: #include <device/if_hdr.h>
82: #include <device/if_ether.h>
83: #include <device/if_hdr.h>
84: #include <device/net_io.h>
85: #include "device_reply.h"
86:
87: #include <linux_emul.h>
88:
89: #define MACH_INCLUDE
90: #include <linux/kernel.h>
91: #include <linux/sched.h>
92: #include <linux/string.h>
93: #include <linux/errno.h>
94: #include <linux/delay.h>
95: #include <linux/interrupt.h>
96: #include <linux/malloc.h>
97: #include <linux/netdevice.h>
98: #include <linux/etherdevice.h>
99:
100: extern int linux_intr_pri;
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)
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: unsigned char *bptr;
220: int len = size;
221:
222: size = (size + 15) & ~15;
223: size += sizeof (struct sk_buff);
224:
225: bptr = linux_kmalloc (size, GFP_KERNEL);
226: if (bptr == NULL)
227: return NULL;
228:
229: /* XXX: In Mach, a sk_buff is located at the head,
230: while it's located at the tail in Linux. */
231: skb = bptr;
232: skb->dev = NULL;
233: skb->reply = IP_NULL;
234: skb->copy = NULL;
235: skb->len = 0;
236: skb->prev = skb->next = NULL;
237: skb->list = NULL;
238: skb->data = bptr + sizeof (struct sk_buff);
239: skb->tail = skb->data;
240: skb->head = skb->data;
241: skb->end = skb->data + len;
242:
243: return skb;
244: }
245:
246: /* Free the sk_buff SKB. */
247: void
248: dev_kfree_skb (struct sk_buff *skb, int mode)
249: {
250: unsigned flags;
251: extern void *io_done_list;
252:
253: /* Queue sk_buff on done list if there is a
254: page list attached or we need to send a reply.
255: Wakeup the iodone thread to process the list. */
256: if (skb->copy || IP_VALID (skb->reply))
257: {
258: skb_queue_tail (&skb_done_list, skb);
259: save_flags (flags);
260: thread_wakeup ((event_t) & io_done_list);
261: restore_flags (flags);
262: return;
263: }
264: linux_kfree (skb);
265: }
266:
267: /* Accept packet SKB received on an interface. */
268: void
269: netif_rx (struct sk_buff *skb)
270: {
271: ipc_kmsg_t kmsg;
272: struct ether_header *eh;
273: struct packet_header *ph;
274: struct linux_device *dev = skb->dev;
275:
276: assert (skb != NULL);
277:
278: if (print_packet_size)
279: printf ("netif_rx: length %ld\n", skb->len);
280:
281: /* Allocate a kernel message buffer. */
282: kmsg = net_kmsg_get ();
283: if (!kmsg)
284: {
285: dev_kfree_skb (skb, FREE_READ);
286: return;
287: }
288:
289: /* Copy packet into message buffer. */
290: eh = (struct ether_header *) (net_kmsg (kmsg)->header);
291: ph = (struct packet_header *) (net_kmsg (kmsg)->packet);
292: memcpy (eh, skb->data, sizeof (struct ether_header));
293: memcpy (ph + 1, skb->data + sizeof (struct ether_header),
294: skb->len - sizeof (struct ether_header));
295: ph->type = eh->ether_type;
296: ph->length = (skb->len - sizeof (struct ether_header)
297: + sizeof (struct packet_header));
298:
299: dev_kfree_skb (skb, FREE_READ);
300:
301: /* Pass packet up to the microkernel. */
302: net_packet (&dev->net_data->ifnet, kmsg,
303: ph->length, ethernet_priority (kmsg));
304: }
305:
306: /* Mach device interface routines. */
307:
308: /* Return a send right associated with network device ND. */
309: static ipc_port_t
310: dev_to_port (void *nd)
311: {
312: return (nd
313: ? ipc_port_make_send (((struct net_data *) nd)->port)
314: : IP_NULL);
315: }
316:
317: static io_return_t
318: device_open (ipc_port_t reply_port, mach_msg_type_name_t reply_port_type,
319: dev_mode_t mode, char *name, device_t *devp)
320: {
321: io_return_t err = D_SUCCESS;
322: ipc_port_t notify;
323: struct ifnet *ifp;
324: struct linux_device *dev;
325: struct net_data *nd;
326:
327: /* Search for the device. */
328: for (dev = dev_base; dev; dev = dev->next)
329: if (dev->base_addr
330: && dev->base_addr != 0xffe0
331: && !strcmp (name, dev->name))
332: break;
333: if (!dev)
334: return D_NO_SUCH_DEVICE;
335:
336: /* Allocate and initialize device data if this is the first open. */
337: nd = dev->net_data;
338: if (!nd)
339: {
340: dev->net_data = nd = ((struct net_data *)
341: kalloc (sizeof (struct net_data)));
342: if (!nd)
343: {
344: err = D_NO_MEMORY;
345: goto out;
346: }
347: nd->dev = dev;
348: nd->device.emul_data = nd;
349: nd->device.emul_ops = &linux_net_emulation_ops;
350: nd->port = ipc_port_alloc_kernel ();
351: if (nd->port == IP_NULL)
352: {
353: err = KERN_RESOURCE_SHORTAGE;
354: goto out;
355: }
356: ipc_kobject_set (nd->port, (ipc_kobject_t) & nd->device, IKOT_DEVICE);
357: notify = ipc_port_make_sonce (nd->port);
358: ip_lock (nd->port);
359: ipc_port_nsrequest (nd->port, 1, notify, ¬ify);
360: assert (notify == IP_NULL);
361:
362: ifp = &nd->ifnet;
363: ifp->if_unit = dev->name[strlen (dev->name) - 1] - '0';
364: ifp->if_flags = IFF_UP | IFF_RUNNING;
365: ifp->if_mtu = dev->mtu;
366: ifp->if_header_size = dev->hard_header_len;
367: ifp->if_header_format = dev->type;
368: ifp->if_address_size = dev->addr_len;
369: ifp->if_address = dev->dev_addr;
370: if_init_queues (ifp);
371:
372: if (dev->open)
373: {
374: linux_intr_pri = SPL6;
375: if ((*dev->open) (dev))
376: err = D_NO_SUCH_DEVICE;
377: }
378:
379: out:
380: if (err)
381: {
382: if (nd)
383: {
384: if (nd->port != IP_NULL)
385: {
386: ipc_kobject_set (nd->port, IKO_NULL, IKOT_NONE);
387: ipc_port_dealloc_kernel (nd->port);
388: }
389: kfree ((vm_offset_t) nd, sizeof (struct net_data));
390: nd = NULL;
391: dev->net_data = NULL;
392: }
393: }
394: else
395: {
396: dev->flags |= LINUX_IFF_UP | LINUX_IFF_RUNNING;
397: skb_queue_head_init (&dev->buffs[0]);
398: }
399: if (IP_VALID (reply_port))
400: ds_device_open_reply (reply_port, reply_port_type,
401: err, dev_to_port (nd));
402: return MIG_NO_REPLY;
403: }
404:
405: *devp = &nd->device;
406: return D_SUCCESS;
407: }
408:
409: static io_return_t
410: device_write (void *d, ipc_port_t reply_port,
411: mach_msg_type_name_t reply_port_type, dev_mode_t mode,
412: recnum_t bn, io_buf_ptr_t data, unsigned int count,
413: int *bytes_written)
414: {
415: unsigned char *p;
416: int i, amt, skblen, s;
417: io_return_t err = 0;
418: vm_map_copy_t copy = (vm_map_copy_t) data;
419: struct net_data *nd = d;
420: struct linux_device *dev = nd->dev;
421: struct sk_buff *skb;
422:
423: if (count == 0 || count > dev->mtu + dev->hard_header_len)
424: return D_INVALID_SIZE;
425:
426: /* Allocate a sk_buff. */
427: amt = PAGE_SIZE - (copy->offset & PAGE_MASK);
428: skblen = (amt >= count) ? 0 : count;
429: skb = dev_alloc_skb (skblen);
430: if (!skb)
431: return D_NO_MEMORY;
432:
433: /* Copy user data. This is only required if it spans multiple pages. */
434: if (skblen == 0)
435: {
436: assert (copy->cpy_npages == 1);
437:
438: skb->copy = copy;
439: skb->data = ((void *) copy->cpy_page_list[0]->phys_addr
440: + (copy->offset & PAGE_MASK));
441: skb->len = count;
442: skb->head = skb->data;
443: skb->tail = skb->data + skb->len;
444: skb->end = skb->tail;
445: }
446: else
447: {
448: skb->len = skblen;
449: skb->tail = skb->data + skblen;
450: skb->end = skb->tail;
451:
452: memcpy (skb->data,
453: ((void *) copy->cpy_page_list[0]->phys_addr
454: + (copy->offset & PAGE_MASK)),
455: amt);
456: count -= amt;
457: p = skb->data + amt;
458: for (i = 1; count > 0 && i < copy->cpy_npages; i++)
459: {
460: amt = PAGE_SIZE;
461: if (amt > count)
462: amt = count;
463: memcpy (p, (void *) copy->cpy_page_list[i]->phys_addr, amt);
464: count -= amt;
465: p += amt;
466: }
467:
468: assert (count == 0);
469:
470: vm_map_copy_discard (copy);
471: }
472:
473: skb->dev = dev;
474: skb->reply = reply_port;
475: skb->reply_type = reply_port_type;
476:
477: /* Queue packet for transmission and schedule a software interrupt. */
478: s = splimp ();
479: if (dev->buffs[0].next != (struct sk_buff *) &dev->buffs[0]
480: || (*dev->hard_start_xmit) (skb, dev))
481: {
482: __skb_queue_tail (&dev->buffs[0], skb);
483: mark_bh (NET_BH);
484: }
485: splx (s);
486:
487: return MIG_NO_REPLY;
488: }
489:
490: static io_return_t
491: device_get_status (void *d, dev_flavor_t flavor, dev_status_t status,
492: mach_msg_type_number_t *count)
493: {
494: return net_getstat (&((struct net_data *) d)->ifnet, flavor, status, count);
495: }
496:
497: static io_return_t
498: device_set_filter (void *d, ipc_port_t port, int priority,
499: filter_t * filter, unsigned filter_count)
500: {
501: return net_set_filter (&((struct net_data *) d)->ifnet,
502: port, priority, filter, filter_count);
503: }
504:
505: struct device_emulation_ops linux_net_emulation_ops =
506: {
507: NULL,
508: NULL,
509: dev_to_port,
510: device_open,
511: NULL,
512: device_write,
513: NULL,
514: NULL,
515: NULL,
516: NULL,
517: device_get_status,
518: device_set_filter,
519: NULL,
520: NULL,
521: NULL,
522: NULL
523: };
524:
525: /* Do any initialization required for network devices. */
526: void
527: linux_net_emulation_init ()
528: {
529: skb_queue_head_init (&skb_done_list);
530: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.