4 Ethernet specific part of the IP implementation
6 Created: Apr 22, 1993 by Philip Homburg
8 Copyright 1995 Philip Homburg
26 typedef struct xmit_hdr
32 PRIVATE ether_addr_t broadcast_ethaddr
=
34 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
36 PRIVATE ether_addr_t ipmulticast_ethaddr
=
38 { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }
41 FORWARD
void do_eth_read
ARGS(( ip_port_t
*port
));
42 FORWARD acc_t
*get_eth_data
ARGS(( int fd
, size_t offset
,
43 size_t count
, int for_ioctl
));
44 FORWARD
int put_eth_data
ARGS(( int fd
, size_t offset
,
45 acc_t
*data
, int for_ioctl
));
46 FORWARD
void ipeth_main
ARGS(( ip_port_t
*port
));
47 FORWARD
void ipeth_set_ipaddr
ARGS(( ip_port_t
*port
));
48 FORWARD
void ipeth_restart_send
ARGS(( ip_port_t
*ip_port
));
49 FORWARD
int ipeth_send
ARGS(( struct ip_port
*ip_port
, ipaddr_t dest
,
50 acc_t
*pack
, int type
));
51 FORWARD
void ipeth_arp_reply
ARGS(( int ip_port_nr
, ipaddr_t ipaddr
,
52 ether_addr_t
*dst_ether_ptr
));
53 FORWARD
int ipeth_update_ttl
ARGS(( time_t enq_time
, time_t now
,
55 FORWARD
void ip_eth_arrived
ARGS(( int port
, acc_t
*pack
,
59 PUBLIC
int ipeth_init(ip_port
)
62 assert(BUF_S
>= sizeof(xmit_hdr_t
));
63 assert(BUF_S
>= sizeof(eth_hdr_t
));
65 ip_port
->ip_dl
.dl_eth
.de_fd
= eth_open(ip_port
->
66 ip_dl
.dl_eth
.de_port
, ip_port
->ip_port
,
67 get_eth_data
, put_eth_data
, ip_eth_arrived
,
68 0 /* no select_res */);
69 if (ip_port
->ip_dl
.dl_eth
.de_fd
< 0)
71 DBLOCK(1, printf("ip.c: unable to open eth port\n"));
74 ip_port
->ip_dl
.dl_eth
.de_state
= IES_EMPTY
;
75 ip_port
->ip_dl
.dl_eth
.de_flags
= IEF_EMPTY
;
76 ip_port
->ip_dl
.dl_eth
.de_q_head
= NULL
;
77 ip_port
->ip_dl
.dl_eth
.de_q_tail
= NULL
;
78 ip_port
->ip_dl
.dl_eth
.de_arp_head
= NULL
;
79 ip_port
->ip_dl
.dl_eth
.de_arp_tail
= NULL
;
80 ip_port
->ip_dev_main
= ipeth_main
;
81 ip_port
->ip_dev_set_ipaddr
= ipeth_set_ipaddr
;
82 ip_port
->ip_dev_send
= ipeth_send
;
83 ip_port
->ip_mtu
= ETH_MAX_PACK_SIZE
-ETH_HDR_SIZE
;
84 ip_port
->ip_mtu_max
= ip_port
->ip_mtu
;
88 PRIVATE
void ipeth_main(ip_port
)
93 switch (ip_port
->ip_dl
.dl_eth
.de_state
)
96 ip_port
->ip_dl
.dl_eth
.de_state
= IES_SETPROTO
;
98 result
= eth_ioctl(ip_port
->ip_dl
.dl_eth
.de_fd
, NWIOSETHOPT
);
99 if (result
== NW_SUSPEND
)
100 ip_port
->ip_dl
.dl_eth
.de_flags
|= IEF_SUSPEND
;
103 DBLOCK(1, printf("eth_ioctl(..,0x%lx)=%d\n",
104 (unsigned long)NWIOSETHOPT
, result
));
107 if (ip_port
->ip_dl
.dl_eth
.de_state
!= IES_SETPROTO
)
111 result
= arp_set_cb(ip_port
->ip_dl
.dl_eth
.de_port
,
116 printf("ipeth_main: arp_set_cb failed: %d\n",
121 /* Wait until the interface is configured up. */
122 ip_port
->ip_dl
.dl_eth
.de_state
= IES_GETIPADDR
;
123 if (!(ip_port
->ip_flags
& IPF_IPADDRSET
))
125 ip_port
->ip_dl
.dl_eth
.de_flags
|= IEF_SUSPEND
;
131 ip_port
->ip_dl
.dl_eth
.de_state
= IES_MAIN
;
132 do_eth_read(ip_port
);
135 ip_panic(( "unknown state: %d",
136 ip_port
->ip_dl
.dl_eth
.de_state
));
140 PRIVATE acc_t
*get_eth_data (fd
, offset
, count
, for_ioctl
)
150 ip_port
= &ip_port_table
[fd
];
152 switch (ip_port
->ip_dl
.dl_eth
.de_state
)
160 ip_port
->ip_dl
.dl_eth
.de_state
= IES_ERROR
;
163 if (ip_port
->ip_dl
.dl_eth
.de_flags
& IEF_SUSPEND
)
167 assert ((!offset
) && (count
== sizeof(struct nwio_ethopt
)));
169 struct nwio_ethopt
*ethopt
;
172 acc
= bf_memreq(sizeof(*ethopt
));
173 ethopt
= (struct nwio_ethopt
*)ptr2acc_data(acc
);
174 ethopt
->nweo_flags
= NWEO_COPY
|NWEO_EN_BROAD
|
175 NWEO_EN_MULTI
|NWEO_TYPESPEC
;
176 ethopt
->nweo_type
= HTONS(ETH_IP_PROTO
);
185 ip_warning(( "error on write: %d\n", result
));
186 bf_afree (ip_port
->ip_dl
.dl_eth
.de_frame
);
187 ip_port
->ip_dl
.dl_eth
.de_frame
= 0;
189 if (ip_port
->ip_dl
.dl_eth
.de_flags
& IEF_WRITE_SP
)
191 ip_port
->ip_dl
.dl_eth
.de_flags
&=
193 ipeth_restart_send(ip_port
);
197 data
= bf_cut (ip_port
->ip_dl
.dl_eth
.de_frame
, offset
, count
);
202 "get_eth_data(%d, 0x%d, 0x%d) called but ip_state=0x%x\n",
203 fd
, offset
, count
, ip_port
->ip_dl
.dl_eth
.de_state
);
209 PRIVATE
int put_eth_data (port
, offset
, data
, for_ioctl
)
218 ip_port
= &ip_port_table
[port
];
222 if (ip_port
->ip_dl
.dl_eth
.de_flags
& IEF_READ_IP
)
230 "ip.c: put_eth_data(..,%d,..)\n", result
));
233 if (ip_port
->ip_dl
.dl_eth
.de_flags
& IEF_READ_SP
)
235 ip_port
->ip_dl
.dl_eth
.de_flags
&=
236 ~(IEF_READ_IP
|IEF_READ_SP
);
237 do_eth_read(ip_port
);
240 ip_port
->ip_dl
.dl_eth
.de_flags
&= ~IEF_READ_IP
;
244 /* Warning: the above assertion is illegal; puts and
245 gets of data can be brokenup in any piece the server
246 likes. However we assume that the server is eth.c
247 and it transfers only whole packets. */
248 ip_eth_arrived(port
, data
, bf_bufsize(data
));
251 printf("ip_port->ip_dl.dl_eth.de_state= 0x%x",
252 ip_port
->ip_dl
.dl_eth
.de_state
);
253 ip_panic (( "strange status" ));
256 PRIVATE
void ipeth_set_ipaddr(ip_port
)
259 arp_set_ipaddr (ip_port
->ip_dl
.dl_eth
.de_port
, ip_port
->ip_ipaddr
);
260 if (ip_port
->ip_dl
.dl_eth
.de_state
== IES_GETIPADDR
)
264 PRIVATE
int ipeth_send(ip_port
, dest
, pack
, type
)
265 struct ip_port
*ip_port
;
271 acc_t
*eth_pack
, *tail
;
274 xmit_hdr_t
*xmit_hdr
;
275 ipaddr_t hostpart
, tmpaddr
;
279 /* Start optimistic: the arp will succeed without blocking and the
280 * ethernet packet can be sent without blocking also. Start with
281 * the allocation of the ethernet header.
283 eth_pack
= bf_memreq(sizeof(*eth_hdr
));
284 assert(eth_pack
->acc_next
== NULL
);
285 eth_pack
->acc_next
= pack
;
286 pack_size
= bf_bufsize(eth_pack
);
287 if (pack_size
<ETH_MIN_PACK_SIZE
)
289 tail
= bf_memreq(ETH_MIN_PACK_SIZE
-pack_size
);
292 for (i
= (ETH_MIN_PACK_SIZE
-pack_size
)/sizeof(*p
),
293 p
= (u32_t
*)ptr2acc_data(tail
);
299 eth_pack
= bf_append(eth_pack
, tail
);
301 eth_hdr
= (eth_hdr_t
*)ptr2acc_data(eth_pack
);
303 /* Lookup the ethernet address */
304 if (type
!= IP_LT_NORMAL
)
306 if (type
== IP_LT_BROADCAST
)
307 eth_hdr
->eh_dst
= broadcast_ethaddr
;
310 tmpaddr
= ntohl(dest
);
311 eth_hdr
->eh_dst
= ipmulticast_ethaddr
;
312 eth_hdr
->eh_dst
.ea_addr
[5]= tmpaddr
& 0xff;
313 eth_hdr
->eh_dst
.ea_addr
[4]= (tmpaddr
>> 8) & 0xff;
314 eth_hdr
->eh_dst
.ea_addr
[3]= (tmpaddr
>> 16) & 0x7f;
319 if ((dest
^ ip_port
->ip_ipaddr
) & ip_port
->ip_subnetmask
)
321 ip_panic(( "invalid destination" ));
324 hostpart
= (dest
& ~ip_port
->ip_subnetmask
);
325 assert(dest
!= ip_port
->ip_ipaddr
);
327 r
= arp_ip_eth(ip_port
->ip_dl
.dl_eth
.de_port
,
328 dest
, ð_hdr
->eh_dst
);
331 /* Unfortunately, the arp takes some time, use
332 * the ethernet header to store the next hop
333 * ip address and the current time.
335 xmit_hdr
= (xmit_hdr_t
*)eth_hdr
;
336 xmit_hdr
->xh_time
= get_time();
337 xmit_hdr
->xh_ipaddr
= dest
;
338 eth_pack
->acc_ext_link
= NULL
;
339 if (ip_port
->ip_dl
.dl_eth
.de_arp_head
== NULL
)
340 ip_port
->ip_dl
.dl_eth
.de_arp_head
= eth_pack
;
343 ip_port
->ip_dl
.dl_eth
.de_arp_tail
->
344 acc_ext_link
= eth_pack
;
346 ip_port
->ip_dl
.dl_eth
.de_arp_tail
= eth_pack
;
357 /* If we have no write in progress, we can try to send the ethernet
358 * packet using eth_send. If the IP packet is larger than mtu,
359 * enqueue the packet and let ipeth_restart_send deal with it.
361 pack_size
= bf_bufsize(eth_pack
);
362 if (ip_port
->ip_dl
.dl_eth
.de_frame
== NULL
&& pack_size
<=
363 ip_port
->ip_mtu
+ sizeof(*eth_hdr
))
365 r
= eth_send(ip_port
->ip_dl
.dl_eth
.de_fd
,
366 eth_pack
, pack_size
);
370 /* A non-blocking send is not possible, start a regular
373 assert(r
== NW_WOULDBLOCK
);
374 ip_port
->ip_dl
.dl_eth
.de_frame
= eth_pack
;
375 r
= eth_write(ip_port
->ip_dl
.dl_eth
.de_fd
, pack_size
);
378 assert(!(ip_port
->ip_dl
.dl_eth
.de_flags
&
380 ip_port
->ip_dl
.dl_eth
.de_flags
|= IEF_WRITE_SP
;
382 assert(r
== NW_OK
|| r
== NW_SUSPEND
);
386 /* Enqueue the packet, and store the current time, in the
387 * space for the ethernet source address.
390 assert(sizeof(t
) <= sizeof(eth_hdr
->eh_src
));
391 memcpy(ð_hdr
->eh_src
, &t
, sizeof(t
));
393 eth_pack
->acc_ext_link
= NULL
;
394 if (ip_port
->ip_dl
.dl_eth
.de_q_head
== NULL
)
395 ip_port
->ip_dl
.dl_eth
.de_q_head
= eth_pack
;
398 ip_port
->ip_dl
.dl_eth
.de_q_tail
->acc_ext_link
= eth_pack
;
400 ip_port
->ip_dl
.dl_eth
.de_q_tail
= eth_pack
;
401 if (ip_port
->ip_dl
.dl_eth
.de_frame
== NULL
)
402 ipeth_restart_send(ip_port
);
406 PRIVATE
void ipeth_restart_send(ip_port
)
409 time_t now
, enq_time
;
411 acc_t
*eth_pack
, *ip_pack
, *next_eth_pack
, *next_part
, *tail
;
413 eth_hdr_t
*eth_hdr
, *next_eth_hdr
;
418 while (ip_port
->ip_dl
.dl_eth
.de_q_head
!= NULL
)
420 eth_pack
= ip_port
->ip_dl
.dl_eth
.de_q_head
;
421 ip_port
->ip_dl
.dl_eth
.de_q_head
= eth_pack
->acc_ext_link
;
423 eth_hdr
= (eth_hdr_t
*)ptr2acc_data(eth_pack
);
425 pack_size
= bf_bufsize(eth_pack
);
427 if (pack_size
> ip_port
->ip_mtu
+sizeof(*eth_hdr
))
429 /* Split the IP packet */
430 assert(eth_pack
->acc_linkC
== 1);
431 ip_pack
= eth_pack
->acc_next
; eth_pack
->acc_next
= NULL
;
432 next_part
= ip_pack
; ip_pack
= NULL
;
433 ip_pack
= ip_split_pack(ip_port
, &next_part
,
441 eth_pack
->acc_next
= ip_pack
; ip_pack
= NULL
;
443 /* Allocate new ethernet header */
444 next_eth_pack
= bf_memreq(sizeof(*next_eth_hdr
));
445 next_eth_hdr
= (eth_hdr_t
*)ptr2acc_data(next_eth_pack
);
446 *next_eth_hdr
= *eth_hdr
;
447 next_eth_pack
->acc_next
= next_part
;
449 next_eth_pack
->acc_ext_link
= NULL
;
450 if (ip_port
->ip_dl
.dl_eth
.de_q_head
== NULL
)
451 ip_port
->ip_dl
.dl_eth
.de_q_head
= next_eth_pack
;
454 ip_port
->ip_dl
.dl_eth
.de_q_tail
->acc_ext_link
=
457 ip_port
->ip_dl
.dl_eth
.de_q_tail
= next_eth_pack
;
459 pack_size
= bf_bufsize(eth_pack
);
462 memcpy(&enq_time
, ð_hdr
->eh_src
, sizeof(enq_time
));
463 if (enq_time
+ HZ
< now
)
465 r
= ipeth_update_ttl(enq_time
, now
, eth_pack
);
468 ip_pack
= bf_delhead(eth_pack
, sizeof(*eth_hdr
));
470 icmp_snd_time_exceeded(ip_port
->ip_port
,
471 ip_pack
, ICMP_TTL_EXC
);
477 if (pack_size
<ETH_MIN_PACK_SIZE
)
479 tail
= bf_memreq(ETH_MIN_PACK_SIZE
-pack_size
);
482 for (i
= (ETH_MIN_PACK_SIZE
-pack_size
)/sizeof(*p
),
483 p
= (u32_t
*)ptr2acc_data(tail
);
489 eth_pack
= bf_append(eth_pack
, tail
);
490 pack_size
= ETH_MIN_PACK_SIZE
;
493 assert(ip_port
->ip_dl
.dl_eth
.de_frame
== NULL
);
495 r
= eth_send(ip_port
->ip_dl
.dl_eth
.de_fd
, eth_pack
, pack_size
);
499 /* A non-blocking send is not possible, start a regular
502 assert(r
== NW_WOULDBLOCK
);
503 ip_port
->ip_dl
.dl_eth
.de_frame
= eth_pack
;
504 r
= eth_write(ip_port
->ip_dl
.dl_eth
.de_fd
, pack_size
);
507 assert(!(ip_port
->ip_dl
.dl_eth
.de_flags
&
509 ip_port
->ip_dl
.dl_eth
.de_flags
|= IEF_WRITE_SP
;
517 PRIVATE
void ipeth_arp_reply(ip_port_nr
, ipaddr
, eth_addr
)
520 ether_addr_t
*eth_addr
;
522 acc_t
*prev
, *eth_pack
;
524 xmit_hdr_t
*xmit_hdr
;
528 ether_addr_t tmp_eth_addr
;
530 assert (ip_port_nr
>= 0 && ip_port_nr
< ip_conf_nr
);
531 ip_port
= &ip_port_table
[ip_port_nr
];
535 for (prev
= 0, eth_pack
= ip_port
->ip_dl
.dl_eth
.de_arp_head
;
537 prev
= eth_pack
, eth_pack
= eth_pack
->acc_ext_link
)
539 xmit_hdr
= (xmit_hdr_t
*)ptr2acc_data(eth_pack
);
540 if (xmit_hdr
->xh_ipaddr
== ipaddr
)
544 if (eth_pack
== NULL
)
546 /* No packet found. */
550 /* Delete packet from the queue. */
553 ip_port
->ip_dl
.dl_eth
.de_arp_head
=
554 eth_pack
->acc_ext_link
;
558 prev
->acc_ext_link
= eth_pack
->acc_ext_link
;
559 if (prev
->acc_ext_link
== NULL
)
560 ip_port
->ip_dl
.dl_eth
.de_arp_tail
= prev
;
563 if (eth_addr
== NULL
)
565 /* Destination is unreachable, delete packet. */
570 /* Fill in the ethernet address and put the packet on the
573 t
= xmit_hdr
->xh_time
;
574 eth_hdr
= (eth_hdr_t
*)ptr2acc_data(eth_pack
);
575 eth_hdr
->eh_dst
= *eth_addr
;
576 memcpy(ð_hdr
->eh_src
, &t
, sizeof(t
));
578 eth_pack
->acc_ext_link
= NULL
;
579 if (ip_port
->ip_dl
.dl_eth
.de_q_head
== NULL
)
580 ip_port
->ip_dl
.dl_eth
.de_q_head
= eth_pack
;
583 ip_port
->ip_dl
.dl_eth
.de_q_tail
->acc_ext_link
=
586 ip_port
->ip_dl
.dl_eth
.de_q_tail
= eth_pack
;
589 /* Try to get some more ARPs in progress. */
590 while (ip_port
->ip_dl
.dl_eth
.de_arp_head
)
592 eth_pack
= ip_port
->ip_dl
.dl_eth
.de_arp_head
;
593 xmit_hdr
= (xmit_hdr_t
*)ptr2acc_data(eth_pack
);
594 r
= arp_ip_eth(ip_port
->ip_dl
.dl_eth
.de_port
,
595 xmit_hdr
->xh_ipaddr
, &tmp_eth_addr
);
597 break; /* Normal case */
599 /* Dequeue the packet */
600 ip_port
->ip_dl
.dl_eth
.de_arp_head
= eth_pack
->acc_ext_link
;
609 /* Fill in the ethernet address and put the packet on the
612 t
= xmit_hdr
->xh_time
;
613 eth_hdr
= (eth_hdr_t
*)ptr2acc_data(eth_pack
);
614 eth_hdr
->eh_dst
= tmp_eth_addr
;
615 memcpy(ð_hdr
->eh_src
, &t
, sizeof(t
));
617 eth_pack
->acc_ext_link
= NULL
;
618 if (ip_port
->ip_dl
.dl_eth
.de_q_head
== NULL
)
619 ip_port
->ip_dl
.dl_eth
.de_q_head
= eth_pack
;
622 ip_port
->ip_dl
.dl_eth
.de_q_tail
->acc_ext_link
=
625 ip_port
->ip_dl
.dl_eth
.de_q_tail
= eth_pack
;
628 /* Restart sending ethernet packets. */
629 if (ip_port
->ip_dl
.dl_eth
.de_frame
== NULL
)
630 ipeth_restart_send(ip_port
);
633 PRIVATE
int ipeth_update_ttl(enq_time
, now
, eth_pack
)
644 ttl_diff
= (now
-enq_time
)/HZ
;
645 enq_time
+= ttl_diff
*HZ
;
646 assert(enq_time
<= now
&& enq_time
+ HZ
> now
);
648 ip_pack
= eth_pack
->acc_next
;
649 assert(ip_pack
->acc_length
>= sizeof(*ip_hdr
));
650 assert(ip_pack
->acc_linkC
== 1 &&
651 ip_pack
->acc_buffer
->buf_linkC
== 1);
653 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(ip_pack
);
654 if (ip_hdr
->ih_ttl
<= ttl_diff
)
656 sum
= (u16_t
)~ip_hdr
->ih_hdr_chk
;
657 word
= *(u16_t
*)&ip_hdr
->ih_ttl
;
659 sum
+= 0xffff - word
;
662 ip_hdr
->ih_ttl
-= ttl_diff
;
663 word
= *(u16_t
*)&ip_hdr
->ih_ttl
;
667 assert(!(sum
& 0xffff0000));
668 ip_hdr
->ih_hdr_chk
= ~sum
;
669 assert(ip_hdr
->ih_ttl
> 0);
673 PRIVATE
void do_eth_read(ip_port
)
678 assert(!(ip_port
->ip_dl
.dl_eth
.de_flags
& IEF_READ_IP
));
682 ip_port
->ip_dl
.dl_eth
.de_flags
|= IEF_READ_IP
;
684 result
= eth_read (ip_port
->ip_dl
.dl_eth
.de_fd
,
686 if (result
== NW_SUSPEND
)
688 assert(!(ip_port
->ip_dl
.dl_eth
.de_flags
&
690 ip_port
->ip_dl
.dl_eth
.de_flags
|= IEF_READ_SP
;
693 ip_port
->ip_dl
.dl_eth
.de_flags
&= ~IEF_READ_IP
;
701 PRIVATE
void ip_eth_arrived(port
, pack
, pack_size
)
709 ip_port
= &ip_port_table
[port
];
710 broadcast
= (*(u8_t
*)ptr2acc_data(pack
) & 1);
712 pack
= bf_delhead(pack
, ETH_HDR_SIZE
);
715 ip_arrived_broadcast(ip_port
, pack
);
717 ip_arrived(ip_port
, pack
);
721 * $PchId: ip_eth.c,v 1.25 2005/06/28 14:18:10 philip Exp $