1 | /*
|
---|
2 | generic/ip_eth.c
|
---|
3 |
|
---|
4 | Ethernet specific part of the IP implementation
|
---|
5 |
|
---|
6 | Created: Apr 22, 1993 by Philip Homburg
|
---|
7 |
|
---|
8 | Copyright 1995 Philip Homburg
|
---|
9 | */
|
---|
10 |
|
---|
11 | #include "inet.h"
|
---|
12 | #include "type.h"
|
---|
13 | #include "arp.h"
|
---|
14 | #include "assert.h"
|
---|
15 | #include "buf.h"
|
---|
16 | #include "clock.h"
|
---|
17 | #include "eth.h"
|
---|
18 | #include "event.h"
|
---|
19 | #include "icmp_lib.h"
|
---|
20 | #include "io.h"
|
---|
21 | #include "ip.h"
|
---|
22 | #include "ip_int.h"
|
---|
23 |
|
---|
24 | THIS_FILE
|
---|
25 |
|
---|
26 | typedef struct xmit_hdr
|
---|
27 | {
|
---|
28 | time_t xh_time;
|
---|
29 | ipaddr_t xh_ipaddr;
|
---|
30 | } xmit_hdr_t;
|
---|
31 |
|
---|
32 | PRIVATE ether_addr_t broadcast_ethaddr=
|
---|
33 | {
|
---|
34 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
|
---|
35 | };
|
---|
36 | PRIVATE ether_addr_t ipmulticast_ethaddr=
|
---|
37 | {
|
---|
38 | { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 }
|
---|
39 | };
|
---|
40 |
|
---|
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,
|
---|
54 | acc_t *eth_pack ));
|
---|
55 | FORWARD void ip_eth_arrived ARGS(( int port, acc_t *pack,
|
---|
56 | size_t pack_size ));
|
---|
57 |
|
---|
58 |
|
---|
59 | PUBLIC int ipeth_init(ip_port)
|
---|
60 | ip_port_t *ip_port;
|
---|
61 | {
|
---|
62 | assert(BUF_S >= sizeof(xmit_hdr_t));
|
---|
63 | assert(BUF_S >= sizeof(eth_hdr_t));
|
---|
64 |
|
---|
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)
|
---|
70 | {
|
---|
71 | DBLOCK(1, printf("ip.c: unable to open eth port\n"));
|
---|
72 | return -1;
|
---|
73 | }
|
---|
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;
|
---|
85 | return 0;
|
---|
86 | }
|
---|
87 |
|
---|
88 | PRIVATE void ipeth_main(ip_port)
|
---|
89 | ip_port_t *ip_port;
|
---|
90 | {
|
---|
91 | int result;
|
---|
92 |
|
---|
93 | switch (ip_port->ip_dl.dl_eth.de_state)
|
---|
94 | {
|
---|
95 | case IES_EMPTY:
|
---|
96 | ip_port->ip_dl.dl_eth.de_state= IES_SETPROTO;
|
---|
97 |
|
---|
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;
|
---|
101 | if (result<0)
|
---|
102 | {
|
---|
103 | DBLOCK(1, printf("eth_ioctl(..,0x%lx)=%d\n",
|
---|
104 | (unsigned long)NWIOSETHOPT, result));
|
---|
105 | return;
|
---|
106 | }
|
---|
107 | if (ip_port->ip_dl.dl_eth.de_state != IES_SETPROTO)
|
---|
108 | return;
|
---|
109 | /* drops through */
|
---|
110 | case IES_SETPROTO:
|
---|
111 | result= arp_set_cb(ip_port->ip_dl.dl_eth.de_port,
|
---|
112 | ip_port->ip_port,
|
---|
113 | ipeth_arp_reply);
|
---|
114 | if (result != NW_OK)
|
---|
115 | {
|
---|
116 | printf("ipeth_main: arp_set_cb failed: %d\n",
|
---|
117 | result);
|
---|
118 | return;
|
---|
119 | }
|
---|
120 |
|
---|
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))
|
---|
124 | {
|
---|
125 | ip_port->ip_dl.dl_eth.de_flags |= IEF_SUSPEND;
|
---|
126 | return;
|
---|
127 | }
|
---|
128 |
|
---|
129 | /* fall through */
|
---|
130 | case IES_GETIPADDR:
|
---|
131 | ip_port->ip_dl.dl_eth.de_state= IES_MAIN;
|
---|
132 | do_eth_read(ip_port);
|
---|
133 | return;
|
---|
134 | default:
|
---|
135 | ip_panic(( "unknown state: %d",
|
---|
136 | ip_port->ip_dl.dl_eth.de_state));
|
---|
137 | }
|
---|
138 | }
|
---|
139 |
|
---|
140 | PRIVATE acc_t *get_eth_data (fd, offset, count, for_ioctl)
|
---|
141 | int fd;
|
---|
142 | size_t offset;
|
---|
143 | size_t count;
|
---|
144 | int for_ioctl;
|
---|
145 | {
|
---|
146 | ip_port_t *ip_port;
|
---|
147 | acc_t *data;
|
---|
148 | int result;
|
---|
149 |
|
---|
150 | ip_port= &ip_port_table[fd];
|
---|
151 |
|
---|
152 | switch (ip_port->ip_dl.dl_eth.de_state)
|
---|
153 | {
|
---|
154 | case IES_SETPROTO:
|
---|
155 | if (!count)
|
---|
156 | {
|
---|
157 | result= (int)offset;
|
---|
158 | if (result<0)
|
---|
159 | {
|
---|
160 | ip_port->ip_dl.dl_eth.de_state= IES_ERROR;
|
---|
161 | break;
|
---|
162 | }
|
---|
163 | if (ip_port->ip_dl.dl_eth.de_flags & IEF_SUSPEND)
|
---|
164 | ipeth_main(ip_port);
|
---|
165 | return NW_OK;
|
---|
166 | }
|
---|
167 | assert ((!offset) && (count == sizeof(struct nwio_ethopt)));
|
---|
168 | {
|
---|
169 | struct nwio_ethopt *ethopt;
|
---|
170 | acc_t *acc;
|
---|
171 |
|
---|
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);
|
---|
177 | return acc;
|
---|
178 | }
|
---|
179 |
|
---|
180 | case IES_MAIN:
|
---|
181 | if (!count)
|
---|
182 | {
|
---|
183 | result= (int)offset;
|
---|
184 | if (result<0)
|
---|
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;
|
---|
188 |
|
---|
189 | if (ip_port->ip_dl.dl_eth.de_flags & IEF_WRITE_SP)
|
---|
190 | {
|
---|
191 | ip_port->ip_dl.dl_eth.de_flags &=
|
---|
192 | ~IEF_WRITE_SP;
|
---|
193 | ipeth_restart_send(ip_port);
|
---|
194 | }
|
---|
195 | return NW_OK;
|
---|
196 | }
|
---|
197 | data= bf_cut (ip_port->ip_dl.dl_eth.de_frame, offset, count);
|
---|
198 | assert (data);
|
---|
199 | return data;
|
---|
200 | default:
|
---|
201 | printf(
|
---|
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);
|
---|
204 | break;
|
---|
205 | }
|
---|
206 | return 0;
|
---|
207 | }
|
---|
208 |
|
---|
209 | PRIVATE int put_eth_data (port, offset, data, for_ioctl)
|
---|
210 | int port;
|
---|
211 | size_t offset;
|
---|
212 | acc_t *data;
|
---|
213 | int for_ioctl;
|
---|
214 | {
|
---|
215 | ip_port_t *ip_port;
|
---|
216 | int result;
|
---|
217 |
|
---|
218 | ip_port= &ip_port_table[port];
|
---|
219 |
|
---|
220 | assert(0);
|
---|
221 |
|
---|
222 | if (ip_port->ip_dl.dl_eth.de_flags & IEF_READ_IP)
|
---|
223 | {
|
---|
224 | if (!data)
|
---|
225 | {
|
---|
226 | result= (int)offset;
|
---|
227 | if (result<0)
|
---|
228 | {
|
---|
229 | DBLOCK(1, printf(
|
---|
230 | "ip.c: put_eth_data(..,%d,..)\n", result));
|
---|
231 | return NW_OK;
|
---|
232 | }
|
---|
233 | if (ip_port->ip_dl.dl_eth.de_flags & IEF_READ_SP)
|
---|
234 | {
|
---|
235 | ip_port->ip_dl.dl_eth.de_flags &=
|
---|
236 | ~(IEF_READ_IP|IEF_READ_SP);
|
---|
237 | do_eth_read(ip_port);
|
---|
238 | }
|
---|
239 | else
|
---|
240 | ip_port->ip_dl.dl_eth.de_flags &= ~IEF_READ_IP;
|
---|
241 | return NW_OK;
|
---|
242 | }
|
---|
243 | assert (!offset);
|
---|
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));
|
---|
249 | return NW_OK;
|
---|
250 | }
|
---|
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" ));
|
---|
254 | }
|
---|
255 |
|
---|
256 | PRIVATE void ipeth_set_ipaddr(ip_port)
|
---|
257 | ip_port_t *ip_port;
|
---|
258 | {
|
---|
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)
|
---|
261 | ipeth_main(ip_port);
|
---|
262 | }
|
---|
263 |
|
---|
264 | PRIVATE int ipeth_send(ip_port, dest, pack, type)
|
---|
265 | struct ip_port *ip_port;
|
---|
266 | ipaddr_t dest;
|
---|
267 | acc_t *pack;
|
---|
268 | int type;
|
---|
269 | {
|
---|
270 | int i, r;
|
---|
271 | acc_t *eth_pack, *tail;
|
---|
272 | size_t pack_size;
|
---|
273 | eth_hdr_t *eth_hdr;
|
---|
274 | xmit_hdr_t *xmit_hdr;
|
---|
275 | ipaddr_t hostpart, tmpaddr;
|
---|
276 | time_t t;
|
---|
277 | u32_t *p;
|
---|
278 |
|
---|
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.
|
---|
282 | */
|
---|
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)
|
---|
288 | {
|
---|
289 | tail= bf_memreq(ETH_MIN_PACK_SIZE-pack_size);
|
---|
290 |
|
---|
291 | /* Clear padding */
|
---|
292 | for (i= (ETH_MIN_PACK_SIZE-pack_size)/sizeof(*p),
|
---|
293 | p= (u32_t *)ptr2acc_data(tail);
|
---|
294 | i >= 0; i--, p++)
|
---|
295 | {
|
---|
296 | *p= 0xdeadbeef;
|
---|
297 | }
|
---|
298 |
|
---|
299 | eth_pack= bf_append(eth_pack, tail);
|
---|
300 | }
|
---|
301 | eth_hdr= (eth_hdr_t *)ptr2acc_data(eth_pack);
|
---|
302 |
|
---|
303 | /* Lookup the ethernet address */
|
---|
304 | if (type != IP_LT_NORMAL)
|
---|
305 | {
|
---|
306 | if (type == IP_LT_BROADCAST)
|
---|
307 | eth_hdr->eh_dst= broadcast_ethaddr;
|
---|
308 | else
|
---|
309 | {
|
---|
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;
|
---|
315 | }
|
---|
316 | }
|
---|
317 | else
|
---|
318 | {
|
---|
319 | if ((dest ^ ip_port->ip_ipaddr) & ip_port->ip_subnetmask)
|
---|
320 | {
|
---|
321 | ip_panic(( "invalid destination" ));
|
---|
322 | }
|
---|
323 |
|
---|
324 | hostpart= (dest & ~ip_port->ip_subnetmask);
|
---|
325 | assert(dest != ip_port->ip_ipaddr);
|
---|
326 |
|
---|
327 | r= arp_ip_eth(ip_port->ip_dl.dl_eth.de_port,
|
---|
328 | dest, ð_hdr->eh_dst);
|
---|
329 | if (r == NW_SUSPEND)
|
---|
330 | {
|
---|
331 | /* Unfortunately, the arp takes some time, use
|
---|
332 | * the ethernet header to store the next hop
|
---|
333 | * ip address and the current time.
|
---|
334 | */
|
---|
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;
|
---|
341 | else
|
---|
342 | {
|
---|
343 | ip_port->ip_dl.dl_eth.de_arp_tail->
|
---|
344 | acc_ext_link= eth_pack;
|
---|
345 | }
|
---|
346 | ip_port->ip_dl.dl_eth.de_arp_tail= eth_pack;
|
---|
347 | return NW_OK;
|
---|
348 | }
|
---|
349 | if (r == EDSTNOTRCH)
|
---|
350 | {
|
---|
351 | bf_afree(eth_pack);
|
---|
352 | return EDSTNOTRCH;
|
---|
353 | }
|
---|
354 | assert(r == NW_OK);
|
---|
355 | }
|
---|
356 |
|
---|
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.
|
---|
360 | */
|
---|
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))
|
---|
364 | {
|
---|
365 | r= eth_send(ip_port->ip_dl.dl_eth.de_fd,
|
---|
366 | eth_pack, pack_size);
|
---|
367 | if (r == NW_OK)
|
---|
368 | return NW_OK;
|
---|
369 |
|
---|
370 | /* A non-blocking send is not possible, start a regular
|
---|
371 | * send.
|
---|
372 | */
|
---|
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);
|
---|
376 | if (r == NW_SUSPEND)
|
---|
377 | {
|
---|
378 | assert(!(ip_port->ip_dl.dl_eth.de_flags &
|
---|
379 | IEF_WRITE_SP));
|
---|
380 | ip_port->ip_dl.dl_eth.de_flags |= IEF_WRITE_SP;
|
---|
381 | }
|
---|
382 | assert(r == NW_OK || r == NW_SUSPEND);
|
---|
383 | return NW_OK;
|
---|
384 | }
|
---|
385 |
|
---|
386 | /* Enqueue the packet, and store the current time, in the
|
---|
387 | * space for the ethernet source address.
|
---|
388 | */
|
---|
389 | t= get_time();
|
---|
390 | assert(sizeof(t) <= sizeof(eth_hdr->eh_src));
|
---|
391 | memcpy(ð_hdr->eh_src, &t, sizeof(t));
|
---|
392 |
|
---|
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;
|
---|
396 | else
|
---|
397 | {
|
---|
398 | ip_port->ip_dl.dl_eth.de_q_tail->acc_ext_link= eth_pack;
|
---|
399 | }
|
---|
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);
|
---|
403 | return NW_OK;
|
---|
404 | }
|
---|
405 |
|
---|
406 | PRIVATE void ipeth_restart_send(ip_port)
|
---|
407 | ip_port_t *ip_port;
|
---|
408 | {
|
---|
409 | time_t now, enq_time;
|
---|
410 | int i, r;
|
---|
411 | acc_t *eth_pack, *ip_pack, *next_eth_pack, *next_part, *tail;
|
---|
412 | size_t pack_size;
|
---|
413 | eth_hdr_t *eth_hdr, *next_eth_hdr;
|
---|
414 | u32_t *p;
|
---|
415 |
|
---|
416 | now= get_time();
|
---|
417 |
|
---|
418 | while (ip_port->ip_dl.dl_eth.de_q_head != NULL)
|
---|
419 | {
|
---|
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;
|
---|
422 |
|
---|
423 | eth_hdr= (eth_hdr_t *)ptr2acc_data(eth_pack);
|
---|
424 |
|
---|
425 | pack_size= bf_bufsize(eth_pack);
|
---|
426 |
|
---|
427 | if (pack_size > ip_port->ip_mtu+sizeof(*eth_hdr))
|
---|
428 | {
|
---|
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,
|
---|
434 | ip_port->ip_mtu);
|
---|
435 | if (ip_pack == NULL)
|
---|
436 | {
|
---|
437 | bf_afree(eth_pack);
|
---|
438 | continue;
|
---|
439 | }
|
---|
440 |
|
---|
441 | eth_pack->acc_next= ip_pack; ip_pack= NULL;
|
---|
442 |
|
---|
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;
|
---|
448 |
|
---|
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;
|
---|
452 | else
|
---|
453 | {
|
---|
454 | ip_port->ip_dl.dl_eth.de_q_tail->acc_ext_link=
|
---|
455 | next_eth_pack;
|
---|
456 | }
|
---|
457 | ip_port->ip_dl.dl_eth.de_q_tail= next_eth_pack;
|
---|
458 |
|
---|
459 | pack_size= bf_bufsize(eth_pack);
|
---|
460 | }
|
---|
461 |
|
---|
462 | memcpy(&enq_time, ð_hdr->eh_src, sizeof(enq_time));
|
---|
463 | if (enq_time + HZ < now)
|
---|
464 | {
|
---|
465 | r= ipeth_update_ttl(enq_time, now, eth_pack);
|
---|
466 | if (r == ETIMEDOUT)
|
---|
467 | {
|
---|
468 | ip_pack= bf_delhead(eth_pack, sizeof(*eth_hdr));
|
---|
469 | eth_pack= NULL;
|
---|
470 | icmp_snd_time_exceeded(ip_port->ip_port,
|
---|
471 | ip_pack, ICMP_TTL_EXC);
|
---|
472 | continue;
|
---|
473 | }
|
---|
474 | assert(r == NW_OK);
|
---|
475 | }
|
---|
476 |
|
---|
477 | if (pack_size<ETH_MIN_PACK_SIZE)
|
---|
478 | {
|
---|
479 | tail= bf_memreq(ETH_MIN_PACK_SIZE-pack_size);
|
---|
480 |
|
---|
481 | /* Clear padding */
|
---|
482 | for (i= (ETH_MIN_PACK_SIZE-pack_size)/sizeof(*p),
|
---|
483 | p= (u32_t *)ptr2acc_data(tail);
|
---|
484 | i >= 0; i--, p++)
|
---|
485 | {
|
---|
486 | *p= 0xdeadbeef;
|
---|
487 | }
|
---|
488 |
|
---|
489 | eth_pack= bf_append(eth_pack, tail);
|
---|
490 | pack_size= ETH_MIN_PACK_SIZE;
|
---|
491 | }
|
---|
492 |
|
---|
493 | assert(ip_port->ip_dl.dl_eth.de_frame == NULL);
|
---|
494 |
|
---|
495 | r= eth_send(ip_port->ip_dl.dl_eth.de_fd, eth_pack, pack_size);
|
---|
496 | if (r == NW_OK)
|
---|
497 | continue;
|
---|
498 |
|
---|
499 | /* A non-blocking send is not possible, start a regular
|
---|
500 | * send.
|
---|
501 | */
|
---|
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);
|
---|
505 | if (r == NW_SUSPEND)
|
---|
506 | {
|
---|
507 | assert(!(ip_port->ip_dl.dl_eth.de_flags &
|
---|
508 | IEF_WRITE_SP));
|
---|
509 | ip_port->ip_dl.dl_eth.de_flags |= IEF_WRITE_SP;
|
---|
510 | return;
|
---|
511 | }
|
---|
512 | assert(r == NW_OK);
|
---|
513 | }
|
---|
514 | }
|
---|
515 |
|
---|
516 |
|
---|
517 | PRIVATE void ipeth_arp_reply(ip_port_nr, ipaddr, eth_addr)
|
---|
518 | int ip_port_nr;
|
---|
519 | ipaddr_t ipaddr;
|
---|
520 | ether_addr_t *eth_addr;
|
---|
521 | {
|
---|
522 | acc_t *prev, *eth_pack;
|
---|
523 | int r;
|
---|
524 | xmit_hdr_t *xmit_hdr;
|
---|
525 | ip_port_t *ip_port;
|
---|
526 | time_t t;
|
---|
527 | eth_hdr_t *eth_hdr;
|
---|
528 | ether_addr_t tmp_eth_addr;
|
---|
529 |
|
---|
530 | assert (ip_port_nr >= 0 && ip_port_nr < ip_conf_nr);
|
---|
531 | ip_port= &ip_port_table[ip_port_nr];
|
---|
532 |
|
---|
533 | for (;;)
|
---|
534 | {
|
---|
535 | for (prev= 0, eth_pack= ip_port->ip_dl.dl_eth.de_arp_head;
|
---|
536 | eth_pack;
|
---|
537 | prev= eth_pack, eth_pack= eth_pack->acc_ext_link)
|
---|
538 | {
|
---|
539 | xmit_hdr= (xmit_hdr_t *)ptr2acc_data(eth_pack);
|
---|
540 | if (xmit_hdr->xh_ipaddr == ipaddr)
|
---|
541 | break;
|
---|
542 | }
|
---|
543 |
|
---|
544 | if (eth_pack == NULL)
|
---|
545 | {
|
---|
546 | /* No packet found. */
|
---|
547 | break;
|
---|
548 | }
|
---|
549 |
|
---|
550 | /* Delete packet from the queue. */
|
---|
551 | if (prev == NULL)
|
---|
552 | {
|
---|
553 | ip_port->ip_dl.dl_eth.de_arp_head=
|
---|
554 | eth_pack->acc_ext_link;
|
---|
555 | }
|
---|
556 | else
|
---|
557 | {
|
---|
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;
|
---|
561 | }
|
---|
562 |
|
---|
563 | if (eth_addr == NULL)
|
---|
564 | {
|
---|
565 | /* Destination is unreachable, delete packet. */
|
---|
566 | bf_afree(eth_pack);
|
---|
567 | continue;
|
---|
568 | }
|
---|
569 |
|
---|
570 | /* Fill in the ethernet address and put the packet on the
|
---|
571 | * transmit queue.
|
---|
572 | */
|
---|
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));
|
---|
577 |
|
---|
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;
|
---|
581 | else
|
---|
582 | {
|
---|
583 | ip_port->ip_dl.dl_eth.de_q_tail->acc_ext_link=
|
---|
584 | eth_pack;
|
---|
585 | }
|
---|
586 | ip_port->ip_dl.dl_eth.de_q_tail= eth_pack;
|
---|
587 | }
|
---|
588 |
|
---|
589 | /* Try to get some more ARPs in progress. */
|
---|
590 | while (ip_port->ip_dl.dl_eth.de_arp_head)
|
---|
591 | {
|
---|
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);
|
---|
596 | if (r == NW_SUSPEND)
|
---|
597 | break; /* Normal case */
|
---|
598 |
|
---|
599 | /* Dequeue the packet */
|
---|
600 | ip_port->ip_dl.dl_eth.de_arp_head= eth_pack->acc_ext_link;
|
---|
601 |
|
---|
602 | if (r == EDSTNOTRCH)
|
---|
603 | {
|
---|
604 | bf_afree(eth_pack);
|
---|
605 | continue;
|
---|
606 | }
|
---|
607 | assert(r == NW_OK);
|
---|
608 |
|
---|
609 | /* Fill in the ethernet address and put the packet on the
|
---|
610 | * transmit queue.
|
---|
611 | */
|
---|
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));
|
---|
616 |
|
---|
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;
|
---|
620 | else
|
---|
621 | {
|
---|
622 | ip_port->ip_dl.dl_eth.de_q_tail->acc_ext_link=
|
---|
623 | eth_pack;
|
---|
624 | }
|
---|
625 | ip_port->ip_dl.dl_eth.de_q_tail= eth_pack;
|
---|
626 | }
|
---|
627 |
|
---|
628 | /* Restart sending ethernet packets. */
|
---|
629 | if (ip_port->ip_dl.dl_eth.de_frame == NULL)
|
---|
630 | ipeth_restart_send(ip_port);
|
---|
631 | }
|
---|
632 |
|
---|
633 | PRIVATE int ipeth_update_ttl(enq_time, now, eth_pack)
|
---|
634 | time_t enq_time;
|
---|
635 | time_t now;
|
---|
636 | acc_t *eth_pack;
|
---|
637 | {
|
---|
638 | int ttl_diff;
|
---|
639 | ip_hdr_t *ip_hdr;
|
---|
640 | u32_t sum;
|
---|
641 | u16_t word;
|
---|
642 | acc_t *ip_pack;
|
---|
643 |
|
---|
644 | ttl_diff= (now-enq_time)/HZ;
|
---|
645 | enq_time += ttl_diff*HZ;
|
---|
646 | assert(enq_time <= now && enq_time + HZ > now);
|
---|
647 |
|
---|
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);
|
---|
652 |
|
---|
653 | ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_pack);
|
---|
654 | if (ip_hdr->ih_ttl <= ttl_diff)
|
---|
655 | return ETIMEDOUT;
|
---|
656 | sum= (u16_t)~ip_hdr->ih_hdr_chk;
|
---|
657 | word= *(u16_t *)&ip_hdr->ih_ttl;
|
---|
658 | if (word > sum)
|
---|
659 | sum += 0xffff - word;
|
---|
660 | else
|
---|
661 | sum -= word;
|
---|
662 | ip_hdr->ih_ttl -= ttl_diff;
|
---|
663 | word= *(u16_t *)&ip_hdr->ih_ttl;
|
---|
664 | sum += word;
|
---|
665 | if (sum > 0xffff)
|
---|
666 | sum -= 0xffff;
|
---|
667 | assert(!(sum & 0xffff0000));
|
---|
668 | ip_hdr->ih_hdr_chk= ~sum;
|
---|
669 | assert(ip_hdr->ih_ttl > 0);
|
---|
670 | return NW_OK;
|
---|
671 | }
|
---|
672 |
|
---|
673 | PRIVATE void do_eth_read(ip_port)
|
---|
674 | ip_port_t *ip_port;
|
---|
675 | {
|
---|
676 | int result;
|
---|
677 |
|
---|
678 | assert(!(ip_port->ip_dl.dl_eth.de_flags & IEF_READ_IP));
|
---|
679 |
|
---|
680 | for (;;)
|
---|
681 | {
|
---|
682 | ip_port->ip_dl.dl_eth.de_flags |= IEF_READ_IP;
|
---|
683 |
|
---|
684 | result= eth_read (ip_port->ip_dl.dl_eth.de_fd,
|
---|
685 | ETH_MAX_PACK_SIZE);
|
---|
686 | if (result == NW_SUSPEND)
|
---|
687 | {
|
---|
688 | assert(!(ip_port->ip_dl.dl_eth.de_flags &
|
---|
689 | IEF_READ_SP));
|
---|
690 | ip_port->ip_dl.dl_eth.de_flags |= IEF_READ_SP;
|
---|
691 | return;
|
---|
692 | }
|
---|
693 | ip_port->ip_dl.dl_eth.de_flags &= ~IEF_READ_IP;
|
---|
694 | if (result<0)
|
---|
695 | {
|
---|
696 | return;
|
---|
697 | }
|
---|
698 | }
|
---|
699 | }
|
---|
700 |
|
---|
701 | PRIVATE void ip_eth_arrived(port, pack, pack_size)
|
---|
702 | int port;
|
---|
703 | acc_t *pack;
|
---|
704 | size_t pack_size;
|
---|
705 | {
|
---|
706 | int broadcast;
|
---|
707 | ip_port_t *ip_port;
|
---|
708 |
|
---|
709 | ip_port= &ip_port_table[port];
|
---|
710 | broadcast= (*(u8_t *)ptr2acc_data(pack) & 1);
|
---|
711 |
|
---|
712 | pack= bf_delhead(pack, ETH_HDR_SIZE);
|
---|
713 |
|
---|
714 | if (broadcast)
|
---|
715 | ip_arrived_broadcast(ip_port, pack);
|
---|
716 | else
|
---|
717 | ip_arrived(ip_port, pack);
|
---|
718 | }
|
---|
719 |
|
---|
720 | /*
|
---|
721 | * $PchId: ip_eth.c,v 1.25 2005/06/28 14:18:10 philip Exp $
|
---|
722 | */
|
---|