4 Copyright 1995 Philip Homburg
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
,
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
)
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
,
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
,
55 assert(!(ip_fd
->if_flags
& IFF_READ_IP
));
58 while (ip_fd
->if_rdbuf_head
)
60 pack
= ip_fd
->if_rdbuf_head
;
61 ip_fd
->if_rdbuf_head
= pack
->acc_ext_link
;
68 static acc_t
*reassemble (ip_port
, pack
, pack_hdr
)
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
;
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
;
91 ass_ent
->ia_frags
= pack
;
101 tmp_hdr
= (ip_hdr_t
*)ptr2acc_data(next_acc
);
102 tmp_offset
= (ntohs(tmp_hdr
->ih_flags_fragoff
) &
105 if (pack_offset
< tmp_offset
)
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
);
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
;
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
;
150 if ((ass_ent
->ia_min_ttl
) * HZ
+ first_time
<
153 if (broadcast_dst(ip_port
, pack_hdr
->ih_dst
))
156 "ip_read'reassemble: reassembly timeout for broadcast packet\n"););
157 bf_afree(pack
); pack
= NULL
;
160 icmp_snd_time_exceeded(ip_port
->ip_port
, pack
,
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
;
179 first
->acc_ext_link
= NULL
;
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
;
209 if (second_offset
+ second_datasize
<= first_offset
+
212 /* May cause problems if we try to merge. */
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
+
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
;
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
));
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
;
244 acc_t
*tmp_acc
, *curr_acc
;
248 for (i
=0, tmp_ass_ent
= ip_ass_table
; i
<IP_ASS_NR
; i
++,
251 if (!tmp_ass_ent
->ia_frags
&& tmp_ass_ent
->ia_first_time
)
254 printf("strange ip_ass entry (can be a race condition)\n"));
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
))
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
;
284 tmp_acc
= curr_acc
->acc_ext_link
;
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
))
293 "ip_read'find_ass_ent: reassembly timeout for broadcast packet\n"));
294 bf_afree(curr_acc
); curr_acc
= NULL
;
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
;
313 static int ip_frag_chk(pack
)
319 if (pack
->acc_length
< sizeof(ip_hdr_t
))
321 DBLOCK(1, printf("wrong length\n"));
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"));
335 if (((ip_hdr
->ih_vers_ihl
>> 4) & IH_VERSION_MASK
) !=
338 DBLOCK(1, printf("wrong version (ih_vers_ihl=0x%x)\n",
339 ip_hdr
->ih_vers_ihl
));
342 if (ntohs(ip_hdr
->ih_length
) != bf_bufsize(pack
))
344 DBLOCK(1, printf("wrong size\n"));
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
)));
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"));
364 int ip_sel_read (ip_fd_t
*ip_fd
)
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
)
376 while (ip_fd
->if_rdbuf_head
)
378 pack
= ip_fd
->if_rdbuf_head
;
379 ip_fd
->if_rdbuf_head
= pack
->acc_ext_link
;
386 void ip_packet2user (ip_fd
, pack
, exp_time
, data_len
)
394 int result
, ip_hdr_len
;
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
);
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
;
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
,
424 printf("ip_packet2user: no select_res\n");
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
);
446 transf_size
= ip_fd
->if_rd_count
;
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
);
457 result
= (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
,
458 (size_t)0, pack
, FALSE
);
461 if (data_len
> transf_size
)
467 ip_fd
->if_flags
&= ~IFF_READ_IP
;
468 result
= (*ip_fd
->if_put_userdata
)(ip_fd
->if_srfd
, result
,
470 assert (result
>= 0);
473 void ip_port_arrive (ip_port
, pack
, ip_hdr
)
478 ip_fd_t
*ip_fd
, *first_fd
, *share_fd
;
479 unsigned long ip_pack_stat
;
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
);
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 */
503 bf_afree(pack
); pack
= NULL
;
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
;
512 ip_pack_stat
= NWIO_EN_BROAD
;
514 proto
= ip_hdr
->ih_proto
;
515 hash
= proto
& (IP_PROTO_HASH_NR
-1);
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
)
528 if (!(ip_fd
->if_ipopt
.nwio_flags
& ip_pack_stat
))
530 if ((ip_fd
->if_ipopt
.nwio_flags
& NWIO_REMSPEC
) &&
531 ip_hdr
->ih_src
!= ip_fd
->if_ipopt
.nwio_rem
)
535 if ((ip_fd
->if_ipopt
.nwio_flags
& NWIO_ACC_MASK
) ==
543 if (!ip_fd
->if_rdbuf_head
)
553 ip_packet2user(ip_fd
, pack
, exp_time
, size
);
559 ip_packet2user(share_fd
, pack
, exp_time
, size
);
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
,
572 ip_packet2user(first_fd
, pack
, exp_time
, size
);
576 if (ip_pack_stat
== NWIO_EN_LOC
)
579 printf("ip_port_arrive: dropping packet for proto %d\n",
584 DBLOCK(0x20, printf("dropping packet for proto %d\n",
591 void ip_arrived(ip_port
, pack
)
597 int ip_frag_len
, ip_hdr_len
, highbyte
;
599 acc_t
*tmp_pack
, *hdr_pack
;
602 pack_size
= bf_bufsize(pack
);
604 if (pack_size
< IP_MIN_HDR_SIZE
)
606 DBLOCK(1, printf("wrong acc_length\n"));
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
)
627 DBLOCK(1, printf("wrong acc_length\n"));
631 assert(ip_frag_len
<pack_size
);
633 pack
= bf_cut(tmp_pack
, 0, ip_frag_len
);
635 pack_size
= ip_frag_len
;
638 if (!ip_frag_chk(pack
))
640 DBLOCK(1, printf("fragment not allright\n"));
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
651 dest
= ip_hdr
->ih_dst
;
653 if (dest
== ip_port
->ip_ipaddr
)
655 ip_port_arrive (ip_port
, pack
, ip_hdr
);
658 if (broadcast_dst(ip_port
, dest
))
660 ip_port_arrive (ip_port
, pack
, ip_hdr
);
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
,
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)) ||
693 /* Bogus destination address */
698 /* Further processing from an event handler */
699 if (pack
->acc_linkC
!= 1)
701 tmp_pack
= bf_dupacc(pack
);
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
;
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
)
725 int ip_frag_len
, ip_hdr_len
;
729 pack_size
= bf_bufsize(pack
);
731 if (pack_size
< IP_MIN_HDR_SIZE
)
733 DBLOCK(1, printf("wrong acc_length\n"));
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
)
757 pack
= bf_cut(tmp_pack
, 0, ip_frag_len
);
761 if (!ip_frag_chk(pack
))
763 DBLOCK(1, printf("fragment not allright\n"));
768 if (!broadcast_dst(ip_port
, ip_hdr
->ih_dst
))
772 "ip[%d]: broadcast packet for ip-nonbroadcast addr, src=",
774 writeIpAddr(ip_hdr
->ih_src
);
776 writeIpAddr(ip_hdr
->ih_dst
);
783 ip_port_arrive (ip_port
, pack
, ip_hdr
);
786 static void route_packets(ev
, ev_arg
)
794 ip_port_t
*next_port
;
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
818 printf("ip[%d]: no route to ",
819 ip_port
-ip_port_table
);
823 icmp_snd_unreachable(ip_port
->ip_port
, pack
,
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
,
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
,
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
);
859 icmp_snd_unreachable(next_port
-
867 bf_afree(pack
); pack
= NULL
;
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
);
880 if (dest
== iroute
->irt_dest
)
882 /* Never forward obsolete directed broadcasts */
883 #if IP_42BSD_BCAST && 0
884 type
= IP_LT_BROADCAST
;
886 /* Bogus destination address */
888 "ip[%d]: dropping old-fashioned directed broadcast ",
889 ip_port
-ip_port_table
);
892 icmp_snd_unreachable(next_port
-ip_port_table
,
893 pack
, ICMP_HOST_UNRCH
);
897 else if (dest
== (iroute
->irt_dest
|
898 ~iroute
->irt_subnetmask
))
900 if (!ip_forward_directed_bcast
)
902 /* Do not forward directed broadcasts */
904 "ip[%d]: dropping directed broadcast ",
905 ip_port
-ip_port_table
);
908 icmp_snd_unreachable(next_port
-
914 type
= IP_LT_BROADCAST
;
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
);
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
);
935 assert(r
== 0 || (printf("r = %d\n", r
), 0));
936 bf_afree(pack
); pack
= NULL
;
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
);
952 writeIpAddr(ip_hdr
->ih_dst
);
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.
964 icmp_snd_redirect(ip_port
->ip_port
, pack
,
965 ICMP_REDIRECT_HOST
, iroute
->irt_gateway
);
969 printf("ip_arrived: packet is wrongly routed, src=");
970 writeIpAddr(ip_hdr
->ih_src
);
972 writeIpAddr(ip_hdr
->ih_dst
);
974 printf("in port %d, output %d, dest net ",
977 writeIpAddr(iroute
->irt_dest
);
979 writeIpAddr(iroute
->irt_subnetmask
);
980 printf(" next hop ");
981 writeIpAddr(iroute
->irt_gateway
);
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
,
994 static int broadcast_dst(ip_port
, dest
)
998 ipaddr_t my_ipaddr
, netmask
, classmask
;
1000 /* Treat class D (multicast) address as broadcasts. */
1001 if ((dest
& HTONL(0xF0000000)) == HTONL(0xE0000000))
1006 /* Accept without complaint if netmask not yet configured. */
1007 if (!(ip_port
->ip_flags
& IPF_NETMASKSET
))
1011 /* Two possibilities, 0 (iff IP_42BSD_BCAST) and -1 */
1012 if (dest
== HTONL((ipaddr_t
)-1))
1015 if (dest
== HTONL((ipaddr_t
)0))
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)
1030 /* Two possibilities, net.0 (iff IP_42BSD_BCAST) and net.-1 */
1031 if ((dest
& ~classmask
) == ~classmask
)
1036 if ((dest
& ~classmask
) == 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
)
1049 if ((dest
& ~netmask
) == 0)
1055 void ip_process_loopb(ev
, arg
)
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 $