source: trunk/minix/servers/inet/generic/eth.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 25.9 KB
Line 
1/*
2eth.c
3
4Copyright 1995 Philip Homburg
5*/
6
7#include "inet.h"
8#include "buf.h"
9#include "clock.h"
10#include "event.h"
11#include "osdep_eth.h"
12#include "type.h"
13
14#include "assert.h"
15#include "buf.h"
16#include "eth.h"
17#include "eth_int.h"
18#include "io.h"
19#include "sr.h"
20
21THIS_FILE
22
23#define ETH_FD_NR (4*IP_PORT_MAX)
24#define EXPIRE_TIME 60*HZ /* seconds */
25
26typedef struct eth_fd
27{
28 int ef_flags;
29 nwio_ethopt_t ef_ethopt;
30 eth_port_t *ef_port;
31 struct eth_fd *ef_type_next;
32 struct eth_fd *ef_send_next;
33 int ef_srfd;
34 acc_t *ef_rdbuf_head;
35 acc_t *ef_rdbuf_tail;
36 get_userdata_t ef_get_userdata;
37 put_userdata_t ef_put_userdata;
38 put_pkt_t ef_put_pkt;
39 time_t ef_exp_time;
40 size_t ef_write_count;
41 ioreq_t ef_ioctl_req;
42} eth_fd_t;
43
44#define EFF_FLAGS 0xf
45# define EFF_EMPTY 0x0
46# define EFF_INUSE 0x1
47# define EFF_BUSY 0xE
48# define EFF_READ_IP 0x2
49# define EFF_WRITE_IP 0x4
50# define EFF_IOCTL_IP 0x8
51# define EFF_OPTSET 0x10
52
53/* Note that the vh_type field is normally considered part of the ethernet
54 * header.
55 */
56typedef struct
57{
58 u16_t vh_type;
59 u16_t vh_vlan;
60} vlan_hdr_t;
61
62FORWARD int eth_checkopt ARGS(( eth_fd_t *eth_fd ));
63FORWARD void hash_fd ARGS(( eth_fd_t *eth_fd ));
64FORWARD void unhash_fd ARGS(( eth_fd_t *eth_fd ));
65FORWARD void eth_buffree ARGS(( int priority ));
66#ifdef BUF_CONSISTENCY_CHECK
67FORWARD void eth_bufcheck ARGS(( void ));
68#endif
69FORWARD void packet2user ARGS(( eth_fd_t *fd, acc_t *pack, time_t exp_time ));
70FORWARD void reply_thr_get ARGS(( eth_fd_t *eth_fd,
71 size_t result, int for_ioctl ));
72FORWARD void reply_thr_put ARGS(( eth_fd_t *eth_fd,
73 size_t result, int for_ioctl ));
74FORWARD void do_rec_conf ARGS(( eth_port_t *eth_port ));
75FORWARD u32_t compute_rec_conf ARGS(( eth_port_t *eth_port ));
76FORWARD acc_t *insert_vlan_hdr ARGS(( eth_port_t *eth_port, acc_t *pack ));
77
78PUBLIC eth_port_t *eth_port_table;
79PUBLIC int no_ethWritePort= 0;
80
81PRIVATE eth_fd_t eth_fd_table[ETH_FD_NR];
82PRIVATE ether_addr_t broadcast= { { 255, 255, 255, 255, 255, 255 } };
83
84PUBLIC void eth_prep()
85{
86 eth_port_table= alloc(eth_conf_nr * sizeof(eth_port_table[0]));
87}
88
89PUBLIC void eth_init()
90{
91 int i, j;
92
93 assert (BUF_S >= sizeof(nwio_ethopt_t));
94 assert (BUF_S >= ETH_HDR_SIZE); /* these are in fact static assertions,
95 thus a good compiler doesn't
96 generate any code for this */
97
98
99 for (i=0; i<ETH_FD_NR; i++)
100 eth_fd_table[i].ef_flags= EFF_EMPTY;
101 for (i=0; i<eth_conf_nr; i++)
102 {
103 eth_port_table[i].etp_flags= EFF_EMPTY;
104 eth_port_table[i].etp_sendq_head= NULL;
105 eth_port_table[i].etp_sendq_tail= NULL;
106 eth_port_table[i].etp_type_any= NULL;
107 ev_init(&eth_port_table[i].etp_sendev);
108 for (j= 0; j<ETH_TYPE_HASH_NR; j++)
109 eth_port_table[i].etp_type[j]= NULL;
110 for (j= 0; j<ETH_VLAN_HASH_NR; j++)
111 eth_port_table[i].etp_vlan_tab[j]= NULL;
112 }
113
114#ifndef BUF_CONSISTENCY_CHECK
115 bf_logon(eth_buffree);
116#else
117 bf_logon(eth_buffree, eth_bufcheck);
118#endif
119
120 osdep_eth_init();
121}
122
123PUBLIC int eth_open(port, srfd, get_userdata, put_userdata, put_pkt,
124 select_res)
125int port, srfd;
126get_userdata_t get_userdata;
127put_userdata_t put_userdata;
128put_pkt_t put_pkt;
129select_res_t select_res;
130{
131 int i;
132 eth_port_t *eth_port;
133 eth_fd_t *eth_fd;
134
135 DBLOCK(0x20, printf("eth_open (%d, %d, %lx, %lx)\n", port, srfd,
136 (unsigned long)get_userdata, (unsigned long)put_userdata));
137 eth_port= &eth_port_table[port];
138 if (!(eth_port->etp_flags & EPF_ENABLED))
139 return EGENERIC;
140
141 for (i=0; i<ETH_FD_NR && (eth_fd_table[i].ef_flags & EFF_INUSE);
142 i++);
143
144 if (i>=ETH_FD_NR)
145 {
146 DBLOCK(1, printf("out of fds\n"));
147 return EAGAIN;
148 }
149
150 eth_fd= &eth_fd_table[i];
151
152 eth_fd->ef_flags= EFF_INUSE;
153 eth_fd->ef_ethopt.nweo_flags=NWEO_DEFAULT;
154 eth_fd->ef_port= eth_port;
155 eth_fd->ef_srfd= srfd;
156 assert(eth_fd->ef_rdbuf_head == NULL);
157 eth_fd->ef_get_userdata= get_userdata;
158 eth_fd->ef_put_userdata= put_userdata;
159 eth_fd->ef_put_pkt= put_pkt;
160
161 return i;
162}
163
164PUBLIC int eth_ioctl(fd, req)
165int fd;
166ioreq_t req;
167{
168 acc_t *data;
169 eth_fd_t *eth_fd;
170 eth_port_t *eth_port;
171
172 DBLOCK(0x20, printf("eth_ioctl (%d, 0x%lx)\n", fd, (unsigned long)req));
173 eth_fd= &eth_fd_table[fd];
174 eth_port= eth_fd->ef_port;
175
176 assert (eth_fd->ef_flags & EFF_INUSE);
177
178 switch (req)
179 {
180 case NWIOSETHOPT:
181 {
182 nwio_ethopt_t *ethopt;
183 nwio_ethopt_t oldopt, newopt;
184 int result;
185 u32_t new_en_flags, new_di_flags,
186 old_en_flags, old_di_flags;
187
188 data= (*eth_fd->ef_get_userdata)(eth_fd->
189 ef_srfd, 0, sizeof(nwio_ethopt_t), TRUE);
190
191 ethopt= (nwio_ethopt_t *)ptr2acc_data(data);
192 oldopt= eth_fd->ef_ethopt;
193 newopt= *ethopt;
194
195 old_en_flags= oldopt.nweo_flags & 0xffff;
196 old_di_flags= (oldopt.nweo_flags >> 16) & 0xffff;
197 new_en_flags= newopt.nweo_flags & 0xffff;
198 new_di_flags= (newopt.nweo_flags >> 16) & 0xffff;
199 if (new_en_flags & new_di_flags)
200 {
201 bf_afree(data);
202 reply_thr_get (eth_fd, EBADMODE, TRUE);
203 return NW_OK;
204 }
205
206 /* NWEO_ACC_MASK */
207 if (new_di_flags & NWEO_ACC_MASK)
208 {
209 bf_afree(data);
210 reply_thr_get (eth_fd, EBADMODE, TRUE);
211 return NW_OK;
212 }
213 /* you can't disable access modes */
214
215 if (!(new_en_flags & NWEO_ACC_MASK))
216 new_en_flags |= (old_en_flags & NWEO_ACC_MASK);
217
218
219 /* NWEO_LOC_MASK */
220 if (!((new_en_flags | new_di_flags) & NWEO_LOC_MASK))
221 {
222 new_en_flags |= (old_en_flags & NWEO_LOC_MASK);
223 new_di_flags |= (old_di_flags & NWEO_LOC_MASK);
224 }
225
226 /* NWEO_BROAD_MASK */
227 if (!((new_en_flags | new_di_flags) & NWEO_BROAD_MASK))
228 {
229 new_en_flags |= (old_en_flags & NWEO_BROAD_MASK);
230 new_di_flags |= (old_di_flags & NWEO_BROAD_MASK);
231 }
232
233 /* NWEO_MULTI_MASK */
234 if (!((new_en_flags | new_di_flags) & NWEO_MULTI_MASK))
235 {
236 new_en_flags |= (old_en_flags & NWEO_MULTI_MASK);
237 new_di_flags |= (old_di_flags & NWEO_MULTI_MASK);
238 newopt.nweo_multi= oldopt.nweo_multi;
239 }
240
241 /* NWEO_PROMISC_MASK */
242 if (!((new_en_flags | new_di_flags) & NWEO_PROMISC_MASK))
243 {
244 new_en_flags |= (old_en_flags & NWEO_PROMISC_MASK);
245 new_di_flags |= (old_di_flags & NWEO_PROMISC_MASK);
246 }
247
248 /* NWEO_REM_MASK */
249 if (!((new_en_flags | new_di_flags) & NWEO_REM_MASK))
250 {
251 new_en_flags |= (old_en_flags & NWEO_REM_MASK);
252 new_di_flags |= (old_di_flags & NWEO_REM_MASK);
253 newopt.nweo_rem= oldopt.nweo_rem;
254 }
255
256 /* NWEO_TYPE_MASK */
257 if (!((new_en_flags | new_di_flags) & NWEO_TYPE_MASK))
258 {
259 new_en_flags |= (old_en_flags & NWEO_TYPE_MASK);
260 new_di_flags |= (old_di_flags & NWEO_TYPE_MASK);
261 newopt.nweo_type= oldopt.nweo_type;
262 }
263
264 /* NWEO_RW_MASK */
265 if (!((new_en_flags | new_di_flags) & NWEO_RW_MASK))
266 {
267 new_en_flags |= (old_en_flags & NWEO_RW_MASK);
268 new_di_flags |= (old_di_flags & NWEO_RW_MASK);
269 }
270
271 if (eth_fd->ef_flags & EFF_OPTSET)
272 unhash_fd(eth_fd);
273
274 newopt.nweo_flags= ((unsigned long)new_di_flags << 16) |
275 new_en_flags;
276 eth_fd->ef_ethopt= newopt;
277
278 result= eth_checkopt(eth_fd);
279
280 if (result<0)
281 eth_fd->ef_ethopt= oldopt;
282 else
283 {
284 unsigned long opt_flags;
285 unsigned changes;
286 opt_flags= oldopt.nweo_flags ^
287 eth_fd->ef_ethopt.nweo_flags;
288 changes= ((opt_flags >> 16) | opt_flags) &
289 0xffff;
290 if (changes & (NWEO_BROAD_MASK |
291 NWEO_MULTI_MASK | NWEO_PROMISC_MASK))
292 {
293 do_rec_conf(eth_port);
294 }
295 }
296
297 if (eth_fd->ef_flags & EFF_OPTSET)
298 hash_fd(eth_fd);
299
300 bf_afree(data);
301 reply_thr_get (eth_fd, result, TRUE);
302 return NW_OK;
303 }
304
305 case NWIOGETHOPT:
306 {
307 nwio_ethopt_t *ethopt;
308 acc_t *acc;
309 int result;
310
311 acc= bf_memreq(sizeof(nwio_ethopt_t));
312
313 ethopt= (nwio_ethopt_t *)ptr2acc_data(acc);
314
315 *ethopt= eth_fd->ef_ethopt;
316
317 result= (*eth_fd->ef_put_userdata)(eth_fd->
318 ef_srfd, 0, acc, TRUE);
319 if (result >= 0)
320 reply_thr_put(eth_fd, NW_OK, TRUE);
321 return result;
322 }
323 case NWIOGETHSTAT:
324 {
325 nwio_ethstat_t *ethstat;
326 acc_t *acc;
327 int result;
328
329 assert (sizeof(nwio_ethstat_t) <= BUF_S);
330
331 eth_port= eth_fd->ef_port;
332 if (!(eth_port->etp_flags & EPF_ENABLED))
333 {
334 reply_thr_put(eth_fd, EGENERIC, TRUE);
335 return NW_OK;
336 }
337
338 if (!(eth_port->etp_flags & EPF_GOT_ADDR))
339 {
340 printf(
341 "eth_ioctl: suspending NWIOGETHSTAT ioctl\n");
342
343 eth_fd->ef_ioctl_req= req;
344 assert(!(eth_fd->ef_flags & EFF_IOCTL_IP));
345 eth_fd->ef_flags |= EFF_IOCTL_IP;
346 return NW_SUSPEND;
347 }
348
349 acc= bf_memreq(sizeof(nwio_ethstat_t));
350 compare (bf_bufsize(acc), ==, sizeof(*ethstat));
351
352 ethstat= (nwio_ethstat_t *)ptr2acc_data(acc);
353 ethstat->nwes_addr= eth_port->etp_ethaddr;
354
355 if (!eth_port->etp_vlan)
356 {
357 result= eth_get_stat(eth_port,
358 &ethstat->nwes_stat);
359 if (result != NW_OK)
360 {
361 bf_afree(acc);
362 reply_thr_put(eth_fd, result, TRUE);
363 return NW_OK;
364 }
365 }
366 else
367 {
368 /* No statistics */
369 memset(&ethstat->nwes_stat, '\0',
370 sizeof(ethstat->nwes_stat));
371 }
372
373 result= (*eth_fd->ef_put_userdata)(eth_fd->
374 ef_srfd, 0, acc, TRUE);
375 if (result >= 0)
376 reply_thr_put(eth_fd, NW_OK, TRUE);
377 return result;
378 }
379 default:
380 break;
381 }
382 reply_thr_put(eth_fd, EBADIOCTL, TRUE);
383 return NW_OK;
384}
385
386PUBLIC int eth_write(fd, count)
387int fd;
388size_t count;
389{
390 eth_fd_t *eth_fd;
391 eth_port_t *eth_port, *rep;
392 acc_t *user_data;
393 int r;
394
395 eth_fd= &eth_fd_table[fd];
396 eth_port= eth_fd->ef_port;
397
398 if (!(eth_fd->ef_flags & EFF_OPTSET))
399 {
400 reply_thr_get (eth_fd, EBADMODE, FALSE);
401 return NW_OK;
402 }
403
404 assert (!(eth_fd->ef_flags & EFF_WRITE_IP));
405
406 eth_fd->ef_write_count= count;
407 if (eth_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY)
408 count += ETH_HDR_SIZE;
409
410 if (count<ETH_MIN_PACK_SIZE || count>ETH_MAX_PACK_SIZE)
411 {
412 DBLOCK(1, printf("illegal packetsize (%d)\n",count));
413 reply_thr_get (eth_fd, EPACKSIZE, FALSE);
414 return NW_OK;
415 }
416 eth_fd->ef_flags |= EFF_WRITE_IP;
417
418 /* Enqueue at the real ethernet port */
419 rep= eth_port->etp_vlan_port;
420 if (!rep)
421 rep= eth_port;
422 if (rep->etp_wr_pack)
423 {
424 eth_fd->ef_send_next= NULL;
425 if (rep->etp_sendq_head)
426 rep->etp_sendq_tail->ef_send_next= eth_fd;
427 else
428 rep->etp_sendq_head= eth_fd;
429 rep->etp_sendq_tail= eth_fd;
430 return NW_SUSPEND;
431 }
432
433 user_data= (*eth_fd->ef_get_userdata)(eth_fd->ef_srfd, 0,
434 eth_fd->ef_write_count, FALSE);
435 if (!user_data)
436 {
437 eth_fd->ef_flags &= ~EFF_WRITE_IP;
438 reply_thr_get (eth_fd, EFAULT, FALSE);
439 return NW_OK;
440 }
441 r= eth_send(fd, user_data, eth_fd->ef_write_count);
442 assert(r == NW_OK);
443
444 eth_fd->ef_flags &= ~EFF_WRITE_IP;
445 reply_thr_get(eth_fd, eth_fd->ef_write_count, FALSE);
446 return NW_OK;
447}
448
449PUBLIC int eth_send(fd, data, data_len)
450int fd;
451acc_t *data;
452size_t data_len;
453{
454 eth_fd_t *eth_fd;
455 eth_port_t *eth_port, *rep;
456 eth_hdr_t *eth_hdr;
457 acc_t *eth_pack;
458 unsigned long nweo_flags;
459 size_t count;
460 ev_arg_t ev_arg;
461
462 eth_fd= &eth_fd_table[fd];
463 eth_port= eth_fd->ef_port;
464
465 if (!(eth_fd->ef_flags & EFF_OPTSET))
466 return EBADMODE;
467
468 count= data_len;
469 if (eth_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY)
470 count += ETH_HDR_SIZE;
471
472 if (count<ETH_MIN_PACK_SIZE || count>ETH_MAX_PACK_SIZE)
473 {
474 DBLOCK(1, printf("illegal packetsize (%d)\n",count));
475 return EPACKSIZE;
476 }
477 rep= eth_port->etp_vlan_port;
478 if (!rep)
479 rep= eth_port;
480
481 if (rep->etp_wr_pack)
482 return NW_WOULDBLOCK;
483
484 nweo_flags= eth_fd->ef_ethopt.nweo_flags;
485 if (nweo_flags & NWEO_RWDATONLY)
486 {
487 eth_pack= bf_memreq(ETH_HDR_SIZE);
488 eth_pack->acc_next= data;
489 }
490 else
491 eth_pack= bf_packIffLess(data, ETH_HDR_SIZE);
492
493 eth_hdr= (eth_hdr_t *)ptr2acc_data(eth_pack);
494
495 if (nweo_flags & NWEO_REMSPEC)
496 eth_hdr->eh_dst= eth_fd->ef_ethopt.nweo_rem;
497
498 if (!(eth_port->etp_flags & EPF_GOT_ADDR))
499 {
500 /* No device, discard packet */
501 bf_afree(eth_pack);
502 return NW_OK;
503 }
504
505 if (!(nweo_flags & NWEO_EN_PROMISC))
506 eth_hdr->eh_src= eth_port->etp_ethaddr;
507
508 if (nweo_flags & NWEO_TYPESPEC)
509 eth_hdr->eh_proto= eth_fd->ef_ethopt.nweo_type;
510
511 if (eth_addrcmp(eth_hdr->eh_dst, eth_port->etp_ethaddr) == 0)
512 {
513 /* Local loopback. */
514 eth_port->etp_wr_pack= eth_pack;
515 ev_arg.ev_ptr= eth_port;
516 ev_enqueue(&eth_port->etp_sendev, eth_loop_ev, ev_arg);
517 return NW_OK;
518 }
519
520 if (rep != eth_port)
521 {
522 eth_pack= insert_vlan_hdr(eth_port, eth_pack);
523 if (!eth_pack)
524 {
525 /* Packet is silently discarded */
526 return NW_OK;
527 }
528 }
529
530 eth_write_port(rep, eth_pack);
531 return NW_OK;
532}
533
534PUBLIC int eth_read (fd, count)
535int fd;
536size_t count;
537{
538 eth_fd_t *eth_fd;
539 acc_t *pack;
540
541 eth_fd= &eth_fd_table[fd];
542 if (!(eth_fd->ef_flags & EFF_OPTSET))
543 {
544 reply_thr_put(eth_fd, EBADMODE, FALSE);
545 return NW_OK;
546 }
547 if (count < ETH_MAX_PACK_SIZE)
548 {
549 reply_thr_put(eth_fd, EPACKSIZE, FALSE);
550 return NW_OK;
551 }
552
553 assert(!(eth_fd->ef_flags & EFF_READ_IP));
554 eth_fd->ef_flags |= EFF_READ_IP;
555
556 while (eth_fd->ef_rdbuf_head)
557 {
558 pack= eth_fd->ef_rdbuf_head;
559 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
560 if (get_time() <= eth_fd->ef_exp_time)
561 {
562 packet2user(eth_fd, pack, eth_fd->ef_exp_time);
563 if (!(eth_fd->ef_flags & EFF_READ_IP))
564 return NW_OK;
565 }
566 else
567 bf_afree(pack);
568 }
569 return NW_SUSPEND;
570}
571
572PUBLIC int eth_cancel(fd, which_operation)
573int fd;
574int which_operation;
575{
576 eth_fd_t *eth_fd, *prev, *loc_fd;
577 eth_port_t *eth_port;
578
579 DBLOCK(2, printf("eth_cancel (%d)\n", fd));
580 eth_fd= &eth_fd_table[fd];
581
582 switch (which_operation)
583 {
584 case SR_CANCEL_READ:
585 assert (eth_fd->ef_flags & EFF_READ_IP);
586 eth_fd->ef_flags &= ~EFF_READ_IP;
587 reply_thr_put(eth_fd, EINTR, FALSE);
588 break;
589 case SR_CANCEL_WRITE:
590 assert (eth_fd->ef_flags & EFF_WRITE_IP);
591 eth_fd->ef_flags &= ~EFF_WRITE_IP;
592
593 /* Remove fd from send queue */
594 eth_port= eth_fd->ef_port;
595 if (eth_port->etp_vlan_port)
596 eth_port= eth_port->etp_vlan_port;
597 for (prev= 0, loc_fd= eth_port->etp_sendq_head; loc_fd != NULL;
598 prev= loc_fd, loc_fd= loc_fd->ef_send_next)
599 {
600 if (loc_fd == eth_fd)
601 break;
602 }
603 assert(loc_fd == eth_fd);
604 if (prev == NULL)
605 eth_port->etp_sendq_head= loc_fd->ef_send_next;
606 else
607 prev->ef_send_next= loc_fd->ef_send_next;
608 if (loc_fd->ef_send_next == NULL)
609 eth_port->etp_sendq_tail= prev;
610
611 reply_thr_get(eth_fd, EINTR, FALSE);
612 break;
613 case SR_CANCEL_IOCTL:
614 assert (eth_fd->ef_flags & EFF_IOCTL_IP);
615 eth_fd->ef_flags &= ~EFF_IOCTL_IP;
616 reply_thr_get(eth_fd, EINTR, TRUE);
617 break;
618 default:
619 ip_panic(( "got unknown cancel request" ));
620 }
621 return NW_OK;
622}
623
624PUBLIC int eth_select(fd, operations)
625int fd;
626unsigned operations;
627{
628 printf("eth_select: not implemented\n");
629 return 0;
630}
631
632PUBLIC void eth_close(fd)
633int fd;
634{
635 eth_fd_t *eth_fd;
636 eth_port_t *eth_port;
637 acc_t *pack;
638
639 eth_fd= &eth_fd_table[fd];
640
641 assert ((eth_fd->ef_flags & EFF_INUSE) &&
642 !(eth_fd->ef_flags & EFF_BUSY));
643
644 if (eth_fd->ef_flags & EFF_OPTSET)
645 unhash_fd(eth_fd);
646 while (eth_fd->ef_rdbuf_head != NULL)
647 {
648 pack= eth_fd->ef_rdbuf_head;
649 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
650 bf_afree(pack);
651 }
652 eth_fd->ef_flags= EFF_EMPTY;
653
654 eth_port= eth_fd->ef_port;
655 do_rec_conf(eth_port);
656}
657
658PUBLIC void eth_loop_ev(ev, ev_arg)
659event_t *ev;
660ev_arg_t ev_arg;
661{
662 acc_t *pack;
663 eth_port_t *eth_port;
664
665 eth_port= ev_arg.ev_ptr;
666 assert(ev == &eth_port->etp_sendev);
667
668 pack= eth_port->etp_wr_pack;
669
670 assert(!no_ethWritePort);
671 no_ethWritePort= 1;
672 eth_arrive(eth_port, pack, bf_bufsize(pack));
673 assert(no_ethWritePort);
674 no_ethWritePort= 0;
675
676 eth_port->etp_wr_pack= NULL;
677 eth_restart_write(eth_port);
678}
679
680PRIVATE int eth_checkopt (eth_fd)
681eth_fd_t *eth_fd;
682{
683/* bug: we don't check access modes yet */
684
685 unsigned long flags;
686 unsigned int en_di_flags;
687 eth_port_t *eth_port;
688 acc_t *pack;
689
690 eth_port= eth_fd->ef_port;
691 flags= eth_fd->ef_ethopt.nweo_flags;
692 en_di_flags= (flags >>16) | (flags & 0xffff);
693
694 if ((en_di_flags & NWEO_ACC_MASK) &&
695 (en_di_flags & NWEO_LOC_MASK) &&
696 (en_di_flags & NWEO_BROAD_MASK) &&
697 (en_di_flags & NWEO_MULTI_MASK) &&
698 (en_di_flags & NWEO_PROMISC_MASK) &&
699 (en_di_flags & NWEO_REM_MASK) &&
700 (en_di_flags & NWEO_TYPE_MASK) &&
701 (en_di_flags & NWEO_RW_MASK))
702 {
703 eth_fd->ef_flags |= EFF_OPTSET;
704 }
705 else
706 eth_fd->ef_flags &= ~EFF_OPTSET;
707
708 while (eth_fd->ef_rdbuf_head != NULL)
709 {
710 pack= eth_fd->ef_rdbuf_head;
711 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
712 bf_afree(pack);
713 }
714
715 return NW_OK;
716}
717
718PRIVATE void hash_fd(eth_fd)
719eth_fd_t *eth_fd;
720{
721 eth_port_t *eth_port;
722 int hash;
723
724 eth_port= eth_fd->ef_port;
725 if (eth_fd->ef_ethopt.nweo_flags & NWEO_TYPEANY)
726 {
727 eth_fd->ef_type_next= eth_port->etp_type_any;
728 eth_port->etp_type_any= eth_fd;
729 }
730 else
731 {
732 hash= eth_fd->ef_ethopt.nweo_type;
733 hash ^= (hash >> 8);
734 hash &= (ETH_TYPE_HASH_NR-1);
735
736 eth_fd->ef_type_next= eth_port->etp_type[hash];
737 eth_port->etp_type[hash]= eth_fd;
738 }
739}
740
741PRIVATE void unhash_fd(eth_fd)
742eth_fd_t *eth_fd;
743{
744 eth_port_t *eth_port;
745 eth_fd_t *prev, *curr, **eth_fd_p;
746 int hash;
747
748 eth_port= eth_fd->ef_port;
749 if (eth_fd->ef_ethopt.nweo_flags & NWEO_TYPEANY)
750 {
751 eth_fd_p= &eth_port->etp_type_any;
752 }
753 else
754 {
755 hash= eth_fd->ef_ethopt.nweo_type;
756 hash ^= (hash >> 8);
757 hash &= (ETH_TYPE_HASH_NR-1);
758
759 eth_fd_p= &eth_port->etp_type[hash];
760 }
761 for (prev= NULL, curr= *eth_fd_p; curr;
762 prev= curr, curr= curr->ef_type_next)
763 {
764 if (curr == eth_fd)
765 break;
766 }
767 assert(curr);
768 if (prev)
769 prev->ef_type_next= curr->ef_type_next;
770 else
771 *eth_fd_p= curr->ef_type_next;
772}
773
774PUBLIC void eth_restart_write(eth_port)
775eth_port_t *eth_port;
776{
777 eth_fd_t *eth_fd;
778 int r;
779
780 assert(eth_port->etp_wr_pack == NULL);
781 while (eth_fd= eth_port->etp_sendq_head, eth_fd != NULL)
782 {
783 if (eth_port->etp_wr_pack)
784 return;
785 eth_port->etp_sendq_head= eth_fd->ef_send_next;
786
787 assert(eth_fd->ef_flags & EFF_WRITE_IP);
788 eth_fd->ef_flags &= ~EFF_WRITE_IP;
789 r= eth_write(eth_fd-eth_fd_table, eth_fd->ef_write_count);
790 assert(r == NW_OK);
791 }
792}
793
794PUBLIC void eth_arrive (eth_port, pack, pack_size)
795eth_port_t *eth_port;
796acc_t *pack;
797size_t pack_size;
798{
799
800 eth_hdr_t *eth_hdr;
801 ether_addr_t *dst_addr;
802 int pack_stat;
803 ether_type_t type;
804 eth_fd_t *eth_fd, *first_fd, *share_fd;
805 int hash, i;
806 u16_t vlan, temp;
807 time_t exp_time;
808 acc_t *vlan_pack, *hdr_acc, *tmp_acc;
809 eth_port_t *vp;
810 vlan_hdr_t vh;
811 u32_t *p;
812
813 exp_time= get_time() + EXPIRE_TIME;
814
815 pack= bf_packIffLess(pack, ETH_HDR_SIZE);
816
817 eth_hdr= (eth_hdr_t*)ptr2acc_data(pack);
818 dst_addr= &eth_hdr->eh_dst;
819
820 DIFBLOCK(0x20, dst_addr->ea_addr[0] != 0xFF &&
821 (dst_addr->ea_addr[0] & 0x1),
822 printf("got multicast packet\n"));
823
824 if (dst_addr->ea_addr[0] & 0x1)
825 {
826 /* multi cast or broadcast */
827 if (eth_addrcmp(*dst_addr, broadcast) == 0)
828 pack_stat= NWEO_EN_BROAD;
829 else
830 pack_stat= NWEO_EN_MULTI;
831 }
832 else
833 {
834 assert(eth_port->etp_flags & EPF_GOT_ADDR);
835 if (eth_addrcmp (*dst_addr, eth_port->etp_ethaddr) == 0)
836 pack_stat= NWEO_EN_LOC;
837 else
838 pack_stat= NWEO_EN_PROMISC;
839 }
840 type= eth_hdr->eh_proto;
841 hash= type;
842 hash ^= (hash >> 8);
843 hash &= (ETH_TYPE_HASH_NR-1);
844
845 if (type == HTONS(ETH_VLAN_PROTO))
846 {
847 /* VLAN packet. Extract original ethernet packet */
848
849 vlan_pack= pack;
850 vlan_pack->acc_linkC++;
851 hdr_acc= bf_cut(vlan_pack, 0, 2*sizeof(ether_addr_t));
852 vlan_pack= bf_delhead(vlan_pack, 2*sizeof(ether_addr_t));
853 vlan_pack= bf_packIffLess(vlan_pack, sizeof(vh));
854 vh= *(vlan_hdr_t *)ptr2acc_data(vlan_pack);
855 vlan_pack= bf_delhead(vlan_pack, sizeof(vh));
856 hdr_acc= bf_append(hdr_acc, vlan_pack);
857 vlan_pack= hdr_acc; hdr_acc= NULL;
858 if (bf_bufsize(vlan_pack) < ETH_MIN_PACK_SIZE)
859 {
860 tmp_acc= bf_memreq(sizeof(vh));
861
862 /* Clear padding */
863 assert(sizeof(vh) <= sizeof(*p));
864 p= (u32_t *)ptr2acc_data(tmp_acc);
865 *p= 0xdeadbeef;
866
867 vlan_pack= bf_append(vlan_pack, tmp_acc);
868 tmp_acc= NULL;
869 }
870 vlan= ntohs(vh.vh_vlan);
871 if (vlan & ETH_TCI_CFI)
872 {
873 /* No support for extended address formats */
874 bf_afree(vlan_pack); vlan_pack= NULL;
875 }
876 vlan &= ETH_TCI_VLAN_MASK;
877 }
878 else
879 {
880 /* No VLAN processing */
881 vlan_pack= NULL;
882 vlan= 0; /* lint */
883 }
884
885 first_fd= NULL;
886 for (i= 0; i<2; i++)
887 {
888 share_fd= NULL;
889
890 eth_fd= (i == 0) ? eth_port->etp_type_any :
891 eth_port->etp_type[hash];
892 for (; eth_fd; eth_fd= eth_fd->ef_type_next)
893 {
894 if (i && eth_fd->ef_ethopt.nweo_type != type)
895 continue;
896 if (!(eth_fd->ef_ethopt.nweo_flags & pack_stat))
897 continue;
898 if (eth_fd->ef_ethopt.nweo_flags & NWEO_REMSPEC &&
899 eth_addrcmp(eth_hdr->eh_src,
900 eth_fd->ef_ethopt.nweo_rem) != 0)
901 {
902 continue;
903 }
904 if ((eth_fd->ef_ethopt.nweo_flags & NWEO_ACC_MASK) ==
905 NWEO_SHARED)
906 {
907 if (!share_fd)
908 {
909 share_fd= eth_fd;
910 continue;
911 }
912 if (!eth_fd->ef_rdbuf_head)
913 share_fd= eth_fd;
914 continue;
915 }
916 if (!first_fd)
917 {
918 first_fd= eth_fd;
919 continue;
920 }
921 pack->acc_linkC++;
922 packet2user(eth_fd, pack, exp_time);
923 }
924 if (share_fd)
925 {
926 pack->acc_linkC++;
927 packet2user(share_fd, pack, exp_time);
928 }
929 }
930 if (first_fd)
931 {
932 if (first_fd->ef_put_pkt &&
933 (first_fd->ef_flags & EFF_READ_IP) &&
934 !(first_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY))
935 {
936 (*first_fd->ef_put_pkt)(first_fd->ef_srfd, pack,
937 pack_size);
938 }
939 else
940 packet2user(first_fd, pack, exp_time);
941 }
942 else
943 {
944 if (pack_stat == NWEO_EN_LOC)
945 {
946 DBLOCK(0x01,
947 printf("eth_arrive: dropping packet for proto 0x%x\n",
948 ntohs(type)));
949 }
950 else
951 {
952 DBLOCK(0x20, printf("dropping packet for proto 0x%x\n",
953 ntohs(type)));
954 }
955 bf_afree(pack);
956 }
957 if (vlan_pack)
958 {
959 hash= ETH_HASH_VLAN(vlan, temp);
960 for (vp= eth_port->etp_vlan_tab[hash]; vp;
961 vp= vp->etp_vlan_next)
962 {
963 if (vp->etp_vlan == vlan)
964 break;
965 }
966 if (vp)
967 {
968 eth_arrive(vp, vlan_pack, pack_size-sizeof(vh));
969 vlan_pack= NULL;
970 }
971 else
972 {
973 /* No device for VLAN */
974 bf_afree(vlan_pack);
975 vlan_pack= NULL;
976 }
977 }
978}
979
980PUBLIC void eth_reg_vlan(eth_port, vlan_port)
981eth_port_t *eth_port;
982eth_port_t *vlan_port;
983{
984 u16_t t, vlan;
985 int h;
986
987 vlan= vlan_port->etp_vlan;
988 h= ETH_HASH_VLAN(vlan, t);
989 vlan_port->etp_vlan_next= eth_port->etp_vlan_tab[h];
990 eth_port->etp_vlan_tab[h]= vlan_port;
991}
992
993PUBLIC void eth_restart_ioctl(eth_port)
994eth_port_t *eth_port;
995{
996 int i;
997 eth_fd_t *eth_fd;
998
999 for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
1000 {
1001 if (!(eth_fd->ef_flags & EFF_INUSE))
1002 continue;
1003 if (eth_fd->ef_port != eth_port)
1004 continue;
1005 if (!(eth_fd->ef_flags & EFF_IOCTL_IP))
1006 continue;
1007 if (eth_fd->ef_ioctl_req != NWIOGETHSTAT)
1008 continue;
1009
1010 eth_fd->ef_flags &= ~EFF_IOCTL_IP;
1011 eth_ioctl(i, eth_fd->ef_ioctl_req);
1012 }
1013}
1014
1015PRIVATE void packet2user (eth_fd, pack, exp_time)
1016eth_fd_t *eth_fd;
1017acc_t *pack;
1018time_t exp_time;
1019{
1020 int result;
1021 acc_t *tmp_pack;
1022 size_t size;
1023
1024 assert (eth_fd->ef_flags & EFF_INUSE);
1025 if (!(eth_fd->ef_flags & EFF_READ_IP))
1026 {
1027 if (pack->acc_linkC != 1)
1028 {
1029 tmp_pack= bf_dupacc(pack);
1030 bf_afree(pack);
1031 pack= tmp_pack;
1032 tmp_pack= NULL;
1033 }
1034 pack->acc_ext_link= NULL;
1035 if (eth_fd->ef_rdbuf_head == NULL)
1036 {
1037 eth_fd->ef_rdbuf_head= pack;
1038 eth_fd->ef_exp_time= exp_time;
1039 }
1040 else
1041 eth_fd->ef_rdbuf_tail->acc_ext_link= pack;
1042 eth_fd->ef_rdbuf_tail= pack;
1043 return;
1044 }
1045
1046 if (eth_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY)
1047 pack= bf_delhead(pack, ETH_HDR_SIZE);
1048
1049 size= bf_bufsize(pack);
1050
1051 if (eth_fd->ef_put_pkt)
1052 {
1053 (*eth_fd->ef_put_pkt)(eth_fd->ef_srfd, pack, size);
1054 return;
1055 }
1056
1057 eth_fd->ef_flags &= ~EFF_READ_IP;
1058 result= (*eth_fd->ef_put_userdata)(eth_fd->ef_srfd, (size_t)0, pack,
1059 FALSE);
1060 if (result >=0)
1061 reply_thr_put(eth_fd, size, FALSE);
1062 else
1063 reply_thr_put(eth_fd, result, FALSE);
1064}
1065
1066PRIVATE void eth_buffree (priority)
1067int priority;
1068{
1069 int i;
1070 eth_fd_t *eth_fd;
1071 acc_t *pack;
1072
1073 if (priority == ETH_PRI_FDBUFS_EXTRA)
1074 {
1075 for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
1076 {
1077 while (eth_fd->ef_rdbuf_head &&
1078 eth_fd->ef_rdbuf_head->acc_ext_link)
1079 {
1080 pack= eth_fd->ef_rdbuf_head;
1081 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
1082 bf_afree(pack);
1083 }
1084 }
1085 }
1086 if (priority == ETH_PRI_FDBUFS)
1087 {
1088 for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
1089 {
1090 while (eth_fd->ef_rdbuf_head)
1091 {
1092 pack= eth_fd->ef_rdbuf_head;
1093 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
1094 bf_afree(pack);
1095 }
1096 }
1097 }
1098}
1099
1100#ifdef BUF_CONSISTENCY_CHECK
1101PRIVATE void eth_bufcheck()
1102{
1103 int i;
1104 eth_fd_t *eth_fd;
1105 acc_t *pack;
1106
1107 for (i= 0; i<eth_conf_nr; i++)
1108 {
1109 bf_check_acc(eth_port_table[i].etp_rd_pack);
1110 bf_check_acc(eth_port_table[i].etp_wr_pack);
1111 }
1112 for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
1113 {
1114 for (pack= eth_fd->ef_rdbuf_head; pack;
1115 pack= pack->acc_ext_link)
1116 {
1117 bf_check_acc(pack);
1118 }
1119 }
1120}
1121#endif
1122
1123PRIVATE void do_rec_conf(eth_port)
1124eth_port_t *eth_port;
1125{
1126 int i;
1127 u32_t flags;
1128 eth_port_t *vp;
1129
1130 if (eth_port->etp_vlan)
1131 {
1132 /* Configure underlying device */
1133 eth_port= eth_port->etp_vlan_port;
1134 }
1135 flags= compute_rec_conf(eth_port);
1136 for (i= 0; i<ETH_VLAN_HASH_NR; i++)
1137 {
1138 for (vp= eth_port->etp_vlan_tab[i]; vp; vp= vp->etp_vlan_next)
1139 flags |= compute_rec_conf(vp);
1140 }
1141 eth_set_rec_conf(eth_port, flags);
1142}
1143
1144PRIVATE u32_t compute_rec_conf(eth_port)
1145eth_port_t *eth_port;
1146{
1147 eth_fd_t *eth_fd;
1148 u32_t flags;
1149 int i;
1150
1151 flags= NWEO_NOFLAGS;
1152 for (i=0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
1153 {
1154 if ((eth_fd->ef_flags & (EFF_INUSE|EFF_OPTSET)) !=
1155 (EFF_INUSE|EFF_OPTSET))
1156 {
1157 continue;
1158 }
1159 if (eth_fd->ef_port != eth_port)
1160 continue;
1161 flags |= eth_fd->ef_ethopt.nweo_flags;
1162 }
1163 return flags;
1164}
1165
1166PRIVATE void reply_thr_get (eth_fd, result, for_ioctl)
1167eth_fd_t *eth_fd;
1168size_t result;
1169int for_ioctl;
1170{
1171 acc_t *data;
1172
1173 data= (*eth_fd->ef_get_userdata)(eth_fd->ef_srfd, result, 0, for_ioctl);
1174 assert (!data);
1175}
1176
1177PRIVATE void reply_thr_put (eth_fd, result, for_ioctl)
1178eth_fd_t *eth_fd;
1179size_t result;
1180int for_ioctl;
1181{
1182 int error;
1183
1184 error= (*eth_fd->ef_put_userdata)(eth_fd->ef_srfd, result, (acc_t *)0,
1185 for_ioctl);
1186 assert(error == NW_OK);
1187}
1188
1189PRIVATE acc_t *insert_vlan_hdr(eth_port, pack)
1190eth_port_t *eth_port;
1191acc_t *pack;
1192{
1193 acc_t *head_acc, *vh_acc;
1194 u16_t type, vlan;
1195 vlan_hdr_t *vp;
1196
1197 head_acc= bf_cut(pack, 0, 2*sizeof(ether_addr_t));
1198 pack= bf_delhead(pack, 2*sizeof(ether_addr_t));
1199 pack= bf_packIffLess(pack, sizeof(type));
1200 type= *(u16_t *)ptr2acc_data(pack);
1201 if (type == HTONS(ETH_VLAN_PROTO))
1202 {
1203 /* Packeted is already tagged. Should update vlan number.
1204 * For now, just discard packet.
1205 */
1206 printf("insert_vlan_hdr: discarding vlan packet\n");
1207 bf_afree(head_acc); head_acc= NULL;
1208 bf_afree(pack); pack= NULL;
1209 return NULL;
1210 }
1211 vlan= eth_port->etp_vlan; /* priority and CFI are zero */
1212
1213 vh_acc= bf_memreq(sizeof(vlan_hdr_t));
1214 vp= (vlan_hdr_t *)ptr2acc_data(vh_acc);
1215 vp->vh_type= HTONS(ETH_VLAN_PROTO);
1216 vp->vh_vlan= htons(vlan);
1217
1218 head_acc= bf_append(head_acc, vh_acc); vh_acc= NULL;
1219 head_acc= bf_append(head_acc, pack); pack= NULL;
1220 pack= head_acc; head_acc= NULL;
1221 return pack;
1222}
1223
1224/*
1225 * $PchId: eth.c,v 1.23 2005/06/28 14:15:58 philip Exp $
1226 */
Note: See TracBrowser for help on using the repository browser.