phys addr arg of 0 must be possible for pt_writemap too (instead of meaning
[minix.git] / servers / inet / generic / eth.c
blobfba51879c7e44a82f1123aefde41bca8bce01f44
1 /*
2 eth.c
4 Copyright 1995 Philip Homburg
5 */
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"
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"
21 THIS_FILE
23 #define ETH_FD_NR (4*IP_PORT_MAX)
24 #define EXPIRE_TIME 60*HZ /* seconds */
26 typedef struct eth_fd
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 select_res_t ef_select_res;
40 time_t ef_exp_time;
41 size_t ef_write_count;
42 ioreq_t ef_ioctl_req;
43 } eth_fd_t;
45 #define EFF_FLAGS 0xf
46 # define EFF_EMPTY 0x0
47 # define EFF_INUSE 0x1
48 # define EFF_BUSY 0xE
49 # define EFF_READ_IP 0x2
50 # define EFF_WRITE_IP 0x4
51 # define EFF_IOCTL_IP 0x8
52 # define EFF_OPTSET 0x10
53 # define EFF_SEL_READ 0x20
55 /* Note that the vh_type field is normally considered part of the ethernet
56 * header.
58 typedef struct
60 u16_t vh_type;
61 u16_t vh_vlan;
62 } vlan_hdr_t;
64 FORWARD int eth_checkopt ARGS(( eth_fd_t *eth_fd ));
65 FORWARD void hash_fd ARGS(( eth_fd_t *eth_fd ));
66 FORWARD void unhash_fd ARGS(( eth_fd_t *eth_fd ));
67 FORWARD void eth_buffree ARGS(( int priority ));
68 #ifdef BUF_CONSISTENCY_CHECK
69 FORWARD void eth_bufcheck ARGS(( void ));
70 #endif
71 FORWARD int eth_sel_read ARGS(( eth_fd_t * ));
72 FORWARD void packet2user ARGS(( eth_fd_t *fd, acc_t *pack, time_t exp_time ));
73 FORWARD void reply_thr_get ARGS(( eth_fd_t *eth_fd,
74 size_t result, int for_ioctl ));
75 FORWARD void reply_thr_put ARGS(( eth_fd_t *eth_fd,
76 size_t result, int for_ioctl ));
77 FORWARD void do_rec_conf ARGS(( eth_port_t *eth_port ));
78 FORWARD u32_t compute_rec_conf ARGS(( eth_port_t *eth_port ));
79 FORWARD acc_t *insert_vlan_hdr ARGS(( eth_port_t *eth_port, acc_t *pack ));
81 PUBLIC eth_port_t *eth_port_table;
82 PUBLIC int no_ethWritePort= 0;
84 PRIVATE eth_fd_t eth_fd_table[ETH_FD_NR];
85 PRIVATE ether_addr_t broadcast= { { 255, 255, 255, 255, 255, 255 } };
87 PUBLIC void eth_prep()
89 eth_port_table= alloc(eth_conf_nr * sizeof(eth_port_table[0]));
92 PUBLIC void eth_init()
94 int i, j;
96 assert (BUF_S >= sizeof(nwio_ethopt_t));
97 assert (BUF_S >= ETH_HDR_SIZE); /* these are in fact static assertions,
98 thus a good compiler doesn't
99 generate any code for this */
102 for (i=0; i<ETH_FD_NR; i++)
103 eth_fd_table[i].ef_flags= EFF_EMPTY;
104 for (i=0; i<eth_conf_nr; i++)
106 eth_port_table[i].etp_flags= EPF_EMPTY;
107 eth_port_table[i].etp_getstat= NULL;
108 eth_port_table[i].etp_sendq_head= NULL;
109 eth_port_table[i].etp_sendq_tail= NULL;
110 eth_port_table[i].etp_type_any= NULL;
111 ev_init(&eth_port_table[i].etp_sendev);
112 for (j= 0; j<ETH_TYPE_HASH_NR; j++)
113 eth_port_table[i].etp_type[j]= NULL;
114 for (j= 0; j<ETH_VLAN_HASH_NR; j++)
115 eth_port_table[i].etp_vlan_tab[j]= NULL;
118 #ifndef BUF_CONSISTENCY_CHECK
119 bf_logon(eth_buffree);
120 #else
121 bf_logon(eth_buffree, eth_bufcheck);
122 #endif
124 osdep_eth_init();
127 PUBLIC int eth_open(port, srfd, get_userdata, put_userdata, put_pkt,
128 select_res)
129 int port, srfd;
130 get_userdata_t get_userdata;
131 put_userdata_t put_userdata;
132 put_pkt_t put_pkt;
133 select_res_t select_res;
135 int i;
136 eth_port_t *eth_port;
137 eth_fd_t *eth_fd;
139 DBLOCK(0x20, printf("eth_open (%d, %d, %lx, %lx)\n", port, srfd,
140 (unsigned long)get_userdata, (unsigned long)put_userdata));
141 eth_port= &eth_port_table[port];
142 if (!(eth_port->etp_flags & EPF_ENABLED))
143 return EGENERIC;
145 for (i=0; i<ETH_FD_NR && (eth_fd_table[i].ef_flags & EFF_INUSE);
146 i++);
148 if (i>=ETH_FD_NR)
150 DBLOCK(1, printf("out of fds\n"));
151 return EAGAIN;
154 eth_fd= &eth_fd_table[i];
156 eth_fd->ef_flags= EFF_INUSE;
157 eth_fd->ef_ethopt.nweo_flags=NWEO_DEFAULT;
158 eth_fd->ef_port= eth_port;
159 eth_fd->ef_srfd= srfd;
160 assert(eth_fd->ef_rdbuf_head == NULL);
161 eth_fd->ef_get_userdata= get_userdata;
162 eth_fd->ef_put_userdata= put_userdata;
163 eth_fd->ef_put_pkt= put_pkt;
164 eth_fd->ef_select_res= select_res;
166 return i;
169 PUBLIC int eth_ioctl(fd, req)
170 int fd;
171 ioreq_t req;
173 acc_t *data;
174 eth_fd_t *eth_fd;
175 eth_port_t *eth_port;
177 DBLOCK(0x20, printf("eth_ioctl (%d, 0x%lx)\n", fd, (unsigned long)req));
178 eth_fd= &eth_fd_table[fd];
179 eth_port= eth_fd->ef_port;
181 assert (eth_fd->ef_flags & EFF_INUSE);
183 switch (req)
185 case NWIOSETHOPT:
187 nwio_ethopt_t *ethopt;
188 nwio_ethopt_t oldopt, newopt;
189 int result;
190 u32_t new_en_flags, new_di_flags,
191 old_en_flags, old_di_flags;
193 data= (*eth_fd->ef_get_userdata)(eth_fd->
194 ef_srfd, 0, sizeof(nwio_ethopt_t), TRUE);
196 ethopt= (nwio_ethopt_t *)ptr2acc_data(data);
197 oldopt= eth_fd->ef_ethopt;
198 newopt= *ethopt;
200 old_en_flags= oldopt.nweo_flags & 0xffff;
201 old_di_flags= (oldopt.nweo_flags >> 16) & 0xffff;
202 new_en_flags= newopt.nweo_flags & 0xffff;
203 new_di_flags= (newopt.nweo_flags >> 16) & 0xffff;
204 if (new_en_flags & new_di_flags)
206 bf_afree(data);
207 reply_thr_get (eth_fd, EBADMODE, TRUE);
208 return NW_OK;
211 /* NWEO_ACC_MASK */
212 if (new_di_flags & NWEO_ACC_MASK)
214 bf_afree(data);
215 reply_thr_get (eth_fd, EBADMODE, TRUE);
216 return NW_OK;
218 /* you can't disable access modes */
220 if (!(new_en_flags & NWEO_ACC_MASK))
221 new_en_flags |= (old_en_flags & NWEO_ACC_MASK);
224 /* NWEO_LOC_MASK */
225 if (!((new_en_flags | new_di_flags) & NWEO_LOC_MASK))
227 new_en_flags |= (old_en_flags & NWEO_LOC_MASK);
228 new_di_flags |= (old_di_flags & NWEO_LOC_MASK);
231 /* NWEO_BROAD_MASK */
232 if (!((new_en_flags | new_di_flags) & NWEO_BROAD_MASK))
234 new_en_flags |= (old_en_flags & NWEO_BROAD_MASK);
235 new_di_flags |= (old_di_flags & NWEO_BROAD_MASK);
238 /* NWEO_MULTI_MASK */
239 if (!((new_en_flags | new_di_flags) & NWEO_MULTI_MASK))
241 new_en_flags |= (old_en_flags & NWEO_MULTI_MASK);
242 new_di_flags |= (old_di_flags & NWEO_MULTI_MASK);
243 newopt.nweo_multi= oldopt.nweo_multi;
246 /* NWEO_PROMISC_MASK */
247 if (!((new_en_flags | new_di_flags) & NWEO_PROMISC_MASK))
249 new_en_flags |= (old_en_flags & NWEO_PROMISC_MASK);
250 new_di_flags |= (old_di_flags & NWEO_PROMISC_MASK);
253 /* NWEO_REM_MASK */
254 if (!((new_en_flags | new_di_flags) & NWEO_REM_MASK))
256 new_en_flags |= (old_en_flags & NWEO_REM_MASK);
257 new_di_flags |= (old_di_flags & NWEO_REM_MASK);
258 newopt.nweo_rem= oldopt.nweo_rem;
261 /* NWEO_TYPE_MASK */
262 if (!((new_en_flags | new_di_flags) & NWEO_TYPE_MASK))
264 new_en_flags |= (old_en_flags & NWEO_TYPE_MASK);
265 new_di_flags |= (old_di_flags & NWEO_TYPE_MASK);
266 newopt.nweo_type= oldopt.nweo_type;
269 /* NWEO_RW_MASK */
270 if (!((new_en_flags | new_di_flags) & NWEO_RW_MASK))
272 new_en_flags |= (old_en_flags & NWEO_RW_MASK);
273 new_di_flags |= (old_di_flags & NWEO_RW_MASK);
276 if (eth_fd->ef_flags & EFF_OPTSET)
277 unhash_fd(eth_fd);
279 newopt.nweo_flags= ((unsigned long)new_di_flags << 16) |
280 new_en_flags;
281 eth_fd->ef_ethopt= newopt;
283 result= eth_checkopt(eth_fd);
285 if (result<0)
286 eth_fd->ef_ethopt= oldopt;
287 else
289 unsigned long opt_flags;
290 unsigned changes;
291 opt_flags= oldopt.nweo_flags ^
292 eth_fd->ef_ethopt.nweo_flags;
293 changes= ((opt_flags >> 16) | opt_flags) &
294 0xffff;
295 if (changes & (NWEO_BROAD_MASK |
296 NWEO_MULTI_MASK | NWEO_PROMISC_MASK))
298 do_rec_conf(eth_port);
302 if (eth_fd->ef_flags & EFF_OPTSET)
303 hash_fd(eth_fd);
305 bf_afree(data);
306 reply_thr_get (eth_fd, result, TRUE);
307 return NW_OK;
310 case NWIOGETHOPT:
312 nwio_ethopt_t *ethopt;
313 acc_t *acc;
314 int result;
316 acc= bf_memreq(sizeof(nwio_ethopt_t));
318 ethopt= (nwio_ethopt_t *)ptr2acc_data(acc);
320 *ethopt= eth_fd->ef_ethopt;
322 result= (*eth_fd->ef_put_userdata)(eth_fd->
323 ef_srfd, 0, acc, TRUE);
324 if (result >= 0)
325 reply_thr_put(eth_fd, NW_OK, TRUE);
326 return result;
328 case NWIOGETHSTAT:
330 nwio_ethstat_t *ethstat;
331 acc_t *acc;
332 int result;
334 assert (sizeof(nwio_ethstat_t) <= BUF_S);
336 eth_port= eth_fd->ef_port;
337 if (!(eth_port->etp_flags & EPF_ENABLED))
339 reply_thr_put(eth_fd, EGENERIC, TRUE);
340 return NW_OK;
343 if (!(eth_port->etp_flags & EPF_GOT_ADDR))
345 #if 0
346 printf(
347 "eth_ioctl: suspending NWIOGETHSTAT ioctl\n");
348 #endif
350 eth_fd->ef_ioctl_req= req;
351 assert(!(eth_fd->ef_flags & EFF_IOCTL_IP));
352 eth_fd->ef_flags |= EFF_IOCTL_IP;
353 return NW_SUSPEND;
356 if (eth_port->etp_getstat)
358 printf(
359 "eth_ioctl: pending eth_get_stat request, suspending caller\n");
360 assert(!(eth_fd->ef_flags & EFF_IOCTL_IP));
361 eth_fd->ef_flags |= EFF_IOCTL_IP;
362 return NW_SUSPEND;
365 acc= bf_memreq(sizeof(nwio_ethstat_t));
366 compare (bf_bufsize(acc), ==, sizeof(*ethstat));
368 ethstat= (nwio_ethstat_t *)ptr2acc_data(acc);
369 ethstat->nwes_addr= eth_port->etp_ethaddr;
371 if (!eth_port->etp_vlan)
373 result= eth_get_stat(eth_port,
374 &ethstat->nwes_stat);
375 if (result == SUSPEND)
377 #if 0
378 printf(
379 "eth_ioctl: eth_get_stat returned SUSPEND\n");
380 #endif
381 eth_fd->ef_ioctl_req= req;
382 assert(!(eth_fd->ef_flags &
383 EFF_IOCTL_IP));
384 eth_fd->ef_flags |= EFF_IOCTL_IP;
385 #if 0
386 printf("eth_ioctl: setting etp_getstat in port %d to %p\n",
387 eth_port-eth_port_table, acc);
388 #endif
389 eth_port->etp_getstat= acc;
390 acc= NULL;
391 return NW_SUSPEND;
393 if (result != NW_OK)
395 bf_afree(acc);
396 reply_thr_put(eth_fd, result, TRUE);
397 return NW_OK;
400 else
402 /* No statistics */
403 memset(&ethstat->nwes_stat, '\0',
404 sizeof(ethstat->nwes_stat));
407 result= (*eth_fd->ef_put_userdata)(eth_fd->
408 ef_srfd, 0, acc, TRUE);
409 if (result >= 0)
410 reply_thr_put(eth_fd, NW_OK, TRUE);
411 return result;
413 default:
414 break;
416 reply_thr_put(eth_fd, EBADIOCTL, TRUE);
417 return NW_OK;
420 PUBLIC int eth_write(fd, count)
421 int fd;
422 size_t count;
424 eth_fd_t *eth_fd;
425 eth_port_t *eth_port, *rep;
426 acc_t *user_data;
427 int r;
429 eth_fd= &eth_fd_table[fd];
430 eth_port= eth_fd->ef_port;
432 if (!(eth_fd->ef_flags & EFF_OPTSET))
434 reply_thr_get (eth_fd, EBADMODE, FALSE);
435 return NW_OK;
438 assert (!(eth_fd->ef_flags & EFF_WRITE_IP));
440 eth_fd->ef_write_count= count;
441 if (eth_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY)
442 count += ETH_HDR_SIZE;
444 if (count<ETH_MIN_PACK_SIZE || count>ETH_MAX_PACK_SIZE)
446 DBLOCK(1, printf("illegal packetsize (%d)\n",count));
447 reply_thr_get (eth_fd, EPACKSIZE, FALSE);
448 return NW_OK;
450 eth_fd->ef_flags |= EFF_WRITE_IP;
452 /* Enqueue at the real ethernet port */
453 rep= eth_port->etp_vlan_port;
454 if (!rep)
455 rep= eth_port;
456 if (rep->etp_wr_pack)
458 eth_fd->ef_send_next= NULL;
459 if (rep->etp_sendq_head)
460 rep->etp_sendq_tail->ef_send_next= eth_fd;
461 else
462 rep->etp_sendq_head= eth_fd;
463 rep->etp_sendq_tail= eth_fd;
464 return NW_SUSPEND;
467 user_data= (*eth_fd->ef_get_userdata)(eth_fd->ef_srfd, 0,
468 eth_fd->ef_write_count, FALSE);
469 if (!user_data)
471 eth_fd->ef_flags &= ~EFF_WRITE_IP;
472 reply_thr_get (eth_fd, EFAULT, FALSE);
473 return NW_OK;
475 r= eth_send(fd, user_data, eth_fd->ef_write_count);
476 assert(r == NW_OK);
478 eth_fd->ef_flags &= ~EFF_WRITE_IP;
479 reply_thr_get(eth_fd, eth_fd->ef_write_count, FALSE);
480 return NW_OK;
483 PUBLIC int eth_send(fd, data, data_len)
484 int fd;
485 acc_t *data;
486 size_t data_len;
488 eth_fd_t *eth_fd;
489 eth_port_t *eth_port, *rep;
490 eth_hdr_t *eth_hdr;
491 acc_t *eth_pack;
492 unsigned long nweo_flags;
493 size_t count;
494 ev_arg_t ev_arg;
496 eth_fd= &eth_fd_table[fd];
497 eth_port= eth_fd->ef_port;
499 if (!(eth_fd->ef_flags & EFF_OPTSET))
500 return EBADMODE;
502 count= data_len;
503 if (eth_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY)
504 count += ETH_HDR_SIZE;
506 if (count<ETH_MIN_PACK_SIZE || count>ETH_MAX_PACK_SIZE)
508 DBLOCK(1, printf("illegal packetsize (%d)\n",count));
509 return EPACKSIZE;
511 rep= eth_port->etp_vlan_port;
512 if (!rep)
513 rep= eth_port;
515 if (rep->etp_wr_pack)
516 return NW_WOULDBLOCK;
518 nweo_flags= eth_fd->ef_ethopt.nweo_flags;
519 if (nweo_flags & NWEO_RWDATONLY)
521 eth_pack= bf_memreq(ETH_HDR_SIZE);
522 eth_pack->acc_next= data;
524 else
525 eth_pack= bf_packIffLess(data, ETH_HDR_SIZE);
527 eth_hdr= (eth_hdr_t *)ptr2acc_data(eth_pack);
529 if (nweo_flags & NWEO_REMSPEC)
530 eth_hdr->eh_dst= eth_fd->ef_ethopt.nweo_rem;
532 if (!(eth_port->etp_flags & EPF_GOT_ADDR))
534 /* No device, discard packet */
535 bf_afree(eth_pack);
536 return NW_OK;
539 if (!(nweo_flags & NWEO_EN_PROMISC))
540 eth_hdr->eh_src= eth_port->etp_ethaddr;
542 if (nweo_flags & NWEO_TYPESPEC)
543 eth_hdr->eh_proto= eth_fd->ef_ethopt.nweo_type;
545 if (eth_addrcmp(eth_hdr->eh_dst, eth_port->etp_ethaddr) == 0)
547 /* Local loopback. */
548 eth_port->etp_wr_pack= eth_pack;
549 ev_arg.ev_ptr= eth_port;
550 ev_enqueue(&eth_port->etp_sendev, eth_loop_ev, ev_arg);
551 return NW_OK;
554 if (rep != eth_port)
556 eth_pack= insert_vlan_hdr(eth_port, eth_pack);
557 if (!eth_pack)
559 /* Packet is silently discarded */
560 return NW_OK;
564 eth_write_port(rep, eth_pack);
565 return NW_OK;
568 PUBLIC int eth_read (fd, count)
569 int fd;
570 size_t count;
572 eth_fd_t *eth_fd;
573 acc_t *pack;
575 eth_fd= &eth_fd_table[fd];
576 if (!(eth_fd->ef_flags & EFF_OPTSET))
578 reply_thr_put(eth_fd, EBADMODE, FALSE);
579 return NW_OK;
581 if (count < ETH_MAX_PACK_SIZE)
583 reply_thr_put(eth_fd, EPACKSIZE, FALSE);
584 return NW_OK;
587 assert(!(eth_fd->ef_flags & EFF_READ_IP));
588 eth_fd->ef_flags |= EFF_READ_IP;
590 while (eth_fd->ef_rdbuf_head)
592 pack= eth_fd->ef_rdbuf_head;
593 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
594 if (get_time() <= eth_fd->ef_exp_time)
596 packet2user(eth_fd, pack, eth_fd->ef_exp_time);
597 if (!(eth_fd->ef_flags & EFF_READ_IP))
598 return NW_OK;
600 else
601 bf_afree(pack);
603 return NW_SUSPEND;
606 PUBLIC int eth_cancel(fd, which_operation)
607 int fd;
608 int which_operation;
610 eth_fd_t *eth_fd, *prev, *loc_fd;
611 eth_port_t *eth_port;
613 DBLOCK(2, printf("eth_cancel (%d)\n", fd));
614 eth_fd= &eth_fd_table[fd];
616 switch (which_operation)
618 case SR_CANCEL_READ:
619 assert (eth_fd->ef_flags & EFF_READ_IP);
620 eth_fd->ef_flags &= ~EFF_READ_IP;
621 reply_thr_put(eth_fd, EINTR, FALSE);
622 break;
623 case SR_CANCEL_WRITE:
624 assert (eth_fd->ef_flags & EFF_WRITE_IP);
625 eth_fd->ef_flags &= ~EFF_WRITE_IP;
627 /* Remove fd from send queue */
628 eth_port= eth_fd->ef_port;
629 if (eth_port->etp_vlan_port)
630 eth_port= eth_port->etp_vlan_port;
631 for (prev= 0, loc_fd= eth_port->etp_sendq_head; loc_fd != NULL;
632 prev= loc_fd, loc_fd= loc_fd->ef_send_next)
634 if (loc_fd == eth_fd)
635 break;
637 assert(loc_fd == eth_fd);
638 if (prev == NULL)
639 eth_port->etp_sendq_head= loc_fd->ef_send_next;
640 else
641 prev->ef_send_next= loc_fd->ef_send_next;
642 if (loc_fd->ef_send_next == NULL)
643 eth_port->etp_sendq_tail= prev;
645 reply_thr_get(eth_fd, EINTR, FALSE);
646 break;
647 case SR_CANCEL_IOCTL:
648 assert (eth_fd->ef_flags & EFF_IOCTL_IP);
649 eth_fd->ef_flags &= ~EFF_IOCTL_IP;
650 reply_thr_get(eth_fd, EINTR, TRUE);
651 break;
652 default:
653 ip_panic(( "got unknown cancel request" ));
655 return NW_OK;
658 PUBLIC int eth_select(fd, operations)
659 int fd;
660 unsigned operations;
662 int i;
663 unsigned resops;
664 eth_fd_t *eth_fd;
666 eth_fd= &eth_fd_table[fd];
667 assert (eth_fd->ef_flags & EFF_INUSE);
669 resops= 0;
671 if (operations & SR_SELECT_READ)
673 if (eth_sel_read(eth_fd))
674 resops |= SR_SELECT_READ;
675 else if (!(operations & SR_SELECT_POLL))
676 eth_fd->ef_flags |= EFF_SEL_READ;
678 if (operations & SR_SELECT_WRITE)
680 /* Should handle special case when the interface is down */
681 resops |= SR_SELECT_WRITE;
683 if (operations & SR_SELECT_EXCEPTION)
685 printf("eth_select: not implemented for exceptions\n");
687 return resops;
690 PUBLIC void eth_close(fd)
691 int fd;
693 eth_fd_t *eth_fd;
694 eth_port_t *eth_port;
695 acc_t *pack;
697 eth_fd= &eth_fd_table[fd];
699 assert ((eth_fd->ef_flags & EFF_INUSE) &&
700 !(eth_fd->ef_flags & EFF_BUSY));
702 if (eth_fd->ef_flags & EFF_OPTSET)
703 unhash_fd(eth_fd);
704 while (eth_fd->ef_rdbuf_head != NULL)
706 pack= eth_fd->ef_rdbuf_head;
707 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
708 bf_afree(pack);
710 eth_fd->ef_flags= EFF_EMPTY;
712 eth_port= eth_fd->ef_port;
713 do_rec_conf(eth_port);
716 PUBLIC void eth_loop_ev(ev, ev_arg)
717 event_t *ev;
718 ev_arg_t ev_arg;
720 acc_t *pack;
721 eth_port_t *eth_port;
723 eth_port= ev_arg.ev_ptr;
724 assert(ev == &eth_port->etp_sendev);
726 pack= eth_port->etp_wr_pack;
728 assert(!no_ethWritePort);
729 no_ethWritePort= 1;
730 eth_arrive(eth_port, pack, bf_bufsize(pack));
731 assert(no_ethWritePort);
732 no_ethWritePort= 0;
734 eth_port->etp_wr_pack= NULL;
735 eth_restart_write(eth_port);
738 PRIVATE int eth_checkopt (eth_fd)
739 eth_fd_t *eth_fd;
741 /* bug: we don't check access modes yet */
743 unsigned long flags;
744 unsigned int en_di_flags;
745 eth_port_t *eth_port;
746 acc_t *pack;
748 eth_port= eth_fd->ef_port;
749 flags= eth_fd->ef_ethopt.nweo_flags;
750 en_di_flags= (flags >>16) | (flags & 0xffff);
752 if ((en_di_flags & NWEO_ACC_MASK) &&
753 (en_di_flags & NWEO_LOC_MASK) &&
754 (en_di_flags & NWEO_BROAD_MASK) &&
755 (en_di_flags & NWEO_MULTI_MASK) &&
756 (en_di_flags & NWEO_PROMISC_MASK) &&
757 (en_di_flags & NWEO_REM_MASK) &&
758 (en_di_flags & NWEO_TYPE_MASK) &&
759 (en_di_flags & NWEO_RW_MASK))
761 eth_fd->ef_flags |= EFF_OPTSET;
763 else
764 eth_fd->ef_flags &= ~EFF_OPTSET;
766 while (eth_fd->ef_rdbuf_head != NULL)
768 pack= eth_fd->ef_rdbuf_head;
769 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
770 bf_afree(pack);
773 return NW_OK;
776 PRIVATE void hash_fd(eth_fd)
777 eth_fd_t *eth_fd;
779 eth_port_t *eth_port;
780 int hash;
782 eth_port= eth_fd->ef_port;
783 if (eth_fd->ef_ethopt.nweo_flags & NWEO_TYPEANY)
785 eth_fd->ef_type_next= eth_port->etp_type_any;
786 eth_port->etp_type_any= eth_fd;
788 else
790 hash= eth_fd->ef_ethopt.nweo_type;
791 hash ^= (hash >> 8);
792 hash &= (ETH_TYPE_HASH_NR-1);
794 eth_fd->ef_type_next= eth_port->etp_type[hash];
795 eth_port->etp_type[hash]= eth_fd;
799 PRIVATE void unhash_fd(eth_fd)
800 eth_fd_t *eth_fd;
802 eth_port_t *eth_port;
803 eth_fd_t *prev, *curr, **eth_fd_p;
804 int hash;
806 eth_port= eth_fd->ef_port;
807 if (eth_fd->ef_ethopt.nweo_flags & NWEO_TYPEANY)
809 eth_fd_p= &eth_port->etp_type_any;
811 else
813 hash= eth_fd->ef_ethopt.nweo_type;
814 hash ^= (hash >> 8);
815 hash &= (ETH_TYPE_HASH_NR-1);
817 eth_fd_p= &eth_port->etp_type[hash];
819 for (prev= NULL, curr= *eth_fd_p; curr;
820 prev= curr, curr= curr->ef_type_next)
822 if (curr == eth_fd)
823 break;
825 assert(curr);
826 if (prev)
827 prev->ef_type_next= curr->ef_type_next;
828 else
829 *eth_fd_p= curr->ef_type_next;
832 PUBLIC void eth_restart_write(eth_port)
833 eth_port_t *eth_port;
835 eth_fd_t *eth_fd;
836 int r;
838 assert(eth_port->etp_wr_pack == NULL);
839 while (eth_fd= eth_port->etp_sendq_head, eth_fd != NULL)
841 if (eth_port->etp_wr_pack)
842 return;
843 eth_port->etp_sendq_head= eth_fd->ef_send_next;
845 assert(eth_fd->ef_flags & EFF_WRITE_IP);
846 eth_fd->ef_flags &= ~EFF_WRITE_IP;
847 r= eth_write(eth_fd-eth_fd_table, eth_fd->ef_write_count);
848 assert(r == NW_OK);
852 PUBLIC void eth_arrive (eth_port, pack, pack_size)
853 eth_port_t *eth_port;
854 acc_t *pack;
855 size_t pack_size;
858 eth_hdr_t *eth_hdr;
859 ether_addr_t *dst_addr;
860 int pack_stat;
861 ether_type_t type;
862 eth_fd_t *eth_fd, *first_fd, *share_fd;
863 int hash, i;
864 u16_t vlan, temp;
865 time_t exp_time;
866 acc_t *vlan_pack, *hdr_acc, *tmp_acc;
867 eth_port_t *vp;
868 vlan_hdr_t vh;
869 u32_t *p;
871 exp_time= get_time() + EXPIRE_TIME;
873 pack= bf_packIffLess(pack, ETH_HDR_SIZE);
875 eth_hdr= (eth_hdr_t*)ptr2acc_data(pack);
876 dst_addr= &eth_hdr->eh_dst;
878 DIFBLOCK(0x20, dst_addr->ea_addr[0] != 0xFF &&
879 (dst_addr->ea_addr[0] & 0x1),
880 printf("got multicast packet\n"));
882 if (dst_addr->ea_addr[0] & 0x1)
884 /* multi cast or broadcast */
885 if (eth_addrcmp(*dst_addr, broadcast) == 0)
886 pack_stat= NWEO_EN_BROAD;
887 else
888 pack_stat= NWEO_EN_MULTI;
890 else
892 assert(eth_port->etp_flags & EPF_GOT_ADDR);
893 if (eth_addrcmp (*dst_addr, eth_port->etp_ethaddr) == 0)
894 pack_stat= NWEO_EN_LOC;
895 else
896 pack_stat= NWEO_EN_PROMISC;
898 type= eth_hdr->eh_proto;
899 hash= type;
900 hash ^= (hash >> 8);
901 hash &= (ETH_TYPE_HASH_NR-1);
903 if (type == HTONS(ETH_VLAN_PROTO))
905 /* VLAN packet. Extract original ethernet packet */
907 vlan_pack= pack;
908 vlan_pack->acc_linkC++;
909 hdr_acc= bf_cut(vlan_pack, 0, 2*sizeof(ether_addr_t));
910 vlan_pack= bf_delhead(vlan_pack, 2*sizeof(ether_addr_t));
911 vlan_pack= bf_packIffLess(vlan_pack, sizeof(vh));
912 vh= *(vlan_hdr_t *)ptr2acc_data(vlan_pack);
913 vlan_pack= bf_delhead(vlan_pack, sizeof(vh));
914 hdr_acc= bf_append(hdr_acc, vlan_pack);
915 vlan_pack= hdr_acc; hdr_acc= NULL;
916 if (bf_bufsize(vlan_pack) < ETH_MIN_PACK_SIZE)
918 tmp_acc= bf_memreq(sizeof(vh));
920 /* Clear padding */
921 assert(sizeof(vh) <= sizeof(*p));
922 p= (u32_t *)ptr2acc_data(tmp_acc);
923 *p= 0xdeadbeef;
925 vlan_pack= bf_append(vlan_pack, tmp_acc);
926 tmp_acc= NULL;
928 vlan= ntohs(vh.vh_vlan);
929 if (vlan & ETH_TCI_CFI)
931 /* No support for extended address formats */
932 bf_afree(vlan_pack); vlan_pack= NULL;
934 vlan &= ETH_TCI_VLAN_MASK;
936 else
938 /* No VLAN processing */
939 vlan_pack= NULL;
940 vlan= 0; /* lint */
943 first_fd= NULL;
944 for (i= 0; i<2; i++)
946 share_fd= NULL;
948 eth_fd= (i == 0) ? eth_port->etp_type_any :
949 eth_port->etp_type[hash];
950 for (; eth_fd; eth_fd= eth_fd->ef_type_next)
952 if (i && eth_fd->ef_ethopt.nweo_type != type)
953 continue;
954 if (!(eth_fd->ef_ethopt.nweo_flags & pack_stat))
955 continue;
956 if (eth_fd->ef_ethopt.nweo_flags & NWEO_REMSPEC &&
957 eth_addrcmp(eth_hdr->eh_src,
958 eth_fd->ef_ethopt.nweo_rem) != 0)
960 continue;
962 if ((eth_fd->ef_ethopt.nweo_flags & NWEO_ACC_MASK) ==
963 NWEO_SHARED)
965 if (!share_fd)
967 share_fd= eth_fd;
968 continue;
970 if (!eth_fd->ef_rdbuf_head)
971 share_fd= eth_fd;
972 continue;
974 if (!first_fd)
976 first_fd= eth_fd;
977 continue;
979 pack->acc_linkC++;
980 packet2user(eth_fd, pack, exp_time);
982 if (share_fd)
984 pack->acc_linkC++;
985 packet2user(share_fd, pack, exp_time);
988 if (first_fd)
990 if (first_fd->ef_put_pkt &&
991 (first_fd->ef_flags & EFF_READ_IP) &&
992 !(first_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY))
994 (*first_fd->ef_put_pkt)(first_fd->ef_srfd, pack,
995 pack_size);
997 else
998 packet2user(first_fd, pack, exp_time);
1000 else
1002 if (pack_stat == NWEO_EN_LOC)
1004 DBLOCK(0x01,
1005 printf("eth_arrive: dropping packet for proto 0x%x\n",
1006 ntohs(type)));
1008 else
1010 DBLOCK(0x20, printf("dropping packet for proto 0x%x\n",
1011 ntohs(type)));
1013 bf_afree(pack);
1015 if (vlan_pack)
1017 hash= ETH_HASH_VLAN(vlan, temp);
1018 for (vp= eth_port->etp_vlan_tab[hash]; vp;
1019 vp= vp->etp_vlan_next)
1021 if (vp->etp_vlan == vlan)
1022 break;
1024 if (vp)
1026 eth_arrive(vp, vlan_pack, pack_size-sizeof(vh));
1027 vlan_pack= NULL;
1029 else
1031 /* No device for VLAN */
1032 bf_afree(vlan_pack);
1033 vlan_pack= NULL;
1038 PUBLIC void eth_reg_vlan(eth_port, vlan_port)
1039 eth_port_t *eth_port;
1040 eth_port_t *vlan_port;
1042 u16_t t, vlan;
1043 int h;
1045 vlan= vlan_port->etp_vlan;
1046 h= ETH_HASH_VLAN(vlan, t);
1047 vlan_port->etp_vlan_next= eth_port->etp_vlan_tab[h];
1048 eth_port->etp_vlan_tab[h]= vlan_port;
1051 PUBLIC void eth_restart_ioctl(eth_port)
1052 eth_port_t *eth_port;
1054 int i, r;
1055 eth_fd_t *eth_fd;
1056 acc_t *acc;
1058 #if 0
1059 printf("in eth_restart_ioctl\n");
1060 #endif
1062 /* eth_restart_ioctl is called on too occasions: when a device
1063 * driver registers with inet and when a eth_get_stat call has
1064 * completed. We assume the second option when etp_getstat is
1065 * not equal to zero at the start of the call.
1067 acc= eth_port->etp_getstat;
1069 for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
1071 if (!(eth_fd->ef_flags & EFF_INUSE))
1072 continue;
1073 if (eth_fd->ef_port != eth_port)
1074 continue;
1075 if (!(eth_fd->ef_flags & EFF_IOCTL_IP))
1076 continue;
1077 if (eth_fd->ef_ioctl_req != NWIOGETHSTAT)
1078 continue;
1080 #if 0
1081 printf("eth_restart_ioctl: etp_getstat in port %d is %p\n",
1082 eth_port-eth_port_table, acc);
1083 #endif
1085 if (acc != NULL)
1087 #if 0
1088 printf("eth_restart_ioctl: completed getstat\n");
1089 #endif
1090 acc->acc_linkC++;
1091 r= (*eth_fd->ef_put_userdata)(eth_fd->ef_srfd, 0,
1092 acc, TRUE);
1093 if (r >= 0)
1094 reply_thr_put(eth_fd, NW_OK, TRUE);
1095 eth_fd->ef_flags &= ~EFF_IOCTL_IP;
1096 continue;
1099 { static int count; if (++count > 5) ip_panic(("too many restarts")); }
1101 eth_fd->ef_flags &= ~EFF_IOCTL_IP;
1102 eth_ioctl(i, eth_fd->ef_ioctl_req);
1105 if (acc != NULL)
1107 #if 0
1108 printf("eth_restart_ioctl: clearing etp_getstat in port %d\n",
1109 eth_port-eth_port_table);
1110 #endif
1111 assert(acc == eth_port->etp_getstat);
1113 bf_afree(acc);
1114 eth_port->etp_getstat= NULL;
1118 PRIVATE int eth_sel_read (eth_fd)
1119 eth_fd_t *eth_fd;
1121 acc_t *pack, *tmp_acc, *next_acc;
1122 int result;
1124 if (!(eth_fd->ef_flags & EFF_OPTSET))
1125 return 1; /* Read will not block */
1127 if (eth_fd->ef_rdbuf_head)
1129 if (get_time() <= eth_fd->ef_exp_time)
1130 return 1;
1132 tmp_acc= eth_fd->ef_rdbuf_head;
1133 while (tmp_acc)
1135 next_acc= tmp_acc->acc_ext_link;
1136 bf_afree(tmp_acc);
1137 tmp_acc= next_acc;
1139 eth_fd->ef_rdbuf_head= NULL;
1141 return 0;
1144 PRIVATE void packet2user (eth_fd, pack, exp_time)
1145 eth_fd_t *eth_fd;
1146 acc_t *pack;
1147 time_t exp_time;
1149 int result;
1150 acc_t *tmp_pack;
1151 size_t size;
1153 assert (eth_fd->ef_flags & EFF_INUSE);
1154 if (!(eth_fd->ef_flags & EFF_READ_IP))
1156 if (pack->acc_linkC != 1)
1158 tmp_pack= bf_dupacc(pack);
1159 bf_afree(pack);
1160 pack= tmp_pack;
1161 tmp_pack= NULL;
1163 pack->acc_ext_link= NULL;
1164 if (eth_fd->ef_rdbuf_head == NULL)
1166 eth_fd->ef_rdbuf_head= pack;
1167 eth_fd->ef_exp_time= exp_time;
1169 else
1170 eth_fd->ef_rdbuf_tail->acc_ext_link= pack;
1171 eth_fd->ef_rdbuf_tail= pack;
1173 if (eth_fd->ef_flags & EFF_SEL_READ)
1175 eth_fd->ef_flags &= ~EFF_SEL_READ;
1176 if (eth_fd->ef_select_res)
1177 eth_fd->ef_select_res(eth_fd->ef_srfd, SR_SELECT_READ);
1178 else
1179 printf("packet2user: no select_res\n");
1181 return;
1184 if (eth_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY)
1185 pack= bf_delhead(pack, ETH_HDR_SIZE);
1187 size= bf_bufsize(pack);
1189 if (eth_fd->ef_put_pkt)
1191 (*eth_fd->ef_put_pkt)(eth_fd->ef_srfd, pack, size);
1192 return;
1195 eth_fd->ef_flags &= ~EFF_READ_IP;
1196 result= (*eth_fd->ef_put_userdata)(eth_fd->ef_srfd, (size_t)0, pack,
1197 FALSE);
1198 if (result >=0)
1199 reply_thr_put(eth_fd, size, FALSE);
1200 else
1201 reply_thr_put(eth_fd, result, FALSE);
1204 PRIVATE void eth_buffree (priority)
1205 int priority;
1207 int i;
1208 eth_fd_t *eth_fd;
1209 acc_t *pack;
1211 if (priority == ETH_PRI_FDBUFS_EXTRA)
1213 for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
1215 while (eth_fd->ef_rdbuf_head &&
1216 eth_fd->ef_rdbuf_head->acc_ext_link)
1218 pack= eth_fd->ef_rdbuf_head;
1219 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
1220 bf_afree(pack);
1224 if (priority == ETH_PRI_FDBUFS)
1226 for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
1228 while (eth_fd->ef_rdbuf_head)
1230 pack= eth_fd->ef_rdbuf_head;
1231 eth_fd->ef_rdbuf_head= pack->acc_ext_link;
1232 bf_afree(pack);
1238 #ifdef BUF_CONSISTENCY_CHECK
1239 PRIVATE void eth_bufcheck()
1241 int i;
1242 eth_fd_t *eth_fd;
1243 acc_t *pack;
1245 for (i= 0; i<eth_conf_nr; i++)
1247 bf_check_acc(eth_port_table[i].etp_rd_pack);
1248 bf_check_acc(eth_port_table[i].etp_wr_pack);
1250 for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
1252 for (pack= eth_fd->ef_rdbuf_head; pack;
1253 pack= pack->acc_ext_link)
1255 bf_check_acc(pack);
1259 #endif
1261 PRIVATE void do_rec_conf(eth_port)
1262 eth_port_t *eth_port;
1264 int i;
1265 u32_t flags;
1266 eth_port_t *vp;
1268 assert(eth_port);
1270 if (eth_port->etp_vlan)
1272 /* Configure underlying device */
1273 eth_port= eth_port->etp_vlan_port;
1275 flags= compute_rec_conf(eth_port);
1276 for (i= 0; i<ETH_VLAN_HASH_NR; i++)
1278 for (vp= eth_port->etp_vlan_tab[i]; vp; vp= vp->etp_vlan_next)
1279 flags |= compute_rec_conf(vp);
1281 eth_set_rec_conf(eth_port, flags);
1284 PRIVATE u32_t compute_rec_conf(eth_port)
1285 eth_port_t *eth_port;
1287 eth_fd_t *eth_fd;
1288 u32_t flags;
1289 int i;
1291 flags= NWEO_NOFLAGS;
1292 for (i=0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
1294 if ((eth_fd->ef_flags & (EFF_INUSE|EFF_OPTSET)) !=
1295 (EFF_INUSE|EFF_OPTSET))
1297 continue;
1299 if (eth_fd->ef_port != eth_port)
1300 continue;
1301 flags |= eth_fd->ef_ethopt.nweo_flags;
1303 return flags;
1306 PRIVATE void reply_thr_get (eth_fd, result, for_ioctl)
1307 eth_fd_t *eth_fd;
1308 size_t result;
1309 int for_ioctl;
1311 acc_t *data;
1313 data= (*eth_fd->ef_get_userdata)(eth_fd->ef_srfd, result, 0, for_ioctl);
1314 assert (!data);
1317 PRIVATE void reply_thr_put (eth_fd, result, for_ioctl)
1318 eth_fd_t *eth_fd;
1319 size_t result;
1320 int for_ioctl;
1322 int error;
1324 error= (*eth_fd->ef_put_userdata)(eth_fd->ef_srfd, result, (acc_t *)0,
1325 for_ioctl);
1326 assert(error == NW_OK);
1329 PRIVATE acc_t *insert_vlan_hdr(eth_port, pack)
1330 eth_port_t *eth_port;
1331 acc_t *pack;
1333 acc_t *head_acc, *vh_acc;
1334 u16_t type, vlan;
1335 vlan_hdr_t *vp;
1337 head_acc= bf_cut(pack, 0, 2*sizeof(ether_addr_t));
1338 pack= bf_delhead(pack, 2*sizeof(ether_addr_t));
1339 pack= bf_packIffLess(pack, sizeof(type));
1340 type= *(u16_t *)ptr2acc_data(pack);
1341 if (type == HTONS(ETH_VLAN_PROTO))
1343 /* Packeted is already tagged. Should update vlan number.
1344 * For now, just discard packet.
1346 printf("insert_vlan_hdr: discarding vlan packet\n");
1347 bf_afree(head_acc); head_acc= NULL;
1348 bf_afree(pack); pack= NULL;
1349 return NULL;
1351 vlan= eth_port->etp_vlan; /* priority and CFI are zero */
1353 vh_acc= bf_memreq(sizeof(vlan_hdr_t));
1354 vp= (vlan_hdr_t *)ptr2acc_data(vh_acc);
1355 vp->vh_type= HTONS(ETH_VLAN_PROTO);
1356 vp->vh_vlan= htons(vlan);
1358 head_acc= bf_append(head_acc, vh_acc); vh_acc= NULL;
1359 head_acc= bf_append(head_acc, pack); pack= NULL;
1360 pack= head_acc; head_acc= NULL;
1361 return pack;
1365 * $PchId: eth.c,v 1.23 2005/06/28 14:15:58 philip Exp $