4 Copyright 1995 Philip Homburg
24 FORWARD
void error_reply
ARGS(( ip_fd_t
*fd
, int error
));
26 PUBLIC
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 PUBLIC
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. What kind of error do we want? For
82 * the moment, we return OK.
88 data_len
= bf_bufsize(data
);
90 if (ip_fd
->if_ipopt
.nwio_flags
& NWIO_RWDATONLY
)
92 tmp_pack
= bf_memreq(IP_MIN_HDR_SIZE
);
93 tmp_pack
->acc_next
= data
;
95 data_len
+= IP_MIN_HDR_SIZE
;
97 if (data_len
<IP_MIN_HDR_SIZE
)
103 data
= bf_packIffLess(data
, IP_MIN_HDR_SIZE
);
104 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
105 if (data
->acc_linkC
!= 1 || data
->acc_buffer
->buf_linkC
!= 1)
107 tmp_pack
= bf_memreq(IP_MIN_HDR_SIZE
);
108 tmp_hdr
= (ip_hdr_t
*)ptr2acc_data(tmp_pack
);
110 tmp_pack
->acc_next
= bf_cut(data
, IP_MIN_HDR_SIZE
,
111 data_len
-IP_MIN_HDR_SIZE
);
115 assert (data
->acc_length
>= IP_MIN_HDR_SIZE
);
118 if (ip_fd
->if_ipopt
.nwio_flags
& NWIO_HDR_O_SPEC
)
120 hdr_opt_len
= ip_fd
->if_ipopt
.nwio_hdropt
.iho_opt_siz
;
123 tmp_pack
= bf_cut(data
, 0, IP_MIN_HDR_SIZE
);
124 tmp_pack1
= bf_cut (data
, IP_MIN_HDR_SIZE
,
125 data_len
-IP_MIN_HDR_SIZE
);
127 data
= bf_packIffLess(tmp_pack
, IP_MIN_HDR_SIZE
);
128 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
129 tmp_pack
= bf_memreq (hdr_opt_len
);
130 memcpy (ptr2acc_data(tmp_pack
), ip_fd
->if_ipopt
.
131 nwio_hdropt
.iho_data
, hdr_opt_len
);
132 data
->acc_next
= tmp_pack
;
133 tmp_pack
->acc_next
= tmp_pack1
;
134 hdr_len
= IP_MIN_HDR_SIZE
+hdr_opt_len
;
137 hdr_len
= IP_MIN_HDR_SIZE
;
138 ip_hdr
->ih_vers_ihl
= hdr_len
/4;
139 ip_hdr
->ih_tos
= ip_fd
->if_ipopt
.nwio_tos
;
140 ip_hdr
->ih_flags_fragoff
= 0;
141 if (ip_fd
->if_ipopt
.nwio_df
)
142 ip_hdr
->ih_flags_fragoff
|= HTONS(IH_DONT_FRAG
);
143 ip_hdr
->ih_ttl
= ip_fd
->if_ipopt
.nwio_ttl
;
144 ttl
= ORTD_UNREACHABLE
+1; /* Don't check TTL */
148 hdr_len
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
)*4;
150 if (hdr_len
<IP_MIN_HDR_SIZE
)
152 else if (hdr_len
>data_len
)
154 else if (!ip_hdr
->ih_ttl
)
162 data
= bf_packIffLess(data
, hdr_len
);
163 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
164 if (hdr_len
!= IP_MIN_HDR_SIZE
)
166 r
= ip_chk_hdropt((u8_t
*)(ptr2acc_data(data
) +
168 hdr_len
-IP_MIN_HDR_SIZE
);
178 ip_hdr
->ih_vers_ihl
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
) |
180 ip_hdr
->ih_length
= htons(data_len
);
181 ip_hdr
->ih_flags_fragoff
&= ~HTONS(IH_FRAGOFF_MASK
|
182 IH_FLAGS_UNUSED
| IH_MORE_FRAGS
);
183 if (ip_fd
->if_ipopt
.nwio_flags
& NWIO_PROTOSPEC
)
184 ip_hdr
->ih_proto
= ip_fd
->if_ipopt
.nwio_proto
;
185 ip_hdr
->ih_id
= htons(ip_port
->ip_frame_id
++);
186 ip_hdr
->ih_src
= ip_fd
->if_port
->ip_ipaddr
;
187 if (ip_fd
->if_ipopt
.nwio_flags
& NWIO_REMSPEC
)
188 ip_hdr
->ih_dst
= ip_fd
->if_ipopt
.nwio_rem
;
190 netmask
= ip_port
->ip_subnetmask
;
191 my_ipaddr
= ip_port
->ip_ipaddr
;
193 dstaddr
= ip_hdr
->ih_dst
;
194 hostrep_dst
= ntohl(dstaddr
);
196 if (hostrep_dst
== (ipaddr_t
)-1)
197 ; /* OK, local broadcast */
198 else if ((hostrep_dst
& 0xe0000000l
) == 0xe0000000l
)
199 ; /* OK, Multicast */
200 else if ((hostrep_dst
& 0xf0000000l
) == 0xf0000000l
)
201 r
= EBADDEST
; /* Bad class */
202 else if ((dstaddr
^ my_ipaddr
) & netmask
)
203 ; /* OK, remote destination */
204 else if (!(dstaddr
& ~netmask
) &&
205 (ip_port
->ip_flags
& IPF_SUBNET_BCAST
))
207 r
= EBADDEST
; /* Zero host part */
211 DIFBLOCK(1, r
== EBADDEST
,
212 printf("bad destination: ");
213 writeIpAddr(ip_hdr
->ih_dst
);
218 ip_hdr_chksum(ip_hdr
, hdr_len
);
220 data
= bf_packIffLess(data
, IP_MIN_HDR_SIZE
);
221 assert (data
->acc_length
>= IP_MIN_HDR_SIZE
);
222 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
224 if (ip_hdr
->ih_flags_fragoff
& HTONS(IH_DONT_FRAG
))
226 req_mtu
= bf_bufsize(data
);
227 if (req_mtu
> ip_port
->ip_mtu
)
230 "packet is larger than link MTU and DF is set\n"));
238 addrInBytes
= (u8_t
*)&dstaddr
;
240 if ((addrInBytes
[0] & 0xff) == 0x7f) /* local loopback */
242 assert (data
->acc_linkC
== 1);
243 dstaddr
= ip_hdr
->ih_dst
; /* swap src and dst
245 ip_hdr
->ih_dst
= ip_hdr
->ih_src
;
246 ip_hdr
->ih_src
= dstaddr
;
247 data
->acc_ext_link
= NULL
;
248 if (ip_port
->ip_loopb_head
== NULL
)
250 ip_port
->ip_loopb_head
= data
;
252 ev_enqueue(&ip_port
->ip_loopb_event
,
253 ip_process_loopb
, arg
);
256 ip_port
->ip_loopb_tail
->acc_ext_link
= data
;
257 ip_port
->ip_loopb_tail
= data
;
262 if ((dstaddr
& HTONL(0xe0000000)) == HTONL(0xe0000000))
264 if (dstaddr
== (ipaddr_t
)-1)
266 r
= (*ip_port
->ip_dev_send
)(ip_port
, dstaddr
, data
,
270 if (ip_nettype(dstaddr
) == IPNT_CLASS_D
)
272 /* Multicast, what about multicast routing? */
273 r
= (*ip_port
->ip_dev_send
)(ip_port
, dstaddr
, data
,
279 if (dstaddr
== my_ipaddr
)
281 assert (data
->acc_linkC
== 1);
283 data
->acc_ext_link
= NULL
;
284 if (ip_port
->ip_loopb_head
== NULL
)
286 ip_port
->ip_loopb_head
= data
;
288 ev_enqueue(&ip_port
->ip_loopb_event
,
289 ip_process_loopb
, arg
);
292 ip_port
->ip_loopb_tail
->acc_ext_link
= data
;
293 ip_port
->ip_loopb_tail
= data
;
298 if (((dstaddr
^ my_ipaddr
) & netmask
) == 0)
300 type
= ((dstaddr
== (my_ipaddr
| ~netmask
) &&
301 (ip_port
->ip_flags
& IPF_SUBNET_BCAST
)) ?
302 IP_LT_BROADCAST
: IP_LT_NORMAL
);
304 r
= (*ip_port
->ip_dev_send
)(ip_port
, dstaddr
, data
, type
);
308 r
= oroute_frag (ip_port
- ip_port_table
, dstaddr
, ttl
, req_mtu
,
313 if (nexthop
== ip_port
->ip_ipaddr
)
315 data
->acc_ext_link
= NULL
;
316 if (ip_port
->ip_loopb_head
== NULL
)
318 ip_port
->ip_loopb_head
= data
;
320 ev_enqueue(&ip_port
->ip_loopb_event
,
321 ip_process_loopb
, arg
);
324 ip_port
->ip_loopb_tail
->acc_ext_link
= data
;
325 ip_port
->ip_loopb_tail
= data
;
329 r
= (*ip_port
->ip_dev_send
)(ip_port
,
330 nexthop
, data
, IP_LT_NORMAL
);
335 DBLOCK(0x10, printf("got error %d\n", r
));
341 PUBLIC
void ip_hdr_chksum(ip_hdr
, ip_hdr_len
)
345 ip_hdr
->ih_hdr_chk
= 0;
346 ip_hdr
->ih_hdr_chk
= ~oneC_sum (0, (u16_t
*)ip_hdr
, ip_hdr_len
);
349 PUBLIC acc_t
*ip_split_pack (ip_port
, ref_last
, mtu
)
355 ip_hdr_t
*first_hdr
, *second_hdr
;
356 int first_hdr_len
, second_hdr_len
;
357 int first_data_len
, second_data_len
;
358 int data_len
, max_data_len
, nfrags
, new_first_data_len
;
359 int first_opt_size
, second_opt_size
;
360 acc_t
*first_pack
, *second_pack
, *tmp_pack
;
361 u8_t
*first_optptr
, *second_optptr
;
364 first_pack
= *ref_last
;
368 first_pack
= bf_align(first_pack
, IP_MIN_HDR_SIZE
, 4);
369 first_pack
= bf_packIffLess(first_pack
, IP_MIN_HDR_SIZE
);
370 assert (first_pack
->acc_length
>= IP_MIN_HDR_SIZE
);
372 first_hdr
= (ip_hdr_t
*)ptr2acc_data(first_pack
);
373 first_hdr_len
= (first_hdr
->ih_vers_ihl
& IH_IHL_MASK
) * 4;
374 if (first_hdr_len
>IP_MIN_HDR_SIZE
)
376 first_pack
= bf_packIffLess(first_pack
, first_hdr_len
);
377 first_hdr
= (ip_hdr_t
*)ptr2acc_data(first_pack
);
380 pack_siz
= bf_bufsize(first_pack
);
381 assert(pack_siz
> mtu
);
383 assert (!(first_hdr
->ih_flags_fragoff
& HTONS(IH_DONT_FRAG
)));
385 if (first_pack
->acc_linkC
!= 1 ||
386 first_pack
->acc_buffer
->buf_linkC
!= 1)
388 /* Get a private copy of the IP header */
389 tmp_pack
= bf_memreq(first_hdr_len
);
390 memcpy(ptr2acc_data(tmp_pack
), first_hdr
, first_hdr_len
);
391 first_pack
= bf_delhead(first_pack
, first_hdr_len
);
392 tmp_pack
->acc_next
= first_pack
;
393 first_pack
= tmp_pack
; tmp_pack
= NULL
;
394 first_hdr
= (ip_hdr_t
*)ptr2acc_data(first_pack
);
397 data_len
= ntohs(first_hdr
->ih_length
) - first_hdr_len
;
399 /* Try to split the packet evenly. */
400 assert(mtu
> first_hdr_len
);
401 max_data_len
= mtu
-first_hdr_len
;
402 nfrags
= (data_len
/max_data_len
)+1;
403 new_first_data_len
= data_len
/nfrags
;
404 if (new_first_data_len
< 8)
406 /* Special case for extremely small MTUs */
407 new_first_data_len
= 8;
409 new_first_data_len
&= ~7; /* data goes in 8 byte chuncks */
411 assert(new_first_data_len
>= 8);
412 assert(new_first_data_len
+first_hdr_len
<= mtu
);
414 second_data_len
= data_len
-new_first_data_len
;
415 second_pack
= bf_cut(first_pack
, first_hdr_len
+
416 new_first_data_len
, second_data_len
);
417 tmp_pack
= first_pack
;
418 first_data_len
= new_first_data_len
;
419 first_pack
= bf_cut (tmp_pack
, 0, first_hdr_len
+first_data_len
);
421 tmp_pack
= bf_memreq(first_hdr_len
);
422 tmp_pack
->acc_next
= second_pack
;
423 second_pack
= tmp_pack
;
424 second_hdr
= (ip_hdr_t
*)ptr2acc_data(second_pack
);
425 *second_hdr
= *first_hdr
;
426 second_hdr
->ih_flags_fragoff
= htons(
427 ntohs(first_hdr
->ih_flags_fragoff
)+(first_data_len
/8));
429 first_opt_size
= first_hdr_len
-IP_MIN_HDR_SIZE
;
433 first_pack
= bf_packIffLess (first_pack
,
435 first_hdr
= (ip_hdr_t
*)ptr2acc_data(first_pack
);
436 assert (first_pack
->acc_length
>=first_hdr_len
);
437 first_optptr
= (u8_t
*)ptr2acc_data(first_pack
)+
439 second_optptr
= (u8_t
*)ptr2acc_data(
440 second_pack
)+IP_MIN_HDR_SIZE
;
442 while (i
<first_opt_size
)
444 switch (*first_optptr
& IP_OPT_NUMBER
)
451 optlen
= first_optptr
[1];
454 assert (i
+ optlen
<= first_opt_size
);
456 if (*first_optptr
& IP_OPT_COPIED
)
458 second_opt_size
+= optlen
;
464 first_optptr
+= optlen
;
466 while (second_opt_size
& 3)
472 second_hdr_len
= IP_MIN_HDR_SIZE
+ second_opt_size
;
474 second_hdr
->ih_vers_ihl
= (second_hdr
->ih_vers_ihl
& 0xf0)
475 + (second_hdr_len
/4);
476 second_hdr
->ih_length
= htons(second_data_len
+
478 second_pack
->acc_length
= second_hdr_len
;
480 assert(first_pack
->acc_linkC
== 1);
481 assert(first_pack
->acc_buffer
->buf_linkC
== 1);
483 first_hdr
->ih_flags_fragoff
|= HTONS(IH_MORE_FRAGS
);
484 first_hdr
->ih_length
= htons(first_data_len
+
486 assert (!(second_hdr
->ih_flags_fragoff
& HTONS(IH_DONT_FRAG
)));
488 ip_hdr_chksum(first_hdr
, first_hdr_len
);
489 if (second_data_len
+second_hdr_len
<= mtu
)
491 /* second_pack will not be split any further, so we have to
492 * calculate the header checksum.
494 ip_hdr_chksum(second_hdr
, second_hdr_len
);
497 *ref_last
= second_pack
;
502 PRIVATE
void error_reply (ip_fd
, error
)
506 if ((*ip_fd
->if_get_userdata
)(ip_fd
->if_srfd
, (size_t)error
,
509 ip_panic(( "can't error_reply" ));
514 * $PchId: ip_write.c,v 1.22 2004/08/03 11:11:04 philip Exp $