opendir change: refinement
[minix.git] / servers / inet / generic / ip_read.c
blob5c8926d08a1eace47cacb2d790b0239dc7fc99e1
1 /*
2 ip_read.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 "type.h"
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 #include "sr.h"
21 THIS_FILE
23 static ip_ass_t *find_ass_ent ARGS(( ip_port_t *ip_port, u16_t id,
24 ipproto_t proto, ipaddr_t src, ipaddr_t dst ));
25 static acc_t *merge_frags ARGS(( acc_t *first, acc_t *second ));
26 static int ip_frag_chk ARGS(( acc_t *pack ));
27 static acc_t *reassemble ARGS(( ip_port_t *ip_port, acc_t *pack,
28 ip_hdr_t *ip_hdr ));
29 static void route_packets ARGS(( event_t *ev, ev_arg_t ev_arg ));
30 static int broadcast_dst ARGS(( ip_port_t *ip_port, ipaddr_t dest ));
32 int ip_read(int fd, size_t count)
34 ip_fd_t *ip_fd;
35 acc_t *pack;
37 ip_fd= &ip_fd_table[fd];
38 if (!(ip_fd->if_flags & IFF_OPTSET))
40 return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, EBADMODE,
41 (acc_t *)0, FALSE);
44 ip_fd->if_rd_count= count;
46 ip_fd->if_flags |= IFF_READ_IP;
47 if (ip_fd->if_rdbuf_head)
49 if (get_time() <= ip_fd->if_exp_time)
51 pack= ip_fd->if_rdbuf_head;
52 ip_fd->if_rdbuf_head= pack->acc_ext_link;
53 ip_packet2user (ip_fd, pack, ip_fd->if_exp_time,
54 bf_bufsize(pack));
55 assert(!(ip_fd->if_flags & IFF_READ_IP));
56 return NW_OK;
58 while (ip_fd->if_rdbuf_head)
60 pack= ip_fd->if_rdbuf_head;
61 ip_fd->if_rdbuf_head= pack->acc_ext_link;
62 bf_afree(pack);
65 return NW_SUSPEND;
68 static acc_t *reassemble (ip_port, pack, pack_hdr)
69 ip_port_t *ip_port;
70 acc_t *pack;
71 ip_hdr_t *pack_hdr;
73 ip_ass_t *ass_ent;
74 size_t pack_offset, tmp_offset;
75 u16_t pack_flags_fragoff;
76 acc_t *prev_acc, *curr_acc, *next_acc, *head_acc, *tmp_acc;
77 ip_hdr_t *tmp_hdr;
78 time_t first_time;
80 ass_ent= find_ass_ent (ip_port, pack_hdr->ih_id,
81 pack_hdr->ih_proto, pack_hdr->ih_src, pack_hdr->ih_dst);
83 pack_flags_fragoff= ntohs(pack_hdr->ih_flags_fragoff);
84 pack_offset= (pack_flags_fragoff & IH_FRAGOFF_MASK)*8;
85 pack->acc_ext_link= NULL;
87 head_acc= ass_ent->ia_frags;
88 ass_ent->ia_frags= NULL;
89 if (head_acc == NULL)
91 ass_ent->ia_frags= pack;
92 return NULL;
95 prev_acc= NULL;
96 curr_acc= NULL;
97 next_acc= head_acc;
99 while(next_acc)
101 tmp_hdr= (ip_hdr_t *)ptr2acc_data(next_acc);
102 tmp_offset= (ntohs(tmp_hdr->ih_flags_fragoff) &
103 IH_FRAGOFF_MASK)*8;
105 if (pack_offset < tmp_offset)
106 break;
108 prev_acc= curr_acc;
109 curr_acc= next_acc;
110 next_acc= next_acc->acc_ext_link;
112 if (curr_acc == NULL)
114 assert(prev_acc == NULL);
115 assert(next_acc != NULL);
117 curr_acc= merge_frags(pack, next_acc);
118 head_acc= curr_acc;
120 else
122 curr_acc= merge_frags(curr_acc, pack);
123 if (next_acc != NULL)
124 curr_acc= merge_frags(curr_acc, next_acc);
125 if (prev_acc != NULL)
126 prev_acc->acc_ext_link= curr_acc;
127 else
128 head_acc= curr_acc;
130 ass_ent->ia_frags= head_acc;
132 pack= ass_ent->ia_frags;
133 pack_hdr= (ip_hdr_t *)ptr2acc_data(pack);
134 pack_flags_fragoff= ntohs(pack_hdr->ih_flags_fragoff);
136 if (!(pack_flags_fragoff & (IH_FRAGOFF_MASK|IH_MORE_FRAGS)))
137 /* it's now a complete packet */
139 first_time= ass_ent->ia_first_time;
141 ass_ent->ia_frags= 0;
142 ass_ent->ia_first_time= 0;
144 while (pack->acc_ext_link)
146 tmp_acc= pack->acc_ext_link;
147 pack->acc_ext_link= tmp_acc->acc_ext_link;
148 bf_afree(tmp_acc);
150 if ((ass_ent->ia_min_ttl) * HZ + first_time <
151 get_time())
153 if (broadcast_dst(ip_port, pack_hdr->ih_dst))
155 DBLOCK(1, printf(
156 "ip_read'reassemble: reassembly timeout for broadcast packet\n"););
157 bf_afree(pack); pack= NULL;
158 return NULL;
160 icmp_snd_time_exceeded(ip_port->ip_port, pack,
161 ICMP_FRAG_REASSEM);
163 else
164 return pack;
166 return NULL;
169 static acc_t *merge_frags (first, second)
170 acc_t *first, *second;
172 ip_hdr_t *first_hdr, *second_hdr;
173 size_t first_hdr_size, second_hdr_size, first_datasize, second_datasize,
174 first_offset, second_offset;
175 acc_t *cut_second, *tmp_acc;
177 if (!second)
179 first->acc_ext_link= NULL;
180 return first;
183 assert (first->acc_length >= IP_MIN_HDR_SIZE);
184 assert (second->acc_length >= IP_MIN_HDR_SIZE);
186 first_hdr= (ip_hdr_t *)ptr2acc_data(first);
187 first_offset= (ntohs(first_hdr->ih_flags_fragoff) &
188 IH_FRAGOFF_MASK) * 8;
189 first_hdr_size= (first_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
190 first_datasize= ntohs(first_hdr->ih_length) - first_hdr_size;
192 second_hdr= (ip_hdr_t *)ptr2acc_data(second);
193 second_offset= (ntohs(second_hdr->ih_flags_fragoff) &
194 IH_FRAGOFF_MASK) * 8;
195 second_hdr_size= (second_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
196 second_datasize= ntohs(second_hdr->ih_length) - second_hdr_size;
198 assert (first_hdr_size + first_datasize == bf_bufsize(first));
199 assert (second_hdr_size + second_datasize == bf_bufsize(second));
200 assert (second_offset >= first_offset);
202 if (second_offset > first_offset+first_datasize)
204 DBLOCK(1, printf("ip fragments out of order\n"));
205 first->acc_ext_link= second;
206 return first;
209 if (second_offset + second_datasize <= first_offset +
210 first_datasize)
212 /* May cause problems if we try to merge. */
213 bf_afree(first);
214 return second;
217 if (!(second_hdr->ih_flags_fragoff & HTONS(IH_MORE_FRAGS)))
218 first_hdr->ih_flags_fragoff &= ~HTONS(IH_MORE_FRAGS);
220 second_datasize= second_offset+second_datasize-(first_offset+
221 first_datasize);
222 cut_second= bf_cut(second, second_hdr_size + first_offset+
223 first_datasize-second_offset, second_datasize);
224 tmp_acc= second->acc_ext_link;
225 bf_afree(second);
226 second= tmp_acc;
228 first_datasize += second_datasize;
229 first_hdr->ih_length= htons(first_hdr_size + first_datasize);
231 first= bf_append (first, cut_second);
232 first->acc_ext_link= second;
234 assert (first_hdr_size + first_datasize == bf_bufsize(first));
236 return first;
239 static ip_ass_t *find_ass_ent ARGS(( ip_port_t *ip_port, u16_t id,
240 ipproto_t proto, ipaddr_t src, ipaddr_t dst ))
242 ip_ass_t *new_ass_ent, *tmp_ass_ent;
243 int i;
244 acc_t *tmp_acc, *curr_acc;
246 new_ass_ent= 0;
248 for (i=0, tmp_ass_ent= ip_ass_table; i<IP_ASS_NR; i++,
249 tmp_ass_ent++)
251 if (!tmp_ass_ent->ia_frags && tmp_ass_ent->ia_first_time)
253 DBLOCK(1,
254 printf("strange ip_ass entry (can be a race condition)\n"));
255 continue;
258 if ((tmp_ass_ent->ia_srcaddr == src) &&
259 (tmp_ass_ent->ia_dstaddr == dst) &&
260 (tmp_ass_ent->ia_proto == proto) &&
261 (tmp_ass_ent->ia_id == id) &&
262 (tmp_ass_ent->ia_port == ip_port))
264 return tmp_ass_ent;
266 if (!new_ass_ent || tmp_ass_ent->ia_first_time <
267 new_ass_ent->ia_first_time)
269 new_ass_ent= tmp_ass_ent;
273 if (new_ass_ent->ia_frags)
275 DBLOCK(2, printf("old frags id= %u, proto= %u, src= ",
276 ntohs(new_ass_ent->ia_id),
277 new_ass_ent->ia_proto);
278 writeIpAddr(new_ass_ent->ia_srcaddr); printf(" dst= ");
279 writeIpAddr(new_ass_ent->ia_dstaddr); printf(": ");
280 ip_print_frags(new_ass_ent->ia_frags); printf("\n"));
281 curr_acc= new_ass_ent->ia_frags->acc_ext_link;
282 while (curr_acc)
284 tmp_acc= curr_acc->acc_ext_link;
285 bf_afree(curr_acc);
286 curr_acc= tmp_acc;
288 curr_acc= new_ass_ent->ia_frags;
289 new_ass_ent->ia_frags= 0;
290 if (broadcast_dst(ip_port, new_ass_ent->ia_dstaddr))
292 DBLOCK(1, printf(
293 "ip_read'find_ass_ent: reassembly timeout for broadcast packet\n"));
294 bf_afree(curr_acc); curr_acc= NULL;
296 else
298 icmp_snd_time_exceeded(ip_port->ip_port,
299 curr_acc, ICMP_FRAG_REASSEM);
302 new_ass_ent->ia_min_ttl= IP_MAX_TTL;
303 new_ass_ent->ia_port= ip_port;
304 new_ass_ent->ia_first_time= get_time();
305 new_ass_ent->ia_srcaddr= src;
306 new_ass_ent->ia_dstaddr= dst;
307 new_ass_ent->ia_proto= proto;
308 new_ass_ent->ia_id= id;
310 return new_ass_ent;
313 static int ip_frag_chk(pack)
314 acc_t *pack;
316 ip_hdr_t *ip_hdr;
317 int hdr_len;
319 if (pack->acc_length < sizeof(ip_hdr_t))
321 DBLOCK(1, printf("wrong length\n"));
322 return FALSE;
325 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
327 hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
328 if (pack->acc_length < hdr_len)
330 DBLOCK(1, printf("wrong length\n"));
332 return FALSE;
335 if (((ip_hdr->ih_vers_ihl >> 4) & IH_VERSION_MASK) !=
336 IP_VERSION)
338 DBLOCK(1, printf("wrong version (ih_vers_ihl=0x%x)\n",
339 ip_hdr->ih_vers_ihl));
340 return FALSE;
342 if (ntohs(ip_hdr->ih_length) != bf_bufsize(pack))
344 DBLOCK(1, printf("wrong size\n"));
346 return FALSE;
348 if ((u16_t)~oneC_sum(0, (u16_t *)ip_hdr, hdr_len))
350 DBLOCK(1, printf("packet with wrong checksum (= %x)\n",
351 (u16_t)~oneC_sum(0, (u16_t *)ip_hdr, hdr_len)));
352 return FALSE;
354 if (hdr_len>IP_MIN_HDR_SIZE && ip_chk_hdropt((u8_t *)
355 (ptr2acc_data(pack) + IP_MIN_HDR_SIZE),
356 hdr_len-IP_MIN_HDR_SIZE))
358 DBLOCK(1, printf("packet with wrong options\n"));
359 return FALSE;
361 return TRUE;
364 int ip_sel_read (ip_fd_t *ip_fd)
366 acc_t *pack;
368 if (!(ip_fd->if_flags & IFF_OPTSET))
369 return 1; /* Read will not block */
371 if (ip_fd->if_rdbuf_head)
373 if (get_time() <= ip_fd->if_exp_time)
374 return 1;
376 while (ip_fd->if_rdbuf_head)
378 pack= ip_fd->if_rdbuf_head;
379 ip_fd->if_rdbuf_head= pack->acc_ext_link;
380 bf_afree(pack);
383 return 0;
386 void ip_packet2user (ip_fd, pack, exp_time, data_len)
387 ip_fd_t *ip_fd;
388 acc_t *pack;
389 time_t exp_time;
390 size_t data_len;
392 acc_t *tmp_pack;
393 ip_hdr_t *ip_hdr;
394 int result, ip_hdr_len;
395 size_t transf_size;
397 assert (ip_fd->if_flags & IFF_INUSE);
398 if (!(ip_fd->if_flags & IFF_READ_IP))
400 if (pack->acc_linkC != 1)
402 tmp_pack= bf_dupacc(pack);
403 bf_afree(pack);
404 pack= tmp_pack;
405 tmp_pack= NULL;
407 pack->acc_ext_link= NULL;
408 if (ip_fd->if_rdbuf_head == NULL)
410 ip_fd->if_rdbuf_head= pack;
411 ip_fd->if_exp_time= exp_time;
413 else
414 ip_fd->if_rdbuf_tail->acc_ext_link= pack;
415 ip_fd->if_rdbuf_tail= pack;
417 if (ip_fd->if_flags & IFF_SEL_READ)
419 ip_fd->if_flags &= ~IFF_SEL_READ;
420 if (ip_fd->if_select_res)
421 ip_fd->if_select_res(ip_fd->if_srfd,
422 SR_SELECT_READ);
423 else
424 printf("ip_packet2user: no select_res\n");
426 return;
429 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
430 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
432 if (ip_fd->if_ipopt.nwio_flags & NWIO_RWDATONLY)
434 ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
436 assert (data_len > ip_hdr_len);
437 data_len -= ip_hdr_len;
438 pack= bf_delhead(pack, ip_hdr_len);
441 if (data_len > ip_fd->if_rd_count)
443 tmp_pack= bf_cut (pack, 0, ip_fd->if_rd_count);
444 bf_afree(pack);
445 pack= tmp_pack;
446 transf_size= ip_fd->if_rd_count;
448 else
449 transf_size= data_len;
451 if (ip_fd->if_put_pkt)
453 (*ip_fd->if_put_pkt)(ip_fd->if_srfd, pack, transf_size);
454 return;
457 result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
458 (size_t)0, pack, FALSE);
459 if (result >= 0)
461 if (data_len > transf_size)
462 result= EPACKSIZE;
463 else
464 result= transf_size;
467 ip_fd->if_flags &= ~IFF_READ_IP;
468 result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd, result,
469 (acc_t *)0, FALSE);
470 assert (result >= 0);
473 void ip_port_arrive (ip_port, pack, ip_hdr)
474 ip_port_t *ip_port;
475 acc_t *pack;
476 ip_hdr_t *ip_hdr;
478 ip_fd_t *ip_fd, *first_fd, *share_fd;
479 unsigned long ip_pack_stat;
480 unsigned size;
481 int i;
482 int hash, proto;
483 time_t exp_time;
485 assert (pack->acc_linkC>0);
486 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
488 if (ntohs(ip_hdr->ih_flags_fragoff) & (IH_FRAGOFF_MASK|IH_MORE_FRAGS))
490 pack= reassemble (ip_port, pack, ip_hdr);
491 if (!pack)
492 return;
493 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
494 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
495 assert (!(ntohs(ip_hdr->ih_flags_fragoff) &
496 (IH_FRAGOFF_MASK|IH_MORE_FRAGS)));
498 size= ntohs(ip_hdr->ih_length);
499 if (size > bf_bufsize(pack))
501 /* Should discard packet */
502 assert(0);
503 bf_afree(pack); pack= NULL;
504 return;
507 exp_time= get_time() + (ip_hdr->ih_ttl+1) * HZ;
509 if (ip_hdr->ih_dst == ip_port->ip_ipaddr)
510 ip_pack_stat= NWIO_EN_LOC;
511 else
512 ip_pack_stat= NWIO_EN_BROAD;
514 proto= ip_hdr->ih_proto;
515 hash= proto & (IP_PROTO_HASH_NR-1);
517 first_fd= NULL;
518 for (i= 0; i<2; i++)
520 share_fd= NULL;
522 ip_fd= (i == 0) ? ip_port->ip_proto_any :
523 ip_port->ip_proto[hash];
524 for (; ip_fd; ip_fd= ip_fd->if_proto_next)
526 if (i && ip_fd->if_ipopt.nwio_proto != proto)
527 continue;
528 if (!(ip_fd->if_ipopt.nwio_flags & ip_pack_stat))
529 continue;
530 if ((ip_fd->if_ipopt.nwio_flags & NWIO_REMSPEC) &&
531 ip_hdr->ih_src != ip_fd->if_ipopt.nwio_rem)
533 continue;
535 if ((ip_fd->if_ipopt.nwio_flags & NWIO_ACC_MASK) ==
536 NWIO_SHARED)
538 if (!share_fd)
540 share_fd= ip_fd;
541 continue;
543 if (!ip_fd->if_rdbuf_head)
544 share_fd= ip_fd;
545 continue;
547 if (!first_fd)
549 first_fd= ip_fd;
550 continue;
552 pack->acc_linkC++;
553 ip_packet2user(ip_fd, pack, exp_time, size);
556 if (share_fd)
558 pack->acc_linkC++;
559 ip_packet2user(share_fd, pack, exp_time, size);
562 if (first_fd)
564 if (first_fd->if_put_pkt &&
565 (first_fd->if_flags & IFF_READ_IP) &&
566 !(first_fd->if_ipopt.nwio_flags & NWIO_RWDATONLY))
568 (*first_fd->if_put_pkt)(first_fd->if_srfd, pack,
569 size);
571 else
572 ip_packet2user(first_fd, pack, exp_time, size);
574 else
576 if (ip_pack_stat == NWIO_EN_LOC)
578 DBLOCK(0x01,
579 printf("ip_port_arrive: dropping packet for proto %d\n",
580 proto));
582 else
584 DBLOCK(0x20, printf("dropping packet for proto %d\n",
585 proto));
587 bf_afree(pack);
591 void ip_arrived(ip_port, pack)
592 ip_port_t *ip_port;
593 acc_t *pack;
595 ip_hdr_t *ip_hdr;
596 ipaddr_t dest;
597 int ip_frag_len, ip_hdr_len, highbyte;
598 size_t pack_size;
599 acc_t *tmp_pack, *hdr_pack;
600 ev_arg_t ev_arg;
602 pack_size= bf_bufsize(pack);
604 if (pack_size < IP_MIN_HDR_SIZE)
606 DBLOCK(1, printf("wrong acc_length\n"));
607 bf_afree(pack);
608 return;
610 pack= bf_align(pack, IP_MIN_HDR_SIZE, 4);
611 pack= bf_packIffLess(pack, IP_MIN_HDR_SIZE);
612 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
614 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
615 ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
616 if (ip_hdr_len>IP_MIN_HDR_SIZE)
618 pack= bf_packIffLess(pack, ip_hdr_len);
619 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
621 ip_frag_len= ntohs(ip_hdr->ih_length);
622 if (ip_frag_len != pack_size)
624 if (pack_size < ip_frag_len)
626 /* Sent ICMP? */
627 DBLOCK(1, printf("wrong acc_length\n"));
628 bf_afree(pack);
629 return;
631 assert(ip_frag_len<pack_size);
632 tmp_pack= pack;
633 pack= bf_cut(tmp_pack, 0, ip_frag_len);
634 bf_afree(tmp_pack);
635 pack_size= ip_frag_len;
638 if (!ip_frag_chk(pack))
640 DBLOCK(1, printf("fragment not allright\n"));
641 bf_afree(pack);
642 return;
645 /* Decide about local delivery or routing. Local delivery can happen
646 * when the destination is the local ip address, or one of the
647 * broadcast addresses and the packet happens to be delivered
648 * point-to-point.
651 dest= ip_hdr->ih_dst;
653 if (dest == ip_port->ip_ipaddr)
655 ip_port_arrive (ip_port, pack, ip_hdr);
656 return;
658 if (broadcast_dst(ip_port, dest))
660 ip_port_arrive (ip_port, pack, ip_hdr);
661 return;
664 if (pack->acc_linkC != 1 || pack->acc_buffer->buf_linkC != 1)
666 /* Get a private copy of the IP header */
667 hdr_pack= bf_memreq(ip_hdr_len);
668 memcpy(ptr2acc_data(hdr_pack), ip_hdr, ip_hdr_len);
669 pack= bf_delhead(pack, ip_hdr_len);
670 hdr_pack->acc_next= pack;
671 pack= hdr_pack; hdr_pack= NULL;
672 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
674 assert(pack->acc_linkC == 1);
675 assert(pack->acc_buffer->buf_linkC == 1);
677 /* Try to decrement the ttl field with one. */
678 if (ip_hdr->ih_ttl < 2)
680 icmp_snd_time_exceeded(ip_port->ip_port, pack,
681 ICMP_TTL_EXC);
682 return;
684 ip_hdr->ih_ttl--;
685 ip_hdr_chksum(ip_hdr, ip_hdr_len);
687 /* Avoid routing to bad destinations. */
688 highbyte= ntohl(dest) >> 24;
689 if (highbyte == 0 || highbyte == 127 ||
690 (highbyte == 169 && (((ntohl(dest) >> 16) & 0xff) == 254)) ||
691 highbyte >= 0xe0)
693 /* Bogus destination address */
694 bf_afree(pack);
695 return;
698 /* Further processing from an event handler */
699 if (pack->acc_linkC != 1)
701 tmp_pack= bf_dupacc(pack);
702 bf_afree(pack);
703 pack= tmp_pack;
704 tmp_pack= NULL;
706 pack->acc_ext_link= NULL;
707 if (ip_port->ip_routeq_head)
709 ip_port->ip_routeq_tail->acc_ext_link= pack;
710 ip_port->ip_routeq_tail= pack;
711 return;
714 ip_port->ip_routeq_head= pack;
715 ip_port->ip_routeq_tail= pack;
716 ev_arg.ev_ptr= ip_port;
717 ev_enqueue(&ip_port->ip_routeq_event, route_packets, ev_arg);
720 void ip_arrived_broadcast(ip_port, pack)
721 ip_port_t *ip_port;
722 acc_t *pack;
724 ip_hdr_t *ip_hdr;
725 int ip_frag_len, ip_hdr_len;
726 size_t pack_size;
727 acc_t *tmp_pack;
729 pack_size= bf_bufsize(pack);
731 if (pack_size < IP_MIN_HDR_SIZE)
733 DBLOCK(1, printf("wrong acc_length\n"));
734 bf_afree(pack);
735 return;
737 pack= bf_align(pack, IP_MIN_HDR_SIZE, 4);
738 pack= bf_packIffLess(pack, IP_MIN_HDR_SIZE);
739 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
741 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
743 DIFBLOCK(0x20, (ip_hdr->ih_dst & HTONL(0xf0000000)) == HTONL(0xe0000000),
744 printf("got multicast packet\n"));
746 ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
747 if (ip_hdr_len>IP_MIN_HDR_SIZE)
749 pack= bf_align(pack, IP_MIN_HDR_SIZE, 4);
750 pack= bf_packIffLess(pack, ip_hdr_len);
751 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
753 ip_frag_len= ntohs(ip_hdr->ih_length);
754 if (ip_frag_len<pack_size)
756 tmp_pack= pack;
757 pack= bf_cut(tmp_pack, 0, ip_frag_len);
758 bf_afree(tmp_pack);
761 if (!ip_frag_chk(pack))
763 DBLOCK(1, printf("fragment not allright\n"));
764 bf_afree(pack);
765 return;
768 if (!broadcast_dst(ip_port, ip_hdr->ih_dst))
770 #if 0
771 printf(
772 "ip[%d]: broadcast packet for ip-nonbroadcast addr, src=",
773 ip_port->ip_port);
774 writeIpAddr(ip_hdr->ih_src);
775 printf(" dst=");
776 writeIpAddr(ip_hdr->ih_dst);
777 printf("\n");
778 #endif
779 bf_afree(pack);
780 return;
783 ip_port_arrive (ip_port, pack, ip_hdr);
786 static void route_packets(ev, ev_arg)
787 event_t *ev;
788 ev_arg_t ev_arg;
790 ip_port_t *ip_port;
791 ipaddr_t dest;
792 acc_t *pack;
793 iroute_t *iroute;
794 ip_port_t *next_port;
795 int r, type;
796 ip_hdr_t *ip_hdr;
797 size_t req_mtu;
799 ip_port= ev_arg.ev_ptr;
800 assert(&ip_port->ip_routeq_event == ev);
802 while (pack= ip_port->ip_routeq_head, pack != NULL)
804 ip_port->ip_routeq_head= pack->acc_ext_link;
806 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
807 dest= ip_hdr->ih_dst;
809 iroute= iroute_frag(ip_port->ip_port, dest);
810 if (iroute == NULL || iroute->irt_dist == IRTD_UNREACHABLE)
812 /* Also unreachable */
813 /* Finding out if we send a network unreachable is too
814 * much trouble.
816 if (iroute == NULL)
818 printf("ip[%d]: no route to ",
819 ip_port-ip_port_table);
820 writeIpAddr(dest);
821 printf("\n");
823 icmp_snd_unreachable(ip_port->ip_port, pack,
824 ICMP_HOST_UNRCH);
825 continue;
827 next_port= &ip_port_table[iroute->irt_port];
829 if (ip_hdr->ih_flags_fragoff & HTONS(IH_DONT_FRAG))
831 req_mtu= bf_bufsize(pack);
832 if (req_mtu > next_port->ip_mtu ||
833 (iroute->irt_mtu && req_mtu>iroute->irt_mtu))
835 icmp_snd_mtu(ip_port->ip_port, pack,
836 next_port->ip_mtu);
837 continue;
841 if (next_port != ip_port)
843 if (iroute->irt_gateway != 0)
845 /* Just send the packet to the next gateway */
846 pack->acc_linkC++; /* Extra ref for ICMP */
847 r= next_port->ip_dev_send(next_port,
848 iroute->irt_gateway,
849 pack, IP_LT_NORMAL);
850 if (r == EHOSTUNREACH)
852 printf("ip[%d]: gw ",
853 ip_port-ip_port_table);
854 writeIpAddr(iroute->irt_gateway);
855 printf(" on ip[%d] is down for dest ",
856 next_port-ip_port_table);
857 writeIpAddr(dest);
858 printf("\n");
859 icmp_snd_unreachable(next_port-
860 ip_port_table, pack,
861 ICMP_HOST_UNRCH);
862 pack= NULL;
864 else
866 assert(r == 0);
867 bf_afree(pack); pack= NULL;
869 continue;
871 /* The packet is for the attached network. Special
872 * addresses are the ip address of the interface and
873 * net.0 if no IP_42BSD_BCAST.
875 if (dest == next_port->ip_ipaddr)
877 ip_port_arrive (next_port, pack, ip_hdr);
878 continue;
880 if (dest == iroute->irt_dest)
882 /* Never forward obsolete directed broadcasts */
883 #if IP_42BSD_BCAST && 0
884 type= IP_LT_BROADCAST;
885 #else
886 /* Bogus destination address */
887 DBLOCK(1, printf(
888 "ip[%d]: dropping old-fashioned directed broadcast ",
889 ip_port-ip_port_table);
890 writeIpAddr(dest);
891 printf("\n"););
892 icmp_snd_unreachable(next_port-ip_port_table,
893 pack, ICMP_HOST_UNRCH);
894 continue;
895 #endif
897 else if (dest == (iroute->irt_dest |
898 ~iroute->irt_subnetmask))
900 if (!ip_forward_directed_bcast)
902 /* Do not forward directed broadcasts */
903 DBLOCK(1, printf(
904 "ip[%d]: dropping directed broadcast ",
905 ip_port-ip_port_table);
906 writeIpAddr(dest);
907 printf("\n"););
908 icmp_snd_unreachable(next_port-
909 ip_port_table, pack,
910 ICMP_HOST_UNRCH);
911 continue;
913 else
914 type= IP_LT_BROADCAST;
916 else
917 type= IP_LT_NORMAL;
919 /* Just send the packet to it's destination */
920 pack->acc_linkC++; /* Extra ref for ICMP */
921 r= next_port->ip_dev_send(next_port, dest, pack, type);
922 if (r == EHOSTUNREACH)
924 DBLOCK(1, printf("ip[%d]: next hop ",
925 ip_port-ip_port_table);
926 writeIpAddr(dest);
927 printf(" on ip[%d] is down\n",
928 next_port-ip_port_table););
929 icmp_snd_unreachable(next_port-ip_port_table,
930 pack, ICMP_HOST_UNRCH);
931 pack= NULL;
933 else
935 assert(r == 0 || (printf("r = %d\n", r), 0));
936 bf_afree(pack); pack= NULL;
938 continue;
941 /* Now we know that the packet should be routed over the same
942 * network as it came from. If there is a next hop gateway,
943 * we can send the packet to that gateway and send a redirect
944 * ICMP to the sender if the sender is on the attached
945 * network. If there is no gateway complain.
947 if (iroute->irt_gateway == 0)
949 printf("ip_arrived: packet should not be here, src=");
950 writeIpAddr(ip_hdr->ih_src);
951 printf(" dst=");
952 writeIpAddr(ip_hdr->ih_dst);
953 printf("\n");
954 bf_afree(pack);
955 continue;
957 if (((ip_hdr->ih_src ^ ip_port->ip_ipaddr) &
958 ip_port->ip_subnetmask) == 0)
960 /* Finding out if we can send a network redirect
961 * instead of a host redirect is too much trouble.
963 pack->acc_linkC++;
964 icmp_snd_redirect(ip_port->ip_port, pack,
965 ICMP_REDIRECT_HOST, iroute->irt_gateway);
967 else
969 printf("ip_arrived: packet is wrongly routed, src=");
970 writeIpAddr(ip_hdr->ih_src);
971 printf(" dst=");
972 writeIpAddr(ip_hdr->ih_dst);
973 printf("\n");
974 printf("in port %d, output %d, dest net ",
975 ip_port->ip_port,
976 iroute->irt_port);
977 writeIpAddr(iroute->irt_dest);
978 printf("/");
979 writeIpAddr(iroute->irt_subnetmask);
980 printf(" next hop ");
981 writeIpAddr(iroute->irt_gateway);
982 printf("\n");
983 bf_afree(pack);
984 continue;
986 /* No code for unreachable ICMPs here. The sender should
987 * process the ICMP redirect and figure it out.
989 ip_port->ip_dev_send(ip_port, iroute->irt_gateway, pack,
990 IP_LT_NORMAL);
994 static int broadcast_dst(ip_port, dest)
995 ip_port_t *ip_port;
996 ipaddr_t dest;
998 ipaddr_t my_ipaddr, netmask, classmask;
1000 /* Treat class D (multicast) address as broadcasts. */
1001 if ((dest & HTONL(0xF0000000)) == HTONL(0xE0000000))
1003 return 1;
1006 /* Accept without complaint if netmask not yet configured. */
1007 if (!(ip_port->ip_flags & IPF_NETMASKSET))
1009 return 1;
1011 /* Two possibilities, 0 (iff IP_42BSD_BCAST) and -1 */
1012 if (dest == HTONL((ipaddr_t)-1))
1013 return 1;
1014 #if IP_42BSD_BCAST
1015 if (dest == HTONL((ipaddr_t)0))
1016 return 1;
1017 #endif
1018 netmask= ip_port->ip_subnetmask;
1019 my_ipaddr= ip_port->ip_ipaddr;
1021 if (((my_ipaddr ^ dest) & netmask) != 0)
1023 classmask= ip_port->ip_classfulmask;
1025 /* Not a subnet broadcast, maybe a classful broadcast */
1026 if (((my_ipaddr ^ dest) & classmask) != 0)
1028 return 0;
1030 /* Two possibilities, net.0 (iff IP_42BSD_BCAST) and net.-1 */
1031 if ((dest & ~classmask) == ~classmask)
1033 return 1;
1035 #if IP_42BSD_BCAST
1036 if ((dest & ~classmask) == 0)
1037 return 1;
1038 #endif
1039 return 0;
1042 if (!(ip_port->ip_flags & IPF_SUBNET_BCAST))
1043 return 0; /* No subnet broadcasts on this network */
1045 /* Two possibilities, subnet.0 (iff IP_42BSD_BCAST) and subnet.-1 */
1046 if ((dest & ~netmask) == ~netmask)
1047 return 1;
1048 #if IP_42BSD_BCAST
1049 if ((dest & ~netmask) == 0)
1050 return 1;
1051 #endif
1052 return 0;
1055 void ip_process_loopb(ev, arg)
1056 event_t *ev;
1057 ev_arg_t arg;
1059 ip_port_t *ip_port;
1060 acc_t *pack;
1062 ip_port= arg.ev_ptr;
1063 assert(ev == &ip_port->ip_loopb_event);
1065 while(pack= ip_port->ip_loopb_head, pack != NULL)
1067 ip_port->ip_loopb_head= pack->acc_ext_link;
1068 ip_arrived(ip_port, pack);
1073 * $PchId: ip_read.c,v 1.33 2005/06/28 14:18:50 philip Exp $