phys addr arg of 0 must be possible for pt_writemap too (instead of meaning
[minix.git] / servers / inet / generic / ip_read.c
blobab4bb9add78711b4da43fc268d5a72590e599eba
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"
20 THIS_FILE
22 FORWARD ip_ass_t *find_ass_ent ARGS(( ip_port_t *ip_port, U16_t id,
23 int proto, ipaddr_t src, ipaddr_t dst ));
24 FORWARD acc_t *merge_frags ARGS(( acc_t *first, acc_t *second ));
25 FORWARD int ip_frag_chk ARGS(( acc_t *pack ));
26 FORWARD acc_t *reassemble ARGS(( ip_port_t *ip_port, acc_t *pack,
27 ip_hdr_t *ip_hdr ));
28 FORWARD void route_packets ARGS(( event_t *ev, ev_arg_t ev_arg ));
29 FORWARD int broadcast_dst ARGS(( ip_port_t *ip_port, ipaddr_t dest ));
31 PUBLIC int ip_read (fd, count)
32 int fd;
33 size_t count;
35 ip_fd_t *ip_fd;
36 acc_t *pack;
38 ip_fd= &ip_fd_table[fd];
39 if (!(ip_fd->if_flags & IFF_OPTSET))
41 return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, EBADMODE,
42 (acc_t *)0, FALSE);
45 ip_fd->if_rd_count= count;
47 ip_fd->if_flags |= IFF_READ_IP;
48 if (ip_fd->if_rdbuf_head)
50 if (get_time() <= ip_fd->if_exp_time)
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;
59 while (ip_fd->if_rdbuf_head)
61 pack= ip_fd->if_rdbuf_head;
62 ip_fd->if_rdbuf_head= pack->acc_ext_link;
63 bf_afree(pack);
66 return NW_SUSPEND;
69 PRIVATE acc_t *reassemble (ip_port, pack, pack_hdr)
70 ip_port_t *ip_port;
71 acc_t *pack;
72 ip_hdr_t *pack_hdr;
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;
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);
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;
90 head_acc= ass_ent->ia_frags;
91 ass_ent->ia_frags= NULL;
92 if (head_acc == NULL)
94 ass_ent->ia_frags= pack;
95 return NULL;
98 prev_acc= NULL;
99 curr_acc= NULL;
100 next_acc= head_acc;
102 while(next_acc)
104 tmp_hdr= (ip_hdr_t *)ptr2acc_data(next_acc);
105 tmp_offset= (ntohs(tmp_hdr->ih_flags_fragoff) &
106 IH_FRAGOFF_MASK)*8;
108 if (pack_offset < tmp_offset)
109 break;
111 prev_acc= curr_acc;
112 curr_acc= next_acc;
113 next_acc= next_acc->acc_ext_link;
115 if (curr_acc == NULL)
117 assert(prev_acc == NULL);
118 assert(next_acc != NULL);
120 curr_acc= merge_frags(pack, next_acc);
121 head_acc= curr_acc;
123 else
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;
133 ass_ent->ia_frags= head_acc;
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);
139 if (!(pack_flags_fragoff & (IH_FRAGOFF_MASK|IH_MORE_FRAGS)))
140 /* it's now a complete packet */
142 first_time= ass_ent->ia_first_time;
144 ass_ent->ia_frags= 0;
145 ass_ent->ia_first_time= 0;
147 while (pack->acc_ext_link)
149 tmp_acc= pack->acc_ext_link;
150 pack->acc_ext_link= tmp_acc->acc_ext_link;
151 bf_afree(tmp_acc);
153 if ((ass_ent->ia_min_ttl) * HZ + first_time <
154 get_time())
156 if (broadcast_dst(ip_port, pack_hdr->ih_dst))
158 DBLOCK(1, printf(
159 "ip_read'reassemble: reassembly timeout for broadcast packet\n"););
160 bf_afree(pack); pack= NULL;
161 return NULL;
163 icmp_snd_time_exceeded(ip_port->ip_port, pack,
164 ICMP_FRAG_REASSEM);
166 else
167 return pack;
169 return NULL;
172 PRIVATE acc_t *merge_frags (first, second)
173 acc_t *first, *second;
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;
180 if (!second)
182 first->acc_ext_link= NULL;
183 return first;
186 assert (first->acc_length >= IP_MIN_HDR_SIZE);
187 assert (second->acc_length >= IP_MIN_HDR_SIZE);
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;
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;
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);
205 if (second_offset > first_offset+first_datasize)
207 DBLOCK(1, printf("ip fragments out of order\n"));
208 first->acc_ext_link= second;
209 return first;
212 if (second_offset + second_datasize <= first_offset +
213 first_datasize)
215 /* May cause problems if we try to merge. */
216 bf_afree(first);
217 return second;
220 if (!(second_hdr->ih_flags_fragoff & HTONS(IH_MORE_FRAGS)))
221 first_hdr->ih_flags_fragoff &= ~HTONS(IH_MORE_FRAGS);
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;
231 first_datasize += second_datasize;
232 first_hdr->ih_length= htons(first_hdr_size + first_datasize);
234 first= bf_append (first, cut_second);
235 first->acc_ext_link= second;
237 assert (first_hdr_size + first_datasize == bf_bufsize(first));
239 return first;
242 PRIVATE ip_ass_t *find_ass_ent (ip_port, id, proto, src, dst)
243 ip_port_t *ip_port;
244 u16_t id;
245 ipproto_t proto;
246 ipaddr_t src;
247 ipaddr_t dst;
249 ip_ass_t *new_ass_ent, *tmp_ass_ent;
250 int i;
251 acc_t *tmp_acc, *curr_acc;
253 new_ass_ent= 0;
255 for (i=0, tmp_ass_ent= ip_ass_table; i<IP_ASS_NR; i++,
256 tmp_ass_ent++)
258 if (!tmp_ass_ent->ia_frags && tmp_ass_ent->ia_first_time)
260 DBLOCK(1,
261 printf("strange ip_ass entry (can be a race condition)\n"));
262 continue;
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))
271 return tmp_ass_ent;
273 if (!new_ass_ent || tmp_ass_ent->ia_first_time <
274 new_ass_ent->ia_first_time)
276 new_ass_ent= tmp_ass_ent;
280 if (new_ass_ent->ia_frags)
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)
291 tmp_acc= curr_acc->acc_ext_link;
292 bf_afree(curr_acc);
293 curr_acc= tmp_acc;
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))
299 DBLOCK(1, printf(
300 "ip_read'find_ass_ent: reassembly timeout for broadcast packet\n"));
301 bf_afree(curr_acc); curr_acc= NULL;
303 else
305 icmp_snd_time_exceeded(ip_port->ip_port,
306 curr_acc, ICMP_FRAG_REASSEM);
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;
317 return new_ass_ent;
320 PRIVATE int ip_frag_chk(pack)
321 acc_t *pack;
323 ip_hdr_t *ip_hdr;
324 int hdr_len;
326 if (pack->acc_length < sizeof(ip_hdr_t))
328 DBLOCK(1, printf("wrong length\n"));
329 return FALSE;
332 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
334 hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
335 if (pack->acc_length < hdr_len)
337 DBLOCK(1, printf("wrong length\n"));
339 return FALSE;
342 if (((ip_hdr->ih_vers_ihl >> 4) & IH_VERSION_MASK) !=
343 IP_VERSION)
345 DBLOCK(1, printf("wrong version (ih_vers_ihl=0x%x)\n",
346 ip_hdr->ih_vers_ihl));
347 return FALSE;
349 if (ntohs(ip_hdr->ih_length) != bf_bufsize(pack))
351 DBLOCK(1, printf("wrong size\n"));
353 return FALSE;
355 if ((u16_t)~oneC_sum(0, (u16_t *)ip_hdr, hdr_len))
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;
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))
365 DBLOCK(1, printf("packet with wrong options\n"));
366 return FALSE;
368 return TRUE;
371 PUBLIC void ip_packet2user (ip_fd, pack, exp_time, data_len)
372 ip_fd_t *ip_fd;
373 acc_t *pack;
374 time_t exp_time;
375 size_t data_len;
377 acc_t *tmp_pack;
378 ip_hdr_t *ip_hdr;
379 int result, ip_hdr_len;
380 size_t transf_size;
382 assert (ip_fd->if_flags & IFF_INUSE);
383 if (!(ip_fd->if_flags & IFF_READ_IP))
385 if (pack->acc_linkC != 1)
387 tmp_pack= bf_dupacc(pack);
388 bf_afree(pack);
389 pack= tmp_pack;
390 tmp_pack= NULL;
392 pack->acc_ext_link= NULL;
393 if (ip_fd->if_rdbuf_head == NULL)
395 ip_fd->if_rdbuf_head= pack;
396 ip_fd->if_exp_time= exp_time;
398 else
399 ip_fd->if_rdbuf_tail->acc_ext_link= pack;
400 ip_fd->if_rdbuf_tail= pack;
401 return;
404 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
405 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
407 if (ip_fd->if_ipopt.nwio_flags & NWIO_RWDATONLY)
409 ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) * 4;
411 assert (data_len > ip_hdr_len);
412 data_len -= ip_hdr_len;
413 pack= bf_delhead(pack, ip_hdr_len);
416 if (data_len > ip_fd->if_rd_count)
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;
423 else
424 transf_size= data_len;
426 if (ip_fd->if_put_pkt)
428 (*ip_fd->if_put_pkt)(ip_fd->if_srfd, pack, transf_size);
429 return;
432 result= (*ip_fd->if_put_userdata)(ip_fd->if_srfd,
433 (size_t)0, pack, FALSE);
434 if (result >= 0)
436 if (data_len > transf_size)
437 result= EPACKSIZE;
438 else
439 result= transf_size;
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);
448 PUBLIC void ip_port_arrive (ip_port, pack, ip_hdr)
449 ip_port_t *ip_port;
450 acc_t *pack;
451 ip_hdr_t *ip_hdr;
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;
460 assert (pack->acc_linkC>0);
461 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
463 if (ntohs(ip_hdr->ih_flags_fragoff) & (IH_FRAGOFF_MASK|IH_MORE_FRAGS))
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)));
473 size= ntohs(ip_hdr->ih_length);
474 if (size > bf_bufsize(pack))
476 /* Should discard packet */
477 assert(0);
478 bf_afree(pack); pack= NULL;
479 return;
482 exp_time= get_time() + (ip_hdr->ih_ttl+1) * HZ;
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;
489 proto= ip_hdr->ih_proto;
490 hash= proto & (IP_PROTO_HASH_NR-1);
492 first_fd= NULL;
493 for (i= 0; i<2; i++)
495 share_fd= NULL;
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)
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)
508 continue;
510 if ((ip_fd->if_ipopt.nwio_flags & NWIO_ACC_MASK) ==
511 NWIO_SHARED)
513 if (!share_fd)
515 share_fd= ip_fd;
516 continue;
518 if (!ip_fd->if_rdbuf_head)
519 share_fd= ip_fd;
520 continue;
522 if (!first_fd)
524 first_fd= ip_fd;
525 continue;
527 pack->acc_linkC++;
528 ip_packet2user(ip_fd, pack, exp_time, size);
531 if (share_fd)
533 pack->acc_linkC++;
534 ip_packet2user(share_fd, pack, exp_time, size);
537 if (first_fd)
539 if (first_fd->if_put_pkt &&
540 (first_fd->if_flags & IFF_READ_IP) &&
541 !(first_fd->if_ipopt.nwio_flags & NWIO_RWDATONLY))
543 (*first_fd->if_put_pkt)(first_fd->if_srfd, pack,
544 size);
546 else
547 ip_packet2user(first_fd, pack, exp_time, size);
549 else
551 if (ip_pack_stat == NWIO_EN_LOC)
553 DBLOCK(0x01,
554 printf("ip_port_arrive: dropping packet for proto %d\n",
555 proto));
557 else
559 DBLOCK(0x20, printf("dropping packet for proto %d\n",
560 proto));
562 bf_afree(pack);
566 PUBLIC void ip_arrived(ip_port, pack)
567 ip_port_t *ip_port;
568 acc_t *pack;
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;
577 pack_size= bf_bufsize(pack);
579 if (pack_size < IP_MIN_HDR_SIZE)
581 DBLOCK(1, printf("wrong acc_length\n"));
582 bf_afree(pack);
583 return;
585 pack= bf_align(pack, IP_MIN_HDR_SIZE, 4);
586 pack= bf_packIffLess(pack, IP_MIN_HDR_SIZE);
587 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
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)
593 pack= bf_packIffLess(pack, ip_hdr_len);
594 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
596 ip_frag_len= ntohs(ip_hdr->ih_length);
597 if (ip_frag_len != pack_size)
599 if (pack_size < ip_frag_len)
601 /* Sent ICMP? */
602 DBLOCK(1, printf("wrong acc_length\n"));
603 bf_afree(pack);
604 return;
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;
613 if (!ip_frag_chk(pack))
615 DBLOCK(1, printf("fragment not allright\n"));
616 bf_afree(pack);
617 return;
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.
626 dest= ip_hdr->ih_dst;
628 if (dest == ip_port->ip_ipaddr)
630 ip_port_arrive (ip_port, pack, ip_hdr);
631 return;
633 if (broadcast_dst(ip_port, dest))
635 ip_port_arrive (ip_port, pack, ip_hdr);
636 return;
639 if (pack->acc_linkC != 1 || pack->acc_buffer->buf_linkC != 1)
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);
649 assert(pack->acc_linkC == 1);
650 assert(pack->acc_buffer->buf_linkC == 1);
652 /* Try to decrement the ttl field with one. */
653 if (ip_hdr->ih_ttl < 2)
655 icmp_snd_time_exceeded(ip_port->ip_port, pack,
656 ICMP_TTL_EXC);
657 return;
659 ip_hdr->ih_ttl--;
660 ip_hdr_chksum(ip_hdr, ip_hdr_len);
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)
668 /* Bogus destination address */
669 bf_afree(pack);
670 return;
673 /* Further processing from an event handler */
674 if (pack->acc_linkC != 1)
676 tmp_pack= bf_dupacc(pack);
677 bf_afree(pack);
678 pack= tmp_pack;
679 tmp_pack= NULL;
681 pack->acc_ext_link= NULL;
682 if (ip_port->ip_routeq_head)
684 ip_port->ip_routeq_tail->acc_ext_link= pack;
685 ip_port->ip_routeq_tail= pack;
686 return;
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);
695 PUBLIC void ip_arrived_broadcast(ip_port, pack)
696 ip_port_t *ip_port;
697 acc_t *pack;
699 ip_hdr_t *ip_hdr;
700 int ip_frag_len, ip_hdr_len;
701 size_t pack_size;
702 acc_t *tmp_pack;
704 pack_size= bf_bufsize(pack);
706 if (pack_size < IP_MIN_HDR_SIZE)
708 DBLOCK(1, printf("wrong acc_length\n"));
709 bf_afree(pack);
710 return;
712 pack= bf_align(pack, IP_MIN_HDR_SIZE, 4);
713 pack= bf_packIffLess(pack, IP_MIN_HDR_SIZE);
714 assert (pack->acc_length >= IP_MIN_HDR_SIZE);
716 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
718 DIFBLOCK(0x20, (ip_hdr->ih_dst & HTONL(0xf0000000)) == HTONL(0xe0000000),
719 printf("got multicast packet\n"));
721 ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
722 if (ip_hdr_len>IP_MIN_HDR_SIZE)
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);
728 ip_frag_len= ntohs(ip_hdr->ih_length);
729 if (ip_frag_len<pack_size)
731 tmp_pack= pack;
732 pack= bf_cut(tmp_pack, 0, ip_frag_len);
733 bf_afree(tmp_pack);
736 if (!ip_frag_chk(pack))
738 DBLOCK(1, printf("fragment not allright\n"));
739 bf_afree(pack);
740 return;
743 if (!broadcast_dst(ip_port, ip_hdr->ih_dst))
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;
758 ip_port_arrive (ip_port, pack, ip_hdr);
761 PRIVATE void route_packets(ev, ev_arg)
762 event_t *ev;
763 ev_arg_t ev_arg;
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;
774 ip_port= ev_arg.ev_ptr;
775 assert(&ip_port->ip_routeq_event == ev);
777 while (pack= ip_port->ip_routeq_head, pack != NULL)
779 ip_port->ip_routeq_head= pack->acc_ext_link;
781 ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
782 dest= ip_hdr->ih_dst;
784 iroute= iroute_frag(ip_port->ip_port, dest);
785 if (iroute == NULL || iroute->irt_dist == IRTD_UNREACHABLE)
787 /* Also unreachable */
788 /* Finding out if we send a network unreachable is too
789 * much trouble.
791 if (iroute == NULL)
793 printf("ip[%d]: no route to ",
794 ip_port-ip_port_table);
795 writeIpAddr(dest);
796 printf("\n");
798 icmp_snd_unreachable(ip_port->ip_port, pack,
799 ICMP_HOST_UNRCH);
800 continue;
802 next_port= &ip_port_table[iroute->irt_port];
804 if (ip_hdr->ih_flags_fragoff & HTONS(IH_DONT_FRAG))
806 req_mtu= bf_bufsize(pack);
807 if (req_mtu > next_port->ip_mtu ||
808 (iroute->irt_mtu && req_mtu>iroute->irt_mtu))
810 icmp_snd_mtu(ip_port->ip_port, pack,
811 next_port->ip_mtu);
812 continue;
816 if (next_port != ip_port)
818 if (iroute->irt_gateway != 0)
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)
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;
839 else
841 assert(r == 0);
842 bf_afree(pack); pack= NULL;
844 continue;
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.
850 if (dest == next_port->ip_ipaddr)
852 ip_port_arrive (next_port, pack, ip_hdr);
853 continue;
855 if (dest == iroute->irt_dest)
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
872 else if (dest == (iroute->irt_dest |
873 ~iroute->irt_subnetmask))
875 if (!ip_forward_directed_bcast)
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;
888 else
889 type= IP_LT_BROADCAST;
891 else
892 type= IP_LT_NORMAL;
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)
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;
908 else
910 assert(r == 0 || (printf("r = %d\n", r), 0));
911 bf_afree(pack); pack= NULL;
913 continue;
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.
922 if (iroute->irt_gateway == 0)
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;
932 if (((ip_hdr->ih_src ^ ip_port->ip_ipaddr) &
933 ip_port->ip_subnetmask) == 0)
935 /* Finding out if we can send a network redirect
936 * instead of a host redirect is too much trouble.
938 pack->acc_linkC++;
939 icmp_snd_redirect(ip_port->ip_port, pack,
940 ICMP_REDIRECT_HOST, iroute->irt_gateway);
942 else
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;
961 /* No code for unreachable ICMPs here. The sender should
962 * process the ICMP redirect and figure it out.
964 ip_port->ip_dev_send(ip_port, iroute->irt_gateway, pack,
965 IP_LT_NORMAL);
969 PRIVATE int broadcast_dst(ip_port, dest)
970 ip_port_t *ip_port;
971 ipaddr_t dest;
973 ipaddr_t my_ipaddr, netmask, classmask;
975 /* Treat class D (multicast) address as broadcasts. */
976 if ((dest & HTONL(0xF0000000)) == HTONL(0xE0000000))
978 return 1;
981 /* Accept without complaint if netmask not yet configured. */
982 if (!(ip_port->ip_flags & IPF_NETMASKSET))
984 return 1;
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;
996 if (((my_ipaddr ^ dest) & netmask) != 0)
998 classmask= ip_port->ip_classfulmask;
1000 /* Not a subnet broadcast, maybe a classful broadcast */
1001 if (((my_ipaddr ^ dest) & classmask) != 0)
1003 return 0;
1005 /* Two possibilities, net.0 (iff IP_42BSD_BCAST) and net.-1 */
1006 if ((dest & ~classmask) == ~classmask)
1008 return 1;
1010 #if IP_42BSD_BCAST
1011 if ((dest & ~classmask) == 0)
1012 return 1;
1013 #endif
1014 return 0;
1017 if (!(ip_port->ip_flags & IPF_SUBNET_BCAST))
1018 return 0; /* No subnet broadcasts on this network */
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;
1030 void ip_process_loopb(ev, arg)
1031 event_t *ev;
1032 ev_arg_t arg;
1034 ip_port_t *ip_port;
1035 acc_t *pack;
1037 ip_port= arg.ev_ptr;
1038 assert(ev == &ip_port->ip_loopb_event);
1040 while(pack= ip_port->ip_loopb_head, pack != NULL)
1042 ip_port->ip_loopb_head= pack->acc_ext_link;
1043 ip_arrived(ip_port, pack);
1048 * $PchId: ip_read.c,v 1.33 2005/06/28 14:18:50 philip Exp $