4 Copyright 1995 Philip Homburg
24 static void error_reply
ARGS(( ip_fd_t
*fd
, int error
));
26 int ip_write (fd
, count
)
34 ip_fd
= &ip_fd_table
[fd
];
35 if (count
> IP_MAX_PACKSIZE
)
37 error_reply (ip_fd
, EPACKSIZE
);
40 pack
= (*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
, (size_t)0,
44 r
= ip_send(fd
, pack
, count
);
45 assert(r
!= NW_WOULDBLOCK
);
48 error_reply (ip_fd
, count
);
50 error_reply (ip_fd
, r
);
54 int ip_send(fd
, data
, data_len
)
61 ip_hdr_t
*ip_hdr
, *tmp_hdr
;
62 ipaddr_t dstaddr
, nexthop
, hostrep_dst
, my_ipaddr
, netmask
;
64 acc_t
*tmp_pack
, *tmp_pack1
;
65 int hdr_len
, hdr_opt_len
, r
;
70 ip_fd
= &ip_fd_table
[fd
];
71 ip_port
= ip_fd
->if_port
;
73 if (!(ip_fd
->if_flags
& IFF_OPTSET
))
79 if (!(ip_fd
->if_port
->ip_flags
& IPF_IPADDRSET
))
81 /* Interface is down. */
86 data_len
= bf_bufsize(data
);
88 if (ip_fd
->if_ipopt
.nwio_flags
& NWIO_RWDATONLY
)
90 tmp_pack
= bf_memreq(IP_MIN_HDR_SIZE
);
91 tmp_pack
->acc_next
= data
;
93 data_len
+= IP_MIN_HDR_SIZE
;
95 if (data_len
<IP_MIN_HDR_SIZE
)
101 data
= bf_packIffLess(data
, IP_MIN_HDR_SIZE
);
102 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
103 if (data
->acc_linkC
!= 1 || data
->acc_buffer
->buf_linkC
!= 1)
105 tmp_pack
= bf_memreq(IP_MIN_HDR_SIZE
);
106 tmp_hdr
= (ip_hdr_t
*)ptr2acc_data(tmp_pack
);
108 tmp_pack
->acc_next
= bf_cut(data
, IP_MIN_HDR_SIZE
,
109 data_len
-IP_MIN_HDR_SIZE
);
113 assert (data
->acc_length
>= IP_MIN_HDR_SIZE
);
116 if (ip_fd
->if_ipopt
.nwio_flags
& NWIO_HDR_O_SPEC
)
118 hdr_opt_len
= ip_fd
->if_ipopt
.nwio_hdropt
.iho_opt_siz
;
121 tmp_pack
= bf_cut(data
, 0, IP_MIN_HDR_SIZE
);
122 tmp_pack1
= bf_cut (data
, IP_MIN_HDR_SIZE
,
123 data_len
-IP_MIN_HDR_SIZE
);
125 data
= bf_packIffLess(tmp_pack
, IP_MIN_HDR_SIZE
);
126 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
127 tmp_pack
= bf_memreq (hdr_opt_len
);
128 memcpy (ptr2acc_data(tmp_pack
), ip_fd
->if_ipopt
.
129 nwio_hdropt
.iho_data
, hdr_opt_len
);
130 data
->acc_next
= tmp_pack
;
131 tmp_pack
->acc_next
= tmp_pack1
;
132 hdr_len
= IP_MIN_HDR_SIZE
+hdr_opt_len
;
135 hdr_len
= IP_MIN_HDR_SIZE
;
136 ip_hdr
->ih_vers_ihl
= hdr_len
/4;
137 ip_hdr
->ih_tos
= ip_fd
->if_ipopt
.nwio_tos
;
138 ip_hdr
->ih_flags_fragoff
= 0;
139 if (ip_fd
->if_ipopt
.nwio_df
)
140 ip_hdr
->ih_flags_fragoff
|= HTONS(IH_DONT_FRAG
);
141 ip_hdr
->ih_ttl
= ip_fd
->if_ipopt
.nwio_ttl
;
142 ttl
= ORTD_UNREACHABLE
+1; /* Don't check TTL */
146 hdr_len
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
)*4;
148 if (hdr_len
<IP_MIN_HDR_SIZE
)
150 else if (hdr_len
>data_len
)
152 else if (!ip_hdr
->ih_ttl
)
160 data
= bf_packIffLess(data
, hdr_len
);
161 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
162 if (hdr_len
!= IP_MIN_HDR_SIZE
)
164 r
= ip_chk_hdropt((u8_t
*)(ptr2acc_data(data
) +
166 hdr_len
-IP_MIN_HDR_SIZE
);
176 ip_hdr
->ih_vers_ihl
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
) |
178 ip_hdr
->ih_length
= htons(data_len
);
179 ip_hdr
->ih_flags_fragoff
&= ~HTONS(IH_FRAGOFF_MASK
|
180 IH_FLAGS_UNUSED
| IH_MORE_FRAGS
);
181 if (ip_fd
->if_ipopt
.nwio_flags
& NWIO_PROTOSPEC
)
182 ip_hdr
->ih_proto
= ip_fd
->if_ipopt
.nwio_proto
;
183 ip_hdr
->ih_id
= htons(ip_port
->ip_frame_id
++);
184 ip_hdr
->ih_src
= ip_fd
->if_port
->ip_ipaddr
;
185 if (ip_fd
->if_ipopt
.nwio_flags
& NWIO_REMSPEC
)
186 ip_hdr
->ih_dst
= ip_fd
->if_ipopt
.nwio_rem
;
188 netmask
= ip_port
->ip_subnetmask
;
189 my_ipaddr
= ip_port
->ip_ipaddr
;
191 dstaddr
= ip_hdr
->ih_dst
;
192 hostrep_dst
= ntohl(dstaddr
);
194 if (hostrep_dst
== (ipaddr_t
)-1)
195 ; /* OK, local broadcast */
196 else if ((hostrep_dst
& 0xe0000000l
) == 0xe0000000l
)
197 ; /* OK, Multicast */
198 else if ((hostrep_dst
& 0xf0000000l
) == 0xf0000000l
)
199 r
= EAFNOSUPPORT
; /* Bad class */
200 else if ((dstaddr
^ my_ipaddr
) & netmask
)
201 ; /* OK, remote destination */
202 else if (!(dstaddr
& ~netmask
) &&
203 (ip_port
->ip_flags
& IPF_SUBNET_BCAST
))
205 r
= EAFNOSUPPORT
; /* Zero host part */
209 DIFBLOCK(1, r
== EAFNOSUPPORT
,
210 printf("bad destination: ");
211 writeIpAddr(ip_hdr
->ih_dst
);
216 ip_hdr_chksum(ip_hdr
, hdr_len
);
218 data
= bf_packIffLess(data
, IP_MIN_HDR_SIZE
);
219 assert (data
->acc_length
>= IP_MIN_HDR_SIZE
);
220 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
222 if (ip_hdr
->ih_flags_fragoff
& HTONS(IH_DONT_FRAG
))
224 req_mtu
= bf_bufsize(data
);
225 if (req_mtu
> ip_port
->ip_mtu
)
228 "packet is larger than link MTU and DF is set\n"));
236 addrInBytes
= (u8_t
*)&dstaddr
;
238 if ((addrInBytes
[0] & 0xff) == 0x7f) /* local loopback */
240 assert (data
->acc_linkC
== 1);
241 dstaddr
= ip_hdr
->ih_dst
; /* swap src and dst
243 ip_hdr
->ih_dst
= ip_hdr
->ih_src
;
244 ip_hdr
->ih_src
= dstaddr
;
245 data
->acc_ext_link
= NULL
;
246 if (ip_port
->ip_loopb_head
== NULL
)
248 ip_port
->ip_loopb_head
= data
;
250 ev_enqueue(&ip_port
->ip_loopb_event
,
251 ip_process_loopb
, arg
);
254 ip_port
->ip_loopb_tail
->acc_ext_link
= data
;
255 ip_port
->ip_loopb_tail
= data
;
260 if ((dstaddr
& HTONL(0xe0000000)) == HTONL(0xe0000000))
262 if (dstaddr
== (ipaddr_t
)-1)
264 r
= (*ip_port
->ip_dev_send
)(ip_port
, dstaddr
, data
,
268 if (ip_nettype(dstaddr
) == IPNT_CLASS_D
)
270 /* Multicast, what about multicast routing? */
271 r
= (*ip_port
->ip_dev_send
)(ip_port
, dstaddr
, data
,
277 if (dstaddr
== my_ipaddr
)
279 assert (data
->acc_linkC
== 1);
281 data
->acc_ext_link
= NULL
;
282 if (ip_port
->ip_loopb_head
== NULL
)
284 ip_port
->ip_loopb_head
= data
;
286 ev_enqueue(&ip_port
->ip_loopb_event
,
287 ip_process_loopb
, arg
);
290 ip_port
->ip_loopb_tail
->acc_ext_link
= data
;
291 ip_port
->ip_loopb_tail
= data
;
296 if (((dstaddr
^ my_ipaddr
) & netmask
) == 0)
298 type
= ((dstaddr
== (my_ipaddr
| ~netmask
) &&
299 (ip_port
->ip_flags
& IPF_SUBNET_BCAST
)) ?
300 IP_LT_BROADCAST
: IP_LT_NORMAL
);
302 r
= (*ip_port
->ip_dev_send
)(ip_port
, dstaddr
, data
, type
);
306 r
= oroute_frag (ip_port
- ip_port_table
, dstaddr
, ttl
, req_mtu
,
311 if (nexthop
== ip_port
->ip_ipaddr
)
313 data
->acc_ext_link
= NULL
;
314 if (ip_port
->ip_loopb_head
== NULL
)
316 ip_port
->ip_loopb_head
= data
;
318 ev_enqueue(&ip_port
->ip_loopb_event
,
319 ip_process_loopb
, arg
);
322 ip_port
->ip_loopb_tail
->acc_ext_link
= data
;
323 ip_port
->ip_loopb_tail
= data
;
327 r
= (*ip_port
->ip_dev_send
)(ip_port
,
328 nexthop
, data
, IP_LT_NORMAL
);
333 DBLOCK(0x10, printf("got error %d\n", r
));
339 void ip_hdr_chksum(ip_hdr
, ip_hdr_len
)
343 ip_hdr
->ih_hdr_chk
= 0;
344 ip_hdr
->ih_hdr_chk
= ~oneC_sum (0, (u16_t
*)ip_hdr
, ip_hdr_len
);
347 acc_t
*ip_split_pack (ip_port
, ref_last
, mtu
)
353 ip_hdr_t
*first_hdr
, *second_hdr
;
354 int first_hdr_len
, second_hdr_len
;
355 int first_data_len
, second_data_len
;
356 int data_len
, max_data_len
, nfrags
, new_first_data_len
;
357 int first_opt_size
, second_opt_size
;
358 acc_t
*first_pack
, *second_pack
, *tmp_pack
;
359 u8_t
*first_optptr
, *second_optptr
;
362 first_pack
= *ref_last
;
366 first_pack
= bf_align(first_pack
, IP_MIN_HDR_SIZE
, 4);
367 first_pack
= bf_packIffLess(first_pack
, IP_MIN_HDR_SIZE
);
368 assert (first_pack
->acc_length
>= IP_MIN_HDR_SIZE
);
370 first_hdr
= (ip_hdr_t
*)ptr2acc_data(first_pack
);
371 first_hdr_len
= (first_hdr
->ih_vers_ihl
& IH_IHL_MASK
) * 4;
372 if (first_hdr_len
>IP_MIN_HDR_SIZE
)
374 first_pack
= bf_packIffLess(first_pack
, first_hdr_len
);
375 first_hdr
= (ip_hdr_t
*)ptr2acc_data(first_pack
);
378 pack_siz
= bf_bufsize(first_pack
);
379 assert(pack_siz
> mtu
);
381 assert (!(first_hdr
->ih_flags_fragoff
& HTONS(IH_DONT_FRAG
)));
383 if (first_pack
->acc_linkC
!= 1 ||
384 first_pack
->acc_buffer
->buf_linkC
!= 1)
386 /* Get a private copy of the IP header */
387 tmp_pack
= bf_memreq(first_hdr_len
);
388 memcpy(ptr2acc_data(tmp_pack
), first_hdr
, first_hdr_len
);
389 first_pack
= bf_delhead(first_pack
, first_hdr_len
);
390 tmp_pack
->acc_next
= first_pack
;
391 first_pack
= tmp_pack
; tmp_pack
= NULL
;
392 first_hdr
= (ip_hdr_t
*)ptr2acc_data(first_pack
);
395 data_len
= ntohs(first_hdr
->ih_length
) - first_hdr_len
;
397 /* Try to split the packet evenly. */
398 assert(mtu
> first_hdr_len
);
399 max_data_len
= mtu
-first_hdr_len
;
400 nfrags
= (data_len
/max_data_len
)+1;
401 new_first_data_len
= data_len
/nfrags
;
402 if (new_first_data_len
< 8)
404 /* Special case for extremely small MTUs */
405 new_first_data_len
= 8;
407 new_first_data_len
&= ~7; /* data goes in 8 byte chuncks */
409 assert(new_first_data_len
>= 8);
410 assert(new_first_data_len
+first_hdr_len
<= mtu
);
412 second_data_len
= data_len
-new_first_data_len
;
413 second_pack
= bf_cut(first_pack
, first_hdr_len
+
414 new_first_data_len
, second_data_len
);
415 tmp_pack
= first_pack
;
416 first_data_len
= new_first_data_len
;
417 first_pack
= bf_cut (tmp_pack
, 0, first_hdr_len
+first_data_len
);
419 tmp_pack
= bf_memreq(first_hdr_len
);
420 tmp_pack
->acc_next
= second_pack
;
421 second_pack
= tmp_pack
;
422 second_hdr
= (ip_hdr_t
*)ptr2acc_data(second_pack
);
423 *second_hdr
= *first_hdr
;
424 second_hdr
->ih_flags_fragoff
= htons(
425 ntohs(first_hdr
->ih_flags_fragoff
)+(first_data_len
/8));
427 first_opt_size
= first_hdr_len
-IP_MIN_HDR_SIZE
;
431 first_pack
= bf_packIffLess (first_pack
,
433 first_hdr
= (ip_hdr_t
*)ptr2acc_data(first_pack
);
434 assert (first_pack
->acc_length
>=first_hdr_len
);
435 first_optptr
= (u8_t
*)ptr2acc_data(first_pack
)+
437 second_optptr
= (u8_t
*)ptr2acc_data(
438 second_pack
)+IP_MIN_HDR_SIZE
;
440 while (i
<first_opt_size
)
442 switch (*first_optptr
& IP_OPT_NUMBER
)
449 optlen
= first_optptr
[1];
452 assert (i
+ optlen
<= first_opt_size
);
454 if (*first_optptr
& IP_OPT_COPIED
)
456 second_opt_size
+= optlen
;
462 first_optptr
+= optlen
;
464 while (second_opt_size
& 3)
470 second_hdr_len
= IP_MIN_HDR_SIZE
+ second_opt_size
;
472 second_hdr
->ih_vers_ihl
= (second_hdr
->ih_vers_ihl
& 0xf0)
473 + (second_hdr_len
/4);
474 second_hdr
->ih_length
= htons(second_data_len
+
476 second_pack
->acc_length
= second_hdr_len
;
478 assert(first_pack
->acc_linkC
== 1);
479 assert(first_pack
->acc_buffer
->buf_linkC
== 1);
481 first_hdr
->ih_flags_fragoff
|= HTONS(IH_MORE_FRAGS
);
482 first_hdr
->ih_length
= htons(first_data_len
+
484 assert (!(second_hdr
->ih_flags_fragoff
& HTONS(IH_DONT_FRAG
)));
486 ip_hdr_chksum(first_hdr
, first_hdr_len
);
487 if (second_data_len
+second_hdr_len
<= mtu
)
489 /* second_pack will not be split any further, so we have to
490 * calculate the header checksum.
492 ip_hdr_chksum(second_hdr
, second_hdr_len
);
495 *ref_last
= second_pack
;
500 static void error_reply (ip_fd
, error
)
504 if ((*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
, (size_t)error
,
507 ip_panic(( "can't error_reply" ));
512 * $PchId: ip_write.c,v 1.22 2004/08/03 11:11:04 philip Exp $