source: trunk/minix/servers/inet/generic/ip_read.c@ 15

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

Minix 3.1.2a

File size: 23.5 KB
Line 
1/*
2ip_read.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 "type.h"
12
13#include "assert.h"
14#include "icmp_lib.h"
15#include "io.h"
16#include "ip.h"
17#include "ip_int.h"
18#include "ipr.h"
19
20THIS_FILE
21
22FORWARD ip_ass_t *find_ass_ent ARGS(( ip_port_t *ip_port, U16_t id,
23 int proto, ipaddr_t src, ipaddr_t dst ));
24FORWARD acc_t *merge_frags ARGS(( acc_t *first, acc_t *second ));
25FORWARD int ip_frag_chk ARGS(( acc_t *pack ));
26FORWARD acc_t *reassemble ARGS(( ip_port_t *ip_port, acc_t *pack,
27 ip_hdr_t *ip_hdr ));
28FORWARD void route_packets ARGS(( event_t *ev, ev_arg_t ev_arg ));
29FORWARD int broadcast_dst ARGS(( ip_port_t *ip_port, ipaddr_t dest ));
30
31PUBLIC int ip_read (fd, count)
32int fd;
33size_t count;
34{
35 ip_fd_t *ip_fd;
36 acc_t *pack;
37
38 ip_fd= &ip_fd_table[fd];
39 if (!(ip_fd->if_flags & IFF_OPTSET))
40 {
41 return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, EBADMODE,
42 (acc_t *)0, FALSE);
43 }
44
45 ip_fd->if_rd_count= count;
46
47 ip_fd->if_flags |= IFF_READ_IP;
48 if (ip_fd->if_rdbuf_head)
49 {
50 if (get_time() <= ip_fd->if_exp_time)
51 {
52 pack= ip_fd->if_rdbuf_head;
53 ip_fd->if_rdbuf_head= pack->acc_ext_link;
54 ip_packet2user (ip_fd, pack, ip_fd->if_exp_time,
55 bf_bufsize(pack));
56 assert(!(ip_fd->if_flags & IFF_READ_IP));
57 return NW_OK;
58 }
59 while (ip_fd->if_rdbuf_head)
60 {
61 pack= ip_fd->if_rdbuf_head;
62 ip_fd->if_rdbuf_head= pack->acc_ext_link;
63 bf_afree(pack);
64 }
65 }
66 return NW_SUSPEND;
67}
68
69PRIVATE acc_t *reassemble (ip_port, pack, pack_hdr)
70ip_port_t *ip_port;
71acc_t *pack;
72ip_hdr_t *pack_hdr;
73{
74 ip_ass_t *ass_ent;
75 size_t pack_hdr_len, pack_data_len, pack_offset, tmp_offset;
76 u16_t pack_flags_fragoff;
77 acc_t *prev_acc, *curr_acc, *next_acc, *head_acc, *tmp_acc;
78 ip_hdr_t *tmp_hdr;
79 time_t first_time;
80
81 ass_ent= find_ass_ent (ip_port, pack_hdr->ih_id,
82 pack_hdr->ih_proto, pack_hdr->ih_src, pack_hdr->ih_dst);
83
84 pack_flags_fragoff= ntohs(pack_hdr->ih_flags_fragoff);
85 pack_hdr_len= (pack_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
86 pack_data_len= ntohs(pack_hdr->ih_length)-pack_hdr_len;
87 pack_offset= (pack_flags_fragoff & IH_FRAGOFF_MASK)*8;
88 pack->acc_ext_link= NULL;
89
90 head_acc= ass_ent->ia_frags;
91 ass_ent->ia_frags= NULL;
92 if (head_acc == NULL)
93 {
94 ass_ent->ia_frags= pack;
95 return NULL;
96 }
97
98 prev_acc= NULL;
99 curr_acc= NULL;
100 next_acc= head_acc;
101
102 while(next_acc)
103 {
104 tmp_hdr= (ip_hdr_t *)ptr2acc_data(next_acc);
105 tmp_offset= (ntohs(tmp_hdr->ih_flags_fragoff) &
106 IH_FRAGOFF_MASK)*8;
107
108 if (pack_offset < tmp_offset)
109 break;
110
111 prev_acc= curr_acc;
112 curr_acc= next_acc;
113 next_acc= next_acc->acc_ext_link;
114 }
115 if (curr_acc == NULL)
116 {
117 assert(prev_acc == NULL);
118 assert(next_acc != NULL);
119
120 curr_acc= merge_frags(pack, next_acc);
121 head_acc= curr_acc;
122 }
123 else
124 {
125 curr_acc= merge_frags(curr_acc, pack);
126 if (next_acc != NULL)
127 curr_acc= merge_frags(curr_acc, next_acc);
128 if (prev_acc != NULL)
129 prev_acc->acc_ext_link= curr_acc;
130 else
131 head_acc= curr_acc;
132 }
133 ass_ent->ia_frags= head_acc;
134
135 pack= ass_ent->ia_frags;
136 pack_hdr= (ip_hdr_t *)ptr2acc_data(pack);
137 pack_flags_fragoff= ntohs(pack_hdr->ih_flags_fragoff);
138
139 if (!(pack_flags_fragoff & (IH_FRAGOFF_MASK|IH_MORE_FRAGS)))
140 /* it's now a complete packet */
141 {
142 first_time= ass_ent->ia_first_time;
143
144 ass_ent->ia_frags= 0;
145 ass_ent->ia_first_time= 0;
146
147 while (pack->acc_ext_link)
148 {
149 tmp_acc= pack->acc_ext_link;
150 pack->acc_ext_link= tmp_acc->acc_ext_link;
151 bf_afree(tmp_acc);
152 }
153 if ((ass_ent->ia_min_ttl) * HZ + first_time <
154 get_time())
155 {
156 if (broadcast_dst(ip_port, pack_hdr->ih_dst))
157 {
158 DBLOCK(1, printf(
159 "ip_read'reassemble: reassembly timeout for broadcast packet\n"););
160 bf_afree(pack); pack= NULL;
161 return NULL;
162 }
163 icmp_snd_time_exceeded(ip_port->ip_port, pack,
164 ICMP_FRAG_REASSEM);
165 }
166 else
167 return pack;
168 }
169 return NULL;
170}
171
172PRIVATE acc_t *merge_frags (first, second)
173acc_t *first, *second;
174{
175 ip_hdr_t *first_hdr, *second_hdr;
176 size_t first_hdr_size, second_hdr_size, first_datasize, second_datasize,
177 first_offset, second_offset;
178 acc_t *cut_second, *tmp_acc;
179
180 if (!second)
181 {
182 first->acc_ext_link= NULL;
183 return first;
184 }
185
186assert (first->acc_length >= IP_MIN_HDR_SIZE);
187assert (second->acc_length >= IP_MIN_HDR_SIZE);
188
189 first_hdr= (ip_hdr_t *)ptr2acc_data(first);
190 first_offset= (ntohs(first_hdr->ih_flags_fragoff) &
191 IH_FRAGOFF_MASK) * 8;
192 first_hdr_size= (first_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
193 first_datasize= ntohs(first_hdr->ih_length) - first_hdr_size;
194
195 second_hdr= (ip_hdr_t *)ptr2acc_data(second);
196 second_offset= (ntohs(second_hdr->ih_flags_fragoff) &
197 IH_FRAGOFF_MASK) * 8;
198 second_hdr_size= (second_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
199 second_datasize= ntohs(second_hdr->ih_length) - second_hdr_size;
200
201 assert (first_hdr_size + first_datasize == bf_bufsize(first));
202 assert (second_hdr_size + second_datasize == bf_bufsize(second));
203 assert (second_offset >= first_offset);
204
205 if (second_offset > first_offset+first_datasize)
206 {
207 DBLOCK(1, printf("ip fragments out of order\n"));
208 first->acc_ext_link= second;
209 return first;
210 }
211
212 if (second_offset + second_datasize <= first_offset +
213 first_datasize)
214 {
215 /* May cause problems if we try to merge. */
216 bf_afree(first);
217 return second;
218 }
219
220 if (!(second_hdr->ih_flags_fragoff & HTONS(IH_MORE_FRAGS)))
221 first_hdr->ih_flags_fragoff &= ~HTONS(IH_MORE_FRAGS);
222
223 second_datasize= second_offset+second_datasize-(first_offset+
224 first_datasize);
225 cut_second= bf_cut(second, second_hdr_size + first_offset+
226 first_datasize-second_offset, second_datasize);
227 tmp_acc= second->acc_ext_link;
228 bf_afree(second);
229 second= tmp_acc;
230
231 first_datasize += second_datasize;
232 first_hdr->ih_length= htons(first_hdr_size + first_datasize);
233
234 first= bf_append (first, cut_second);
235 first->acc_ext_link= second;
236
237assert (first_hdr_size + first_datasize == bf_bufsize(first));
238
239 return first;
240}
241
242PRIVATE ip_ass_t *find_ass_ent (ip_port, id, proto, src, dst)
243ip_port_t *ip_port;
244u16_t id;
245ipproto_t proto;
246ipaddr_t src;
247ipaddr_t dst;
248{
249 ip_ass_t *new_ass_ent, *tmp_ass_ent;
250 int i;
251 acc_t *tmp_acc, *curr_acc;
252
253 new_ass_ent= 0;
254
255 for (i=0, tmp_ass_ent= ip_ass_table; i<IP_ASS_NR; i++,
256 tmp_ass_ent++)
257 {
258 if (!tmp_ass_ent->ia_frags && tmp_ass_ent->ia_first_time)
259 {
260 DBLOCK(1,
261 printf("strange ip_ass entry (can be a race condition)\n"));
262 continue;
263 }
264
265 if ((tmp_ass_ent->ia_srcaddr == src) &&
266 (tmp_ass_ent->ia_dstaddr == dst) &&
267 (tmp_ass_ent->ia_proto == proto) &&
268 (tmp_ass_ent->ia_id == id) &&
269 (tmp_ass_ent->ia_port == ip_port))
270 {
271 return tmp_ass_ent;
272 }
273 if (!new_ass_ent || tmp_ass_ent->ia_first_time <
274 new_ass_ent->ia_first_time)
275 {
276 new_ass_ent= tmp_ass_ent;
277 }
278 }
279
280 if (new_ass_ent->ia_frags)
281 {
282 DBLOCK(2, printf("old frags id= %u, proto= %u, src= ",
283 ntohs(new_ass_ent->ia_id),
284 new_ass_ent->ia_proto);
285 writeIpAddr(new_ass_ent->ia_srcaddr); printf(" dst= ");
286 writeIpAddr(new_ass_ent->ia_dstaddr); printf(": ");
287 ip_print_frags(new_ass_ent->ia_frags); printf("\n"));
288 curr_acc= new_ass_ent->ia_frags->acc_ext_link;
289 while (curr_acc)
290 {
291 tmp_acc= curr_acc->acc_ext_link;
292 bf_afree(curr_acc);
293 curr_acc= tmp_acc;
294 }
295 curr_acc= new_ass_ent->ia_frags;
296 new_ass_ent->ia_frags= 0;
297 if (broadcast_dst(ip_port, new_ass_ent->ia_dstaddr))
298 {
299 DBLOCK(1, printf(
300 "ip_read'find_ass_ent: reassembly timeout for broadcast packet\n"));
301 bf_afree(curr_acc); curr_acc= NULL;
302 }
303 else
304 {
305 icmp_snd_time_exceeded(ip_port->ip_port,
306 curr_acc, ICMP_FRAG_REASSEM);
307 }
308 }
309 new_ass_ent->ia_min_ttl= IP_MAX_TTL;
310 new_ass_ent->ia_port= ip_port;
311 new_ass_ent->ia_first_time= get_time();
312 new_ass_ent->ia_srcaddr= src;
313 new_ass_ent->ia_dstaddr= dst;
314 new_ass_ent->ia_proto= proto;
315 new_ass_ent->ia_id= id;
316
317 return new_ass_ent;
318}
319
320PRIVATE int ip_frag_chk(pack)
321acc_t *pack;
322{
323 ip_hdr_t *ip_hdr;
324 int hdr_len;
325
326 if (pack->acc_length < sizeof(ip_hdr_t))
327 {
328 DBLOCK(1, printf("wrong length\n"));
329 return FALSE;
330 }
331
332 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
333
334 hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
335 if (pack->acc_length < hdr_len)
336 {
337 DBLOCK(1, printf("wrong length\n"));
338
339 return FALSE;
340 }
341
342 if (((ip_hdr->ih_vers_ihl >> 4) & IH_VERSION_MASK) !=
343 IP_VERSION)
344 {
345 DBLOCK(1, printf("wrong version (ih_vers_ihl=0x%x)\n",
346 ip_hdr->ih_vers_ihl));
347 return FALSE;
348 }
349 if (ntohs(ip_hdr->ih_length) != bf_bufsize(pack))
350 {
351 DBLOCK(1, printf("wrong size\n"));
352
353 return FALSE;
354 }
355 if ((u16_t)~oneC_sum(0, (u16_t *)ip_hdr, hdr_len))
356 {
357 DBLOCK(1, printf("packet with wrong checksum (= %x)\n",
358 (u16_t)~oneC_sum(0, (u16_t *)ip_hdr, hdr_len)));
359 return FALSE;
360 }
361 if (hdr_len>IP_MIN_HDR_SIZE && ip_chk_hdropt((u8_t *)
362 (ptr2acc_data(pack) + IP_MIN_HDR_SIZE),
363 hdr_len-IP_MIN_HDR_SIZE))
364 {
365 DBLOCK(1, printf("packet with wrong options\n"));
366 return FALSE;
367 }
368 return TRUE;
369}
370
371PUBLIC void ip_packet2user (ip_fd, pack, exp_time, data_len)
372ip_fd_t *ip_fd;
373acc_t *pack;
374time_t exp_time;
375size_t data_len;
376{
377 acc_t *tmp_pack;
378 ip_hdr_t *ip_hdr;
379 int result, ip_hdr_len;
380 size_t transf_size;
381
382 assert (ip_fd->if_flags & IFF_INUSE);
383 if (!(ip_fd->if_flags & IFF_READ_IP))
384 {
385 if (pack->acc_linkC != 1)
386 {
387 tmp_pack= bf_dupacc(pack);
388 bf_afree(pack);
389 pack= tmp_pack;
390 tmp_pack= NULL;
391 }
392 pack->acc_ext_link= NULL;
393 if (ip_fd->if_rdbuf_head == NULL)
394 {
395 ip_fd->if_rdbuf_head= pack;
396 ip_fd->if_exp_time= exp_time;
397 }
398 else
399 ip_fd->if_rdbuf_tail->acc_ext_link= pack;
400 ip_fd->if_rdbuf_tail= pack;
401 return;
402 }
403
404 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
405 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
406
407 if (ip_fd->if_ipopt.nwio_flags & NWIO_RWDATONLY)
408 {
409 ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
410
411 assert (data_len > ip_hdr_len);
412 data_len -= ip_hdr_len;
413 pack= bf_delhead(pack, ip_hdr_len);
414 }
415
416 if (data_len > ip_fd->if_rd_count)
417 {
418 tmp_pack= bf_cut (pack, 0, ip_fd->if_rd_count);
419 bf_afree(pack);
420 pack= tmp_pack;
421 transf_size= ip_fd->if_rd_count;
422 }
423 else
424 transf_size= data_len;
425
426 if (ip_fd->if_put_pkt)
427 {
428 (*ip_fd->if_put_pkt)(ip_fd->if_srfd, pack, transf_size);
429 return;
430 }
431
432 result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
433 (size_t)0, pack, FALSE);
434 if (result >= 0)
435 {
436 if (data_len > transf_size)
437 result= EPACKSIZE;
438 else
439 result= transf_size;
440 }
441
442 ip_fd->if_flags &= ~IFF_READ_IP;
443 result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd, result,
444 (acc_t *)0, FALSE);
445 assert (result >= 0);
446}
447
448PUBLIC void ip_port_arrive (ip_port, pack, ip_hdr)
449ip_port_t *ip_port;
450acc_t *pack;
451ip_hdr_t *ip_hdr;
452{
453 ip_fd_t *ip_fd, *first_fd, *share_fd;
454 unsigned long ip_pack_stat;
455 unsigned size;
456 int i;
457 int hash, proto;
458 time_t exp_time;
459
460 assert (pack->acc_linkC>0);
461 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
462
463 if (ntohs(ip_hdr->ih_flags_fragoff) & (IH_FRAGOFF_MASK|IH_MORE_FRAGS))
464 {
465 pack= reassemble (ip_port, pack, ip_hdr);
466 if (!pack)
467 return;
468 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
469 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
470 assert (!(ntohs(ip_hdr->ih_flags_fragoff) &
471 (IH_FRAGOFF_MASK|IH_MORE_FRAGS)));
472 }
473 size= ntohs(ip_hdr->ih_length);
474 if (size > bf_bufsize(pack))
475 {
476 /* Should discard packet */
477 assert(0);
478 bf_afree(pack); pack= NULL;
479 return;
480 }
481
482 exp_time= get_time() + (ip_hdr->ih_ttl+1) * HZ;
483
484 if (ip_hdr->ih_dst == ip_port->ip_ipaddr)
485 ip_pack_stat= NWIO_EN_LOC;
486 else
487 ip_pack_stat= NWIO_EN_BROAD;
488
489 proto= ip_hdr->ih_proto;
490 hash= proto & (IP_PROTO_HASH_NR-1);
491
492 first_fd= NULL;
493 for (i= 0; i<2; i++)
494 {
495 share_fd= NULL;
496
497 ip_fd= (i == 0) ? ip_port->ip_proto_any :
498 ip_port->ip_proto[hash];
499 for (; ip_fd; ip_fd= ip_fd->if_proto_next)
500 {
501 if (i && ip_fd->if_ipopt.nwio_proto != proto)
502 continue;
503 if (!(ip_fd->if_ipopt.nwio_flags & ip_pack_stat))
504 continue;
505 if ((ip_fd->if_ipopt.nwio_flags & NWIO_REMSPEC) &&
506 ip_hdr->ih_src != ip_fd->if_ipopt.nwio_rem)
507 {
508 continue;
509 }
510 if ((ip_fd->if_ipopt.nwio_flags & NWIO_ACC_MASK) ==
511 NWIO_SHARED)
512 {
513 if (!share_fd)
514 {
515 share_fd= ip_fd;
516 continue;
517 }
518 if (!ip_fd->if_rdbuf_head)
519 share_fd= ip_fd;
520 continue;
521 }
522 if (!first_fd)
523 {
524 first_fd= ip_fd;
525 continue;
526 }
527 pack->acc_linkC++;
528 ip_packet2user(ip_fd, pack, exp_time, size);
529
530 }
531 if (share_fd)
532 {
533 pack->acc_linkC++;
534 ip_packet2user(share_fd, pack, exp_time, size);
535 }
536 }
537 if (first_fd)
538 {
539 if (first_fd->if_put_pkt &&
540 (first_fd->if_flags & IFF_READ_IP) &&
541 !(first_fd->if_ipopt.nwio_flags & NWIO_RWDATONLY))
542 {
543 (*first_fd->if_put_pkt)(first_fd->if_srfd, pack,
544 size);
545 }
546 else
547 ip_packet2user(first_fd, pack, exp_time, size);
548 }
549 else
550 {
551 if (ip_pack_stat == NWIO_EN_LOC)
552 {
553 DBLOCK(0x01,
554 printf("ip_port_arrive: dropping packet for proto %d\n",
555 proto));
556 }
557 else
558 {
559 DBLOCK(0x20, printf("dropping packet for proto %d\n",
560 proto));
561 }
562 bf_afree(pack);
563 }
564}
565
566PUBLIC void ip_arrived(ip_port, pack)
567ip_port_t *ip_port;
568acc_t *pack;
569{
570 ip_hdr_t *ip_hdr;
571 ipaddr_t dest;
572 int ip_frag_len, ip_hdr_len, highbyte;
573 size_t pack_size;
574 acc_t *tmp_pack, *hdr_pack;
575 ev_arg_t ev_arg;
576
577 pack_size= bf_bufsize(pack);
578
579 if (pack_size < IP_MIN_HDR_SIZE)
580 {
581 DBLOCK(1, printf("wrong acc_length\n"));
582 bf_afree(pack);
583 return;
584 }
585 pack= bf_align(pack, IP_MIN_HDR_SIZE, 4);
586 pack= bf_packIffLess(pack, IP_MIN_HDR_SIZE);
587assert (pack->acc_length >= IP_MIN_HDR_SIZE);
588
589 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
590 ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
591 if (ip_hdr_len>IP_MIN_HDR_SIZE)
592 {
593 pack= bf_packIffLess(pack, ip_hdr_len);
594 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
595 }
596 ip_frag_len= ntohs(ip_hdr->ih_length);
597 if (ip_frag_len != pack_size)
598 {
599 if (pack_size < ip_frag_len)
600 {
601 /* Sent ICMP? */
602 DBLOCK(1, printf("wrong acc_length\n"));
603 bf_afree(pack);
604 return;
605 }
606 assert(ip_frag_len<pack_size);
607 tmp_pack= pack;
608 pack= bf_cut(tmp_pack, 0, ip_frag_len);
609 bf_afree(tmp_pack);
610 pack_size= ip_frag_len;
611 }
612
613 if (!ip_frag_chk(pack))
614 {
615 DBLOCK(1, printf("fragment not allright\n"));
616 bf_afree(pack);
617 return;
618 }
619
620 /* Decide about local delivery or routing. Local delivery can happen
621 * when the destination is the local ip address, or one of the
622 * broadcast addresses and the packet happens to be delivered
623 * point-to-point.
624 */
625
626 dest= ip_hdr->ih_dst;
627
628 if (dest == ip_port->ip_ipaddr)
629 {
630 ip_port_arrive (ip_port, pack, ip_hdr);
631 return;
632 }
633 if (broadcast_dst(ip_port, dest))
634 {
635 ip_port_arrive (ip_port, pack, ip_hdr);
636 return;
637 }
638
639 if (pack->acc_linkC != 1 || pack->acc_buffer->buf_linkC != 1)
640 {
641 /* Get a private copy of the IP header */
642 hdr_pack= bf_memreq(ip_hdr_len);
643 memcpy(ptr2acc_data(hdr_pack), ip_hdr, ip_hdr_len);
644 pack= bf_delhead(pack, ip_hdr_len);
645 hdr_pack->acc_next= pack;
646 pack= hdr_pack; hdr_pack= NULL;
647 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
648 }
649 assert(pack->acc_linkC == 1);
650 assert(pack->acc_buffer->buf_linkC == 1);
651
652 /* Try to decrement the ttl field with one. */
653 if (ip_hdr->ih_ttl < 2)
654 {
655 icmp_snd_time_exceeded(ip_port->ip_port, pack,
656 ICMP_TTL_EXC);
657 return;
658 }
659 ip_hdr->ih_ttl--;
660 ip_hdr_chksum(ip_hdr, ip_hdr_len);
661
662 /* Avoid routing to bad destinations. */
663 highbyte= ntohl(dest) >> 24;
664 if (highbyte == 0 || highbyte == 127 ||
665 (highbyte == 169 && (((ntohl(dest) >> 16) & 0xff) == 254)) ||
666 highbyte >= 0xe0)
667 {
668 /* Bogus destination address */
669 bf_afree(pack);
670 return;
671 }
672
673 /* Further processing from an event handler */
674 if (pack->acc_linkC != 1)
675 {
676 tmp_pack= bf_dupacc(pack);
677 bf_afree(pack);
678 pack= tmp_pack;
679 tmp_pack= NULL;
680 }
681 pack->acc_ext_link= NULL;
682 if (ip_port->ip_routeq_head)
683 {
684 ip_port->ip_routeq_tail->acc_ext_link= pack;
685 ip_port->ip_routeq_tail= pack;
686 return;
687 }
688
689 ip_port->ip_routeq_head= pack;
690 ip_port->ip_routeq_tail= pack;
691 ev_arg.ev_ptr= ip_port;
692 ev_enqueue(&ip_port->ip_routeq_event, route_packets, ev_arg);
693}
694
695PUBLIC void ip_arrived_broadcast(ip_port, pack)
696ip_port_t *ip_port;
697acc_t *pack;
698{
699 ip_hdr_t *ip_hdr;
700 int ip_frag_len, ip_hdr_len;
701 size_t pack_size;
702 acc_t *tmp_pack;
703
704 pack_size= bf_bufsize(pack);
705
706 if (pack_size < IP_MIN_HDR_SIZE)
707 {
708 DBLOCK(1, printf("wrong acc_length\n"));
709 bf_afree(pack);
710 return;
711 }
712 pack= bf_align(pack, IP_MIN_HDR_SIZE, 4);
713 pack= bf_packIffLess(pack, IP_MIN_HDR_SIZE);
714assert (pack->acc_length >= IP_MIN_HDR_SIZE);
715
716 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
717
718 DIFBLOCK(0x20, (ip_hdr->ih_dst & HTONL(0xf0000000)) == HTONL(0xe0000000),
719 printf("got multicast packet\n"));
720
721 ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
722 if (ip_hdr_len>IP_MIN_HDR_SIZE)
723 {
724 pack= bf_align(pack, IP_MIN_HDR_SIZE, 4);
725 pack= bf_packIffLess(pack, ip_hdr_len);
726 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
727 }
728 ip_frag_len= ntohs(ip_hdr->ih_length);
729 if (ip_frag_len<pack_size)
730 {
731 tmp_pack= pack;
732 pack= bf_cut(tmp_pack, 0, ip_frag_len);
733 bf_afree(tmp_pack);
734 }
735
736 if (!ip_frag_chk(pack))
737 {
738 DBLOCK(1, printf("fragment not allright\n"));
739 bf_afree(pack);
740 return;
741 }
742
743 if (!broadcast_dst(ip_port, ip_hdr->ih_dst))
744 {
745#if 0
746 printf(
747 "ip[%d]: broadcast packet for ip-nonbroadcast addr, src=",
748 ip_port->ip_port);
749 writeIpAddr(ip_hdr->ih_src);
750 printf(" dst=");
751 writeIpAddr(ip_hdr->ih_dst);
752 printf("\n");
753#endif
754 bf_afree(pack);
755 return;
756 }
757
758 ip_port_arrive (ip_port, pack, ip_hdr);
759}
760
761PRIVATE void route_packets(ev, ev_arg)
762event_t *ev;
763ev_arg_t ev_arg;
764{
765 ip_port_t *ip_port;
766 ipaddr_t dest;
767 acc_t *pack;
768 iroute_t *iroute;
769 ip_port_t *next_port;
770 int r, type;
771 ip_hdr_t *ip_hdr;
772 size_t req_mtu;
773
774 ip_port= ev_arg.ev_ptr;
775 assert(&ip_port->ip_routeq_event == ev);
776
777 while (pack= ip_port->ip_routeq_head, pack != NULL)
778 {
779 ip_port->ip_routeq_head= pack->acc_ext_link;
780
781 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
782 dest= ip_hdr->ih_dst;
783
784 iroute= iroute_frag(ip_port->ip_port, dest);
785 if (iroute == NULL || iroute->irt_dist == IRTD_UNREACHABLE)
786 {
787 /* Also unreachable */
788 /* Finding out if we send a network unreachable is too
789 * much trouble.
790 */
791 if (iroute == NULL)
792 {
793 printf("ip[%d]: no route to ",
794 ip_port-ip_port_table);
795 writeIpAddr(dest);
796 printf("\n");
797 }
798 icmp_snd_unreachable(ip_port->ip_port, pack,
799 ICMP_HOST_UNRCH);
800 continue;
801 }
802 next_port= &ip_port_table[iroute->irt_port];
803
804 if (ip_hdr->ih_flags_fragoff & HTONS(IH_DONT_FRAG))
805 {
806 req_mtu= bf_bufsize(pack);
807 if (req_mtu > next_port->ip_mtu ||
808 (iroute->irt_mtu && req_mtu>iroute->irt_mtu))
809 {
810 icmp_snd_mtu(ip_port->ip_port, pack,
811 next_port->ip_mtu);
812 continue;
813 }
814 }
815
816 if (next_port != ip_port)
817 {
818 if (iroute->irt_gateway != 0)
819 {
820 /* Just send the packet to the next gateway */
821 pack->acc_linkC++; /* Extra ref for ICMP */
822 r= next_port->ip_dev_send(next_port,
823 iroute->irt_gateway,
824 pack, IP_LT_NORMAL);
825 if (r == EDSTNOTRCH)
826 {
827 printf("ip[%d]: gw ",
828 ip_port-ip_port_table);
829 writeIpAddr(iroute->irt_gateway);
830 printf(" on ip[%d] is down for dest ",
831 next_port-ip_port_table);
832 writeIpAddr(dest);
833 printf("\n");
834 icmp_snd_unreachable(next_port-
835 ip_port_table, pack,
836 ICMP_HOST_UNRCH);
837 pack= NULL;
838 }
839 else
840 {
841 assert(r == 0);
842 bf_afree(pack); pack= NULL;
843 }
844 continue;
845 }
846 /* The packet is for the attached network. Special
847 * addresses are the ip address of the interface and
848 * net.0 if no IP_42BSD_BCAST.
849 */
850 if (dest == next_port->ip_ipaddr)
851 {
852 ip_port_arrive (next_port, pack, ip_hdr);
853 continue;
854 }
855 if (dest == iroute->irt_dest)
856 {
857 /* Never forward obsolete directed broadcasts */
858#if IP_42BSD_BCAST && 0
859 type= IP_LT_BROADCAST;
860#else
861 /* Bogus destination address */
862 DBLOCK(1, printf(
863 "ip[%d]: dropping old-fashioned directed broadcast ",
864 ip_port-ip_port_table);
865 writeIpAddr(dest);
866 printf("\n"););
867 icmp_snd_unreachable(next_port-ip_port_table,
868 pack, ICMP_HOST_UNRCH);
869 continue;
870#endif
871 }
872 else if (dest == (iroute->irt_dest |
873 ~iroute->irt_subnetmask))
874 {
875 if (!ip_forward_directed_bcast)
876 {
877 /* Do not forward directed broadcasts */
878 DBLOCK(1, printf(
879 "ip[%d]: dropping directed broadcast ",
880 ip_port-ip_port_table);
881 writeIpAddr(dest);
882 printf("\n"););
883 icmp_snd_unreachable(next_port-
884 ip_port_table, pack,
885 ICMP_HOST_UNRCH);
886 continue;
887 }
888 else
889 type= IP_LT_BROADCAST;
890 }
891 else
892 type= IP_LT_NORMAL;
893
894 /* Just send the packet to it's destination */
895 pack->acc_linkC++; /* Extra ref for ICMP */
896 r= next_port->ip_dev_send(next_port, dest, pack, type);
897 if (r == EDSTNOTRCH)
898 {
899 DBLOCK(1, printf("ip[%d]: next hop ",
900 ip_port-ip_port_table);
901 writeIpAddr(dest);
902 printf(" on ip[%d] is down\n",
903 next_port-ip_port_table););
904 icmp_snd_unreachable(next_port-ip_port_table,
905 pack, ICMP_HOST_UNRCH);
906 pack= NULL;
907 }
908 else
909 {
910 assert(r == 0 || (printf("r = %d\n", r), 0));
911 bf_afree(pack); pack= NULL;
912 }
913 continue;
914 }
915
916 /* Now we know that the packet should be routed over the same
917 * network as it came from. If there is a next hop gateway,
918 * we can send the packet to that gateway and send a redirect
919 * ICMP to the sender if the sender is on the attached
920 * network. If there is no gateway complain.
921 */
922 if (iroute->irt_gateway == 0)
923 {
924 printf("ip_arrived: packet should not be here, src=");
925 writeIpAddr(ip_hdr->ih_src);
926 printf(" dst=");
927 writeIpAddr(ip_hdr->ih_dst);
928 printf("\n");
929 bf_afree(pack);
930 continue;
931 }
932 if (((ip_hdr->ih_src ^ ip_port->ip_ipaddr) &
933 ip_port->ip_subnetmask) == 0)
934 {
935 /* Finding out if we can send a network redirect
936 * instead of a host redirect is too much trouble.
937 */
938 pack->acc_linkC++;
939 icmp_snd_redirect(ip_port->ip_port, pack,
940 ICMP_REDIRECT_HOST, iroute->irt_gateway);
941 }
942 else
943 {
944 printf("ip_arrived: packet is wrongly routed, src=");
945 writeIpAddr(ip_hdr->ih_src);
946 printf(" dst=");
947 writeIpAddr(ip_hdr->ih_dst);
948 printf("\n");
949 printf("in port %d, output %d, dest net ",
950 ip_port->ip_port,
951 iroute->irt_port);
952 writeIpAddr(iroute->irt_dest);
953 printf("/");
954 writeIpAddr(iroute->irt_subnetmask);
955 printf(" next hop ");
956 writeIpAddr(iroute->irt_gateway);
957 printf("\n");
958 bf_afree(pack);
959 continue;
960 }
961 /* No code for unreachable ICMPs here. The sender should
962 * process the ICMP redirect and figure it out.
963 */
964 ip_port->ip_dev_send(ip_port, iroute->irt_gateway, pack,
965 IP_LT_NORMAL);
966 }
967}
968
969PRIVATE int broadcast_dst(ip_port, dest)
970ip_port_t *ip_port;
971ipaddr_t dest;
972{
973 ipaddr_t my_ipaddr, netmask, classmask;
974
975 /* Treat class D (multicast) address as broadcasts. */
976 if ((dest & HTONL(0xF0000000)) == HTONL(0xE0000000))
977 {
978 return 1;
979 }
980
981 /* Accept without complaint if netmask not yet configured. */
982 if (!(ip_port->ip_flags & IPF_NETMASKSET))
983 {
984 return 1;
985 }
986 /* Two possibilities, 0 (iff IP_42BSD_BCAST) and -1 */
987 if (dest == HTONL((ipaddr_t)-1))
988 return 1;
989#if IP_42BSD_BCAST
990 if (dest == HTONL((ipaddr_t)0))
991 return 1;
992#endif
993 netmask= ip_port->ip_subnetmask;
994 my_ipaddr= ip_port->ip_ipaddr;
995
996 if (((my_ipaddr ^ dest) & netmask) != 0)
997 {
998 classmask= ip_port->ip_classfulmask;
999
1000 /* Not a subnet broadcast, maybe a classful broadcast */
1001 if (((my_ipaddr ^ dest) & classmask) != 0)
1002 {
1003 return 0;
1004 }
1005 /* Two possibilities, net.0 (iff IP_42BSD_BCAST) and net.-1 */
1006 if ((dest & ~classmask) == ~classmask)
1007 {
1008 return 1;
1009 }
1010#if IP_42BSD_BCAST
1011 if ((dest & ~classmask) == 0)
1012 return 1;
1013#endif
1014 return 0;
1015 }
1016
1017 if (!(ip_port->ip_flags & IPF_SUBNET_BCAST))
1018 return 0; /* No subnet broadcasts on this network */
1019
1020 /* Two possibilities, subnet.0 (iff IP_42BSD_BCAST) and subnet.-1 */
1021 if ((dest & ~netmask) == ~netmask)
1022 return 1;
1023#if IP_42BSD_BCAST
1024 if ((dest & ~netmask) == 0)
1025 return 1;
1026#endif
1027 return 0;
1028}
1029
1030void ip_process_loopb(ev, arg)
1031event_t *ev;
1032ev_arg_t arg;
1033{
1034 ip_port_t *ip_port;
1035 acc_t *pack;
1036
1037 ip_port= arg.ev_ptr;
1038 assert(ev == &ip_port->ip_loopb_event);
1039
1040 while(pack= ip_port->ip_loopb_head, pack != NULL)
1041 {
1042 ip_port->ip_loopb_head= pack->acc_ext_link;
1043 ip_arrived(ip_port, pack);
1044 }
1045}
1046
1047/*
1048 * $PchId: ip_read.c,v 1.33 2005/06/28 14:18:50 philip Exp $
1049 */
Note: See TracBrowser for help on using the repository browser.