4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * ipv4.c, Code implementing the IPv4 internet protocol.
28 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include <sys/types.h>
31 #include <socket_impl.h>
32 #include <socket_inet.h>
33 #include <sys/sysmacros.h>
34 #include <sys/socket.h>
35 #include <netinet/in_systm.h>
36 #include <netinet/in.h>
37 #include <netinet/ip.h>
38 #include <netinet/udp.h>
39 #include <net/if_arp.h>
40 #include <sys/promif.h>
41 #include <sys/bootconf.h>
42 #include <sys/fcntl.h>
43 #include <sys/salib.h>
47 #include "ipv4_impl.h"
50 #include "v4_sum_impl.h"
51 #include <sys/bootdebug.h>
53 static struct ip_frag fragment
[FRAG_MAX
]; /* ip fragment buffers */
54 static int fragments
; /* Number of fragments */
55 static uint8_t ttl
= MAXTTL
; /* IP ttl */
56 static struct in_addr myip
; /* our network-order IP addr */
57 static struct in_addr mynet
; /* net-order netaddr */
58 static struct in_addr netmask
=
59 { 0xff, 0xff, 0xff, 0xff }; /* our network-order netmask */
60 static boolean_t netmask_set
= B_FALSE
; /* has anyone set netmask? */
61 static struct in_addr defaultrouter
; /* net-order defaultrouter */
62 static int promiscuous
; /* promiscuous mode */
63 static struct routing table
[IPV4_ROUTE_TABLE_SIZE
];
65 static uint16_t g_ip_id
;
73 * display the fragment list. For debugging purposes.
76 frag_disp(uint16_t size
)
81 printf("Dumping fragment info: (%d)\n\n", fragments
);
82 printf("More:\tOffset:\tDatap:\t\tIPid:\t\tIPlen:\tIPhlen:\n");
83 for (i
= 0; i
< FRAG_MAX
; i
++) {
84 if (fragment
[i
].mp
== NULL
)
86 printf("%d\t%d\t0x%x\t%d\t\t%d\t%d\n", fragment
[i
].more
,
87 fragment
[i
].offset
, fragment
[i
].mp
->b_rptr
,
88 fragment
[i
].ipid
, fragment
[i
].iplen
, fragment
[i
].iphlen
);
89 total
+= (fragment
[i
].iplen
- fragment
[i
].iphlen
);
91 printf("Total length is: %d. It should be: %d\n\n", total
, size
);
93 #endif /* FRAG_DEBUG */
96 * This function returns index of fragment 0 of the current fragmented DGRAM
97 * (which would contain the transport header). Return the fragment number
98 * for success, -1 if we don't yet have the first fragment.
108 for (i
= 0; i
< FRAG_MAX
; i
++) {
109 if (fragment
[i
].mp
!= NULL
&& fragment
[i
].offset
== 0)
116 * This function returns index of the last fragment of the current DGRAM.
117 * Returns the fragment number for success, -1 if we don't yet have the
128 for (i
= 0; i
< FRAG_MAX
; i
++) {
129 if (fragment
[i
].mp
!= NULL
&& !fragment
[i
].more
)
136 * This function adds a fragment to the current pkt fragment list. Returns
137 * FRAG_NOSLOTS if there are no more slots, FRAG_DUP if the fragment is
138 * a duplicate, or FRAG_SUCCESS if it is successful.
141 frag_add(int16_t offset
, mblk_t
*mp
, uint16_t ipid
,
142 int16_t iplen
, int16_t iphlen
, uint8_t ipp
)
145 int16_t true_offset
= IPV4_OFFSET(offset
);
147 /* first pass - look for duplicates */
148 for (i
= 0; i
< FRAG_MAX
; i
++) {
149 if (fragment
[i
].mp
!= NULL
&&
150 fragment
[i
].offset
== true_offset
)
154 /* second pass - fill in empty slot */
155 for (i
= 0; i
< FRAG_MAX
; i
++) {
156 if (fragment
[i
].mp
== NULL
) {
157 fragment
[i
].more
= (offset
& IP_MF
);
158 fragment
[i
].offset
= true_offset
;
160 fragment
[i
].ipid
= ipid
;
161 fragment
[i
].iplen
= iplen
;
162 fragment
[i
].iphlen
= iphlen
;
163 fragment
[i
].ipp
= ipp
;
165 return (FRAG_SUCCESS
);
168 return (FRAG_NOSLOTS
);
177 if (fragment
[index
].mp
!= NULL
) {
178 freeb(fragment
[index
].mp
);
181 bzero((caddr_t
)&fragment
[index
], sizeof (struct ip_frag
));
185 * zero the frag list.
192 for (i
= 0; i
< FRAG_MAX
; i
++)
199 * Analyze the fragment list - see if we captured all our fragments.
201 * Returns TRUE if we've got all the fragments, and FALSE if we don't.
206 int i
, first_frag
, last_frag
;
207 int16_t actual
, total
;
211 if (fragments
== 0 || (first_frag
= frag_first()) < 0 ||
212 (last_frag
= frag_last()) < 0)
216 * Validate the ipid's of our fragments - nuke those that don't
217 * match the id of the first fragment or don't match the IP
218 * protocol of the first fragment.
220 ip_id
= fragment
[first_frag
].ipid
;
221 ipp
= fragment
[first_frag
].ipp
;
222 for (i
= 0; i
< FRAG_MAX
; i
++) {
223 if (fragment
[i
].mp
!= NULL
&& ip_id
!= fragment
[i
].ipid
&&
224 fragment
[i
].ipp
!= ipp
) {
226 printf("ipv4: Frag id mismatch: %x != %x\n",
227 fragment
[i
].ipid
, ip_id
);
228 #endif /* FRAG_DEBUG */
236 total
= fragment
[last_frag
].offset
+ fragment
[last_frag
].iplen
-
237 fragment
[last_frag
].iphlen
;
239 for (i
= 0, actual
= 0; i
< FRAG_MAX
; i
++)
240 actual
+= (fragment
[i
].iplen
- fragment
[i
].iphlen
);
244 #endif /* FRAG_DEBUG */
246 return (total
== actual
);
250 * Load the assembled fragments into igp. Returns 0 for success, nonzero
254 frag_load(struct inetgram
*igp
)
259 boolean_t first_frag
= B_FALSE
;
268 /* Get the IP header length of the first fragment. */
271 first_iph_len
= fragment
[i
].iphlen
;
272 for (i
= 0, len
= 0, total_len
= 0; i
< FRAG_MAX
; i
++) {
273 if (fragment
[i
].mp
!= NULL
) {
275 * Copy just the data (omit the ip header of all
276 * fragments except the first one which contains
279 if (fragment
[i
].offset
== 0) {
280 len
= fragment
[i
].iplen
;
283 len
= fragment
[i
].iplen
- fragment
[i
].iphlen
;
286 if (total_len
> mp
->b_size
)
289 bcopy((caddr_t
)(fragment
[i
].mp
->b_rptr
),
290 (caddr_t
)mp
->b_rptr
, len
);
291 first_frag
= B_FALSE
;
293 bcopy((caddr_t
)(fragment
[i
].mp
->b_rptr
+
295 (caddr_t
)(mp
->b_rptr
+ first_iph_len
+
296 fragment
[i
].offset
), len
);
301 /* Fix the total length in the IP header. */
302 iph
= (struct ip
*)mp
->b_rptr
;
303 iph
->ip_len
= htons(total_len
);
308 * Locate a routing table entry based upon arguments. IP addresses expected
309 * in network order. Returns index for success, -1 if entry not found.
312 find_route(uint8_t *flagp
, struct in_addr
*destp
, struct in_addr
*gatewayp
)
314 int i
, table_entry
= -1;
316 for (i
= 0; table_entry
== -1 && i
< IPV4_ROUTE_TABLE_SIZE
; i
++) {
318 if (*flagp
& table
[i
].flag
)
322 if (destp
->s_addr
== table
[i
].dest
.s_addr
)
327 if (gatewayp
!= NULL
) {
328 if (gatewayp
->s_addr
== table
[i
].gateway
.s_addr
)
334 return (table_entry
);
338 * ADD or DEL a routing table entry. Returns 0 for success, -1 and errno
339 * otherwise. IP addresses are expected in network order.
342 ipv4_route(int cmd
, uint8_t flag
, struct in_addr
*destp
,
343 struct in_addr
*gatewayp
)
345 static int routing_table_initialized
;
349 if (gatewayp
== NULL
) {
354 /* initialize routing table */
355 if (routing_table_initialized
== 0) {
356 for (index
= 0; index
< IPV4_ROUTE_TABLE_SIZE
; index
++)
357 table
[index
].flag
= RT_UNUSED
;
358 routing_table_initialized
= 1;
363 tmp_flag
= (uint8_t)RT_UNUSED
;
364 if ((index
= find_route(&tmp_flag
, NULL
, NULL
)) == -1) {
365 dprintf("ipv4_route: routing table full.\n");
369 table
[index
].flag
= flag
;
371 table
[index
].dest
.s_addr
= destp
->s_addr
;
373 table
[index
].dest
.s_addr
= htonl(INADDR_ANY
);
374 table
[index
].gateway
.s_addr
= gatewayp
->s_addr
;
379 if ((index
= find_route(&flag
, destp
, gatewayp
)) == -1) {
380 dprintf("ipv4_route: No such routing entry.\n");
384 if (cmd
== IPV4_DEL_ROUTE
) {
385 table
[index
].flag
= RT_UNUSED
;
386 table
[index
].dest
.s_addr
= htonl(INADDR_ANY
);
387 table
[index
].gateway
.s_addr
= htonl(INADDR_ANY
);
389 table
[index
].flag
= RT_NG
;
398 * Return gateway to destination. Returns gateway IP address in network order
399 * for success, NULL if no route to destination exists.
402 ipv4_get_route(uint8_t flag
, struct in_addr
*destp
, struct in_addr
*gatewayp
)
405 if ((index
= find_route(&flag
, destp
, gatewayp
)) == -1)
407 return (&table
[index
].gateway
);
411 * Initialize the IPv4 generic parts of the socket, as well as the routing
415 ipv4_socket_init(struct inetboot_socket
*isp
)
417 isp
->input
[NETWORK_LVL
] = ipv4_input
;
418 isp
->output
[NETWORK_LVL
] = ipv4_output
;
419 isp
->close
[NETWORK_LVL
] = NULL
;
420 isp
->headerlen
[NETWORK_LVL
] = ipv4_header_len
;
424 * Initialize a raw ipv4 socket.
427 ipv4_raw_socket(struct inetboot_socket
*isp
, uint8_t proto
)
429 isp
->type
= INETBOOT_RAW
;
431 isp
->proto
= IPPROTO_IP
;
434 isp
->input
[TRANSPORT_LVL
] = NULL
;
435 isp
->output
[TRANSPORT_LVL
] = NULL
;
436 isp
->headerlen
[TRANSPORT_LVL
] = NULL
;
441 * Return the size of an IPv4 header (no options)
445 ipv4_header_len(struct inetgram
*igm
)
447 return (sizeof (struct ip
));
451 * Set our source address.
452 * Argument is assumed to be host order.
455 ipv4_setipaddr(struct in_addr
*ip
)
457 myip
.s_addr
= htonl(ip
->s_addr
);
461 * Returns our current source address in host order.
464 ipv4_getipaddr(struct in_addr
*ip
)
466 ip
->s_addr
= ntohl(myip
.s_addr
);
471 * Argument is assumed to be host order.
474 ipv4_setnetmask(struct in_addr
*ip
)
476 netmask_set
= B_TRUE
;
477 netmask
.s_addr
= htonl(ip
->s_addr
);
478 mynet
.s_addr
= netmask
.s_addr
& myip
.s_addr
; /* implicit */
482 ipv4_getnetid(struct in_addr
*my_netid
)
484 struct in_addr my_netmask
;
485 if (mynet
.s_addr
!= 0)
486 my_netid
->s_addr
= ntohl(mynet
.s_addr
);
488 ipv4_getnetmask(&my_netmask
);
489 my_netid
->s_addr
= my_netmask
.s_addr
& ntohl(myip
.s_addr
);
494 * Returns our current netmask in host order.
495 * Neither OBP nor the standalone DHCP client mandate
496 * that the netmask be specified, so in the absence of
497 * a netmask, we attempt to derive it using class-based
501 ipv4_getnetmask(struct in_addr
*ip
)
503 if (netmask_set
|| (myip
.s_addr
== 0))
504 ip
->s_addr
= ntohl(netmask
.s_addr
);
506 /* base the netmask on our IP address */
507 if (IN_CLASSA(ntohl(myip
.s_addr
)))
508 ip
->s_addr
= ntohl(IN_CLASSA_NET
);
509 else if (IN_CLASSB(ntohl(myip
.s_addr
)))
510 ip
->s_addr
= ntohl(IN_CLASSB_NET
);
511 else if (IN_CLASSC(ntohl(myip
.s_addr
)))
512 ip
->s_addr
= ntohl(IN_CLASSC_NET
);
514 ip
->s_addr
= ntohl(IN_CLASSE_NET
);
519 * Set our default router.
520 * Argument is assumed to be host order, and *MUST* be on the same network
521 * as our source IP address.
524 ipv4_setdefaultrouter(struct in_addr
*ip
)
526 defaultrouter
.s_addr
= htonl(ip
->s_addr
);
530 * Returns our current default router in host order.
533 ipv4_getdefaultrouter(struct in_addr
*ip
)
535 ip
->s_addr
= ntohl(defaultrouter
.s_addr
);
539 * Toggle promiscuous flag. If set, client disregards destination IP
540 * address. Otherwise, only limited broadcast, network broadcast, and
541 * unicast traffic get through. Returns previous setting.
544 ipv4_setpromiscuous(int toggle
)
546 int old
= promiscuous
;
548 promiscuous
= toggle
;
557 ipv4_setmaxttl(uint8_t cttl
)
563 * Convert an ipv4 address to dotted notation.
564 * Returns ptr to statically allocated buffer containing dotted string.
567 inet_ntoa(struct in_addr ip
)
570 static char ipaddr
[16];
572 p
= (uint8_t *)&ip
.s_addr
;
573 (void) sprintf(ipaddr
, "%u.%u.%u.%u", p
[0], p
[1], p
[2], p
[3]);
578 * Construct a transport datagram from a series of IP fragments (igp == NULL)
579 * or from a single IP datagram (igp != NULL). Return the address of the
580 * contructed transport datagram.
583 make_trans_datagram(int index
, struct inetgram
*igp
, struct in_addr ipsrc
,
584 struct in_addr ipdst
, uint16_t iphlen
)
586 uint16_t trans_len
, *transp
, new_len
;
587 int first_frag
, last_frag
;
588 boolean_t fragmented
;
589 struct inetgram
*ngp
;
592 fragmented
= (igp
== NULL
);
594 ngp
= (struct inetgram
*)bkmem_zalloc(sizeof (struct inetgram
));
603 last_frag
= frag_last();
604 trans_len
= fragment
[last_frag
].offset
+
605 fragment
[last_frag
].iplen
- fragment
[last_frag
].iphlen
;
606 first_frag
= frag_first();
608 * The returned buffer contains the IP header of the
611 trans_len
+= fragment
[first_frag
].iphlen
;
612 transp
= (uint16_t *)(fragment
[first_frag
].mp
->b_rptr
+
613 fragment
[first_frag
].iphlen
);
616 * Note that igm_len may not be the real length of an
617 * IP packet because some network interface, such as
618 * Ethernet, as a minimum frame size. So we should not
619 * use the interface frame size to determine the
620 * length of an IP packet. We should use the IP
621 * length field in the IP header.
623 iph
= (struct ip
*)igp
->igm_mp
->b_rptr
;
624 trans_len
= ntohs(iph
->ip_len
);
625 transp
= (uint16_t *)(igp
->igm_mp
->b_rptr
+ iphlen
);
628 ngp
->igm_saddr
.sin_addr
.s_addr
= ipsrc
.s_addr
;
629 ngp
->igm_saddr
.sin_port
= sockets
[index
].ports(transp
, SOURCE
);
630 ngp
->igm_target
.s_addr
= ipdst
.s_addr
;
631 ngp
->igm_level
= TRANSPORT_LVL
;
634 * Align to 16bit value. Checksum code may require an extra byte
637 new_len
= ((trans_len
+ sizeof (int16_t) - 1) &
638 ~(sizeof (int16_t) - 1));
639 if ((ngp
->igm_mp
= allocb(new_len
, 0)) == NULL
) {
641 bkmem_free((caddr_t
)ngp
, sizeof (struct inetgram
));
648 if (frag_load(ngp
) != 0) {
650 bkmem_free((caddr_t
)ngp
, sizeof (struct inetgram
));
656 bcopy((caddr_t
)(igp
->igm_mp
->b_rptr
),
657 (caddr_t
)ngp
->igm_mp
->b_rptr
, trans_len
);
658 ngp
->igm_mp
->b_wptr
+= trans_len
;
664 * ipv4_input: Pull in IPv4 datagrams addressed to us. Handle IP fragmentation
665 * (fragments received in any order) and ICMP at this level.
667 * Note that because our network is serviced by polling when we expect
668 * something (upon a referenced socket), we don't go through the work of
669 * locating the appropriate socket a datagram is destined for. We'll only
670 * accept data for the referenced socket. This means we don't have
671 * asynchronous networking, but since we can't service the net using an
672 * interrupt handler, it doesn't do us any good to try to service datagrams
673 * destined for sockets other than the referenced one. Data is handled in
676 * The mac layer will grab all frames for us. If we find we don't have all
677 * the necessary fragments to reassemble the datagram, we'll call the mac
678 * layer again for FRAG_ATTEMPTS to see if it has any more frames.
680 * Supported protocols: IPPROTO_IP, IPPROTO_ICMP, IPPROTO_UDP.
682 * Returns: number of NETWORK_LVL datagrams placed on socket , -1 if error
685 * Note: errno is set to ETIMEDOUT if fragment reassembly fails.
688 ipv4_input(int index
)
691 int frag_stat
, input_attempts
= 0;
692 uint16_t iphlen
, iplen
, ip_id
;
695 struct inetgram
*igp
, *newgp
= NULL
, *ipv4_listp
= NULL
;
696 struct in_addr ipdst
, ipsrc
;
701 printf("ipv4_input(%d): start ######################################\n",
709 while ((igp
= sockets
[index
].inq
) != NULL
) {
710 if (igp
->igm_level
!= NETWORK_LVL
) {
712 printf("ipv4_input(%d): unexpected frame type: %d\n",
713 index
, igp
->igm_level
);
715 del_gram(&sockets
[index
].inq
, igp
, TRUE
);
718 iphp
= (struct ip
*)igp
->igm_mp
->b_rptr
;
719 if (iphp
->ip_v
!= IPVERSION
) {
720 dprintf("ipv4_input(%d): IPv%d datagram discarded\n",
722 del_gram(&sockets
[index
].inq
, igp
, TRUE
);
725 iphlen
= iphp
->ip_hl
<< 2;
726 if (iphlen
< sizeof (struct ip
)) {
727 dprintf("ipv4_input(%d): IP msg too short (%d < %u)\n",
728 index
, iphlen
, (uint_t
)sizeof (struct ip
));
729 del_gram(&sockets
[index
].inq
, igp
, TRUE
);
732 iplen
= ntohs(iphp
->ip_len
);
733 if (iplen
> msgdsize(igp
->igm_mp
)) {
734 dprintf("ipv4_input(%d): IP len/buffer mismatch "
735 "(%d > %lu)\n", index
, iplen
, igp
->igm_mp
->b_size
);
736 del_gram(&sockets
[index
].inq
, igp
, TRUE
);
740 bcopy((caddr_t
)&(iphp
->ip_dst
), (caddr_t
)&ipdst
,
742 bcopy((caddr_t
)&(iphp
->ip_src
), (caddr_t
)&ipsrc
,
745 /* igp->igm_mp->b_datap is guaranteed to be 64 bit aligned] */
746 if (ipv4cksum((uint16_t *)iphp
, iphlen
) != 0) {
747 dprintf("ipv4_input(%d): Bad IP header checksum "
748 "(to %s)\n", index
, inet_ntoa(ipdst
));
749 del_gram(&sockets
[index
].inq
, igp
, TRUE
);
754 /* validate destination address */
755 if (ipdst
.s_addr
!= htonl(INADDR_BROADCAST
) &&
756 ipdst
.s_addr
!= (mynet
.s_addr
| ~netmask
.s_addr
) &&
757 ipdst
.s_addr
!= myip
.s_addr
) {
759 printf("ipv4_input(%d): msg to %s discarded.\n",
760 index
, inet_ntoa(ipdst
));
763 del_gram(&sockets
[index
].inq
, igp
, TRUE
);
768 /* Intercept ICMP first */
769 if (!promiscuous
&& (iphp
->ip_p
== IPPROTO_ICMP
)) {
770 icmp4(igp
, iphp
, iphlen
, ipsrc
);
771 del_gram(&sockets
[index
].inq
, igp
, TRUE
);
776 printf("ipv4_input(%d): processing ID: 0x%x protocol %d "
777 "(0x%x) (0x%x,%d)\n",
778 index
, ntohs(iphp
->ip_id
), iphp
->ip_p
, igp
, igp
->igm_mp
,
779 igp
->igm_mp
->b_size
);
781 type
= sockets
[index
].type
;
782 if (type
== INETBOOT_RAW
) {
783 /* No fragmentation - Just the raw packet. */
785 printf("ipv4_input(%d): Raw packet.\n", index
);
787 del_gram(&sockets
[index
].inq
, igp
, FALSE
);
788 add_grams(&ipv4_listp
, igp
);
789 igp
->igm_mp
->b_rptr
+= iphlen
;
790 igp
->igm_mp
->b_wptr
= igp
->igm_mp
->b_rptr
+ iplen
;
795 if ((type
== INETBOOT_DGRAM
&& iphp
->ip_p
!= IPPROTO_UDP
) ||
796 (type
== INETBOOT_STREAM
&& iphp
->ip_p
!= IPPROTO_TCP
)) {
797 /* Wrong protocol. */
798 dprintf("ipv4_input(%d): unexpected protocol: "
799 "%d for socket type %d\n", index
, iphp
->ip_p
, type
);
800 del_gram(&sockets
[index
].inq
, igp
, TRUE
);
805 * The following code is common to both STREAM and DATAGRAM
810 * Once we process the first fragment, we won't have
811 * the transport header, so we'll have to match on
814 curr_off
= ntohs(iphp
->ip_off
);
815 if ((curr_off
& ~(IP_DF
| IP_MF
)) == 0) {
818 /* Validate transport header. */
820 if ((mp
->b_wptr
- mp
->b_rptr
- iphlen
) <
821 sockets
[index
].headerlen
[TRANSPORT_LVL
](igp
)) {
822 dprintf("ipv4_input(%d): datagram 0 "
823 "too small to hold transport header "
824 "(from %s)\n", index
, inet_ntoa(ipsrc
));
825 del_gram(&sockets
[index
].inq
, igp
, TRUE
);
830 * check alignment - transport elements are 16
833 transp
= (uint16_t *)(mp
->b_rptr
+ iphlen
);
834 if ((uintptr_t)transp
% sizeof (uint16_t)) {
835 dprintf("ipv4_input(%d): Transport "
836 "header is not 16-bit aligned "
837 "(0x%lx, from %s)\n", index
, (long)transp
,
839 del_gram(&sockets
[index
].inq
, igp
, TRUE
);
843 if (curr_off
& IP_MF
) {
844 /* fragment 0 of fragmented datagram */
845 ip_id
= ntohs(iphp
->ip_id
);
846 frag_stat
= frag_add(curr_off
, igp
->igm_mp
,
847 ip_id
, iplen
, iphlen
, iphp
->ip_p
);
848 if (frag_stat
!= FRAG_SUCCESS
) {
850 if (frag_stat
== FRAG_DUP
) {
852 "(%d): Frag dup.\n", index
);
858 #endif /* FRAG_DEBUG */
859 del_gram(&sockets
[index
].inq
,
864 del_gram(&sockets
[index
].inq
, igp
, FALSE
);
865 /* keep the data, lose the inetgram */
866 bkmem_free((caddr_t
)igp
,
867 sizeof (struct inetgram
));
869 printf("ipv4_input(%d): Frag/Off/Id "
870 "(%d/%d/%x)\n", index
, fragments
,
871 IPV4_OFFSET(curr_off
), ip_id
);
872 #endif /* FRAG_DEBUG */
874 /* Single, unfragmented datagram */
875 newgp
= make_trans_datagram(index
, igp
,
876 ipsrc
, ipdst
, iphlen
);
878 add_grams(&ipv4_listp
, newgp
);
881 del_gram(&sockets
[index
].inq
, igp
,
886 /* fragments other than 0 */
887 frag_stat
= frag_add(curr_off
, igp
->igm_mp
,
888 ntohs(iphp
->ip_id
), iplen
, iphlen
, iphp
->ip_p
);
890 if (frag_stat
== FRAG_SUCCESS
) {
892 printf("ipv4_input(%d): Frag(%d) "
893 "off(%d) id(%x)\n", index
,
894 fragments
, IPV4_OFFSET(curr_off
),
896 #endif /* FRAG_DEBUG */
897 del_gram(&sockets
[index
].inq
, igp
, FALSE
);
898 /* keep the data, lose the inetgram */
899 bkmem_free((caddr_t
)igp
,
900 sizeof (struct inetgram
));
903 if (frag_stat
== FRAG_DUP
)
904 printf("ipv4_input(%d): Frag "
907 printf("ipv4_input(%d): too "
908 "many frags\n", index
);
910 #endif /* FRAG_DEBUG */
911 del_gram(&sockets
[index
].inq
, igp
, TRUE
);
917 * Determine if we have all of the fragments.
919 * NOTE: at this point, we've placed the data in the
920 * fragment table, and the inetgram (igp) has been
926 newgp
= make_trans_datagram(index
, NULL
, ipsrc
, ipdst
, iphlen
);
929 add_grams(&ipv4_listp
, newgp
);
932 if (ipv4_listp
== NULL
&& fragments
!= 0) {
933 if (++input_attempts
> FRAG_ATTEMPTS
) {
934 dprintf("ipv4_input(%d): reassembly(%d) timed out in "
935 "%d msecs.\n", index
, fragments
,
936 sockets
[index
].in_timeout
* input_attempts
);
942 * Call the media layer again... there may be more
945 if (sockets
[index
].input
[MEDIA_LVL
](index
) < 0) {
946 /* errno will be set appropriately */
954 add_grams(&sockets
[index
].inq
, ipv4_listp
);
960 * ipv4_output: Generate IPv4 datagram(s) for the payload and deliver them.
961 * Routing is handled here as well, by reusing the saddr field to hold the
962 * router's IP address.
964 * We don't deal with fragmentation on the outgoing side.
966 * Arguments: index to socket, inetgram to send.
968 * Returns: 0 for success, -1 if error occurred.
971 ipv4_output(int index
, struct inetgram
*ogp
)
974 uint64_t iphbuffer
[sizeof (struct ip
)];
977 printf("ipv4_output(%d): size %d\n", index
,
978 ogp
->igm_mp
->b_wptr
- ogp
->igm_mp
->b_rptr
);
981 /* we don't deal (yet) with fragmentation. Maybe never will */
982 if ((ogp
->igm_mp
->b_wptr
- ogp
->igm_mp
->b_rptr
) > mac_get_mtu()) {
983 dprintf("ipv4: datagram too big for MAC layer.\n");
988 if (ogp
->igm_level
!= NETWORK_LVL
) {
990 printf("ipv4_output(%d): unexpected frame type: %d\n", index
,
997 if (sockets
[index
].out_flags
& SO_DONTROUTE
)
998 ogp
->igm_oflags
|= MSG_DONTROUTE
;
1000 iphp
= (struct ip
*)&iphbuffer
;
1001 iphp
->ip_v
= IPVERSION
;
1002 iphp
->ip_hl
= sizeof (struct ip
) / 4;
1004 iphp
->ip_len
= htons(ogp
->igm_mp
->b_wptr
- ogp
->igm_mp
->b_rptr
+
1005 sizeof (struct ip
));
1006 iphp
->ip_id
= htons(++g_ip_id
);
1007 iphp
->ip_off
= htons(IP_DF
);
1008 iphp
->ip_p
= sockets
[index
].proto
;
1009 iphp
->ip_sum
= htons(0);
1013 iphp
->ip_src
= myip
;
1014 iphp
->ip_dst
= ogp
->igm_saddr
.sin_addr
;
1017 * On local / limited broadcasts, don't route. From a purist's
1018 * perspective, we should be setting the TTL to 1. But
1019 * operational experience has shown that some BOOTP relay agents
1020 * (ciscos) discard our packets. Furthermore, these devices also
1021 * *don't* reset the TTL to MAXTTL on the unicast side of the
1022 * BOOTP relay agent! Sigh. Thus to work correctly in these
1023 * environments, we leave the TTL as it has been been set by
1024 * the application layer, and simply don't check for a route.
1026 if (iphp
->ip_dst
.s_addr
== htonl(INADDR_BROADCAST
) ||
1027 (netmask
.s_addr
!= htonl(INADDR_BROADCAST
) &&
1028 iphp
->ip_dst
.s_addr
== (mynet
.s_addr
| ~netmask
.s_addr
))) {
1029 ogp
->igm_oflags
|= MSG_DONTROUTE
;
1032 /* Routing necessary? */
1033 if ((ogp
->igm_oflags
& MSG_DONTROUTE
) == 0 &&
1034 ((iphp
->ip_dst
.s_addr
& netmask
.s_addr
) != mynet
.s_addr
)) {
1035 struct in_addr
*rip
;
1036 if ((rip
= ipv4_get_route(RT_HOST
, &iphp
->ip_dst
,
1038 rip
= ipv4_get_route(RT_DEFAULT
, NULL
, NULL
);
1041 dprintf("ipv4(%d): No route to %s.\n",
1042 index
, inet_ntoa(iphp
->ip_dst
));
1043 errno
= EHOSTUNREACH
;
1046 ogp
->igm_router
.s_addr
= rip
->s_addr
;
1048 ogp
->igm_router
.s_addr
= htonl(INADDR_ANY
);
1050 iphp
->ip_sum
= ipv4cksum((uint16_t *)iphp
, sizeof (struct ip
));
1051 ogp
->igm_mp
->b_rptr
-= sizeof (struct ip
);
1052 bcopy((caddr_t
)iphp
, (caddr_t
)(ogp
->igm_mp
->b_rptr
),
1053 sizeof (struct ip
));
1055 ogp
->igm_level
= MEDIA_LVL
;
1061 * Function to be called by TCP to send out a packet. This is used
1062 * when TCP wants to send out packets which it has already filled in
1063 * most of the header fields.
1066 ipv4_tcp_output(int sock_id
, mblk_t
*pkt
)
1069 struct in_addr
*rip
= NULL
;
1070 struct inetgram datagram
;
1072 iph
= (struct ip
*)pkt
->b_rptr
;
1074 bzero(&datagram
, sizeof (struct inetgram
));
1077 * Bootparams doesn't know about subnet masks, so we need to
1078 * explicitly check for this flag.
1080 if (sockets
[sock_id
].out_flags
& SO_DONTROUTE
)
1081 datagram
.igm_oflags
|= MSG_DONTROUTE
;
1083 /* Routing necessary? */
1084 if (((datagram
.igm_oflags
& MSG_DONTROUTE
) == 0) &&
1085 ((iph
->ip_dst
.s_addr
& netmask
.s_addr
) != mynet
.s_addr
)) {
1086 if ((rip
= ipv4_get_route(RT_HOST
, &iph
->ip_dst
,
1088 rip
= ipv4_get_route(RT_DEFAULT
, NULL
, NULL
);
1091 dprintf("ipv4(%d): No route to %s.\n",
1092 sock_id
, inet_ntoa(iph
->ip_dst
));
1093 errno
= EHOSTUNREACH
;
1098 iph
->ip_id
= htons(++g_ip_id
);
1099 iph
->ip_sum
= ipv4cksum((uint16_t *)iph
, sizeof (struct ip
));
1101 printf("ipv4_tcp_output: dump IP packet(%d)\n", iph
->ip_len
);
1102 hexdump((char *)pkt
->b_rptr
, iph
->ip_len
);
1104 /* Call the MAC layer output routine to send it out. */
1105 datagram
.igm_mp
= pkt
;
1106 datagram
.igm_level
= MEDIA_LVL
;
1108 datagram
.igm_router
.s_addr
= rip
->s_addr
;
1110 datagram
.igm_router
.s_addr
= 0;
1111 return (mac_state
.mac_output(sock_id
, &datagram
));
1115 * Internet address interpretation routine.
1116 * All the network library routines call this
1117 * routine to interpret entries in the data bases
1118 * which are expected to be an address.
1119 * The value returned is in network order.
1122 inet_addr(const char *cp
)
1124 uint32_t val
, base
, n
;
1126 uint32_t parts
[4], *pp
= parts
;
1129 return ((uint32_t)-1); /* disallow null string in cp */
1132 * Collect number up to ``.''.
1133 * Values are specified as for C:
1134 * 0x=hex, 0=octal, other=decimal.
1138 if (*++cp
== 'x' || *cp
== 'X')
1143 while ((c
= *cp
) != NULL
) {
1145 if ((c
- '0') >= base
)
1147 val
= (val
* base
) + (c
- '0');
1151 if (base
== 16 && isxdigit(c
)) {
1152 val
= (val
<< 4) + (c
+ 10 - (islower(c
) ? 'a' : 'A'));
1162 * a.b.c (with c treated as 16-bits)
1163 * a.b (with b treated as 24 bits)
1165 if ((pp
>= parts
+ 3) || (val
> 0xff)) {
1166 return ((uint32_t)-1);
1172 * Check for trailing characters.
1174 if (*cp
&& !isspace(*cp
)) {
1175 return ((uint32_t)-1);
1179 * Concoct the address according to
1180 * the number of parts specified.
1185 case 1: /* a -- 32 bits */
1189 case 2: /* a.b -- 8.24 bits */
1190 if (parts
[1] > 0xffffff)
1191 return ((uint32_t)-1);
1192 val
= (parts
[0] << 24) | (parts
[1] & 0xffffff);
1195 case 3: /* a.b.c -- 8.8.16 bits */
1196 if (parts
[2] > 0xffff)
1197 return ((uint32_t)-1);
1198 val
= (parts
[0] << 24) | ((parts
[1] & 0xff) << 16) |
1199 (parts
[2] & 0xffff);
1202 case 4: /* a.b.c.d -- 8.8.8.8 bits */
1203 if (parts
[3] > 0xff)
1204 return ((uint32_t)-1);
1205 val
= (parts
[0] << 24) | ((parts
[1] & 0xff) << 16) |
1206 ((parts
[2] & 0xff) << 8) | (parts
[3] & 0xff);
1210 return ((uint32_t)-1);
1217 hexdump(char *data
, int datalen
)
1220 ushort_t
*p16
= (ushort_t
*)data
;
1223 int chunk
= 16; /* 16 bytes per line */
1227 for (p
= data
; p
< data
+ datalen
; p
+= chunk
) {
1228 printf("\t%4d: ", (int)(p
- data
));
1229 left
= (data
+ datalen
) - p
;
1230 len
= MIN(chunk
, left
);
1231 for (i
= 0; i
< (len
/ 2); i
++)
1232 printf("%04x ", ntohs(*p16
++) & 0xffff);
1234 printf("%02x ", *((unsigned char *)p16
));
1236 for (i
= 0; i
< (chunk
- left
) / 2; i
++)
1240 for (i
= 0; i
< len
; i
++, p8
++)
1241 printf("%c", isprint(*p8
) ? *p8
: '.');