xref: /titanic_53/usr/src/stand/lib/inet/ipv4.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * ipv4.c, Code implementing the IPv4 internet protocol.
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
32*7c478bd9Sstevel@tonic-gate #include <socket_impl.h>
33*7c478bd9Sstevel@tonic-gate #include <socket_inet.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
36*7c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
37*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
38*7c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
39*7c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
40*7c478bd9Sstevel@tonic-gate #include <net/if_arp.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/promif.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/salib.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate #include "icmp4.h"
47*7c478bd9Sstevel@tonic-gate #include "ipv4.h"
48*7c478bd9Sstevel@tonic-gate #include "ipv4_impl.h"
49*7c478bd9Sstevel@tonic-gate #include "mac.h"
50*7c478bd9Sstevel@tonic-gate #include "mac_impl.h"
51*7c478bd9Sstevel@tonic-gate #include "v4_sum_impl.h"
52*7c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h>
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate static struct ip_frag	fragment[FRAG_MAX];	/* ip fragment buffers */
55*7c478bd9Sstevel@tonic-gate static int		fragments;		/* Number of fragments */
56*7c478bd9Sstevel@tonic-gate static uint8_t		ttl = MAXTTL;		/* IP ttl */
57*7c478bd9Sstevel@tonic-gate static struct in_addr	myip;			/* our network-order IP addr */
58*7c478bd9Sstevel@tonic-gate static struct in_addr	mynet;			/* net-order netaddr */
59*7c478bd9Sstevel@tonic-gate static struct in_addr	netmask =
60*7c478bd9Sstevel@tonic-gate 	{ 0xff, 0xff, 0xff, 0xff };		/* our network-order netmask */
61*7c478bd9Sstevel@tonic-gate static boolean_t	netmask_set = B_FALSE;	/* has anyone set netmask? */
62*7c478bd9Sstevel@tonic-gate static struct in_addr	defaultrouter;		/* net-order defaultrouter */
63*7c478bd9Sstevel@tonic-gate static int		promiscuous;		/* promiscuous mode */
64*7c478bd9Sstevel@tonic-gate static struct routing table[IPV4_ROUTE_TABLE_SIZE];
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate static uint16_t	g_ip_id;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
69*7c478bd9Sstevel@tonic-gate #define	FRAG_DEBUG
70*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG
73*7c478bd9Sstevel@tonic-gate /*
74*7c478bd9Sstevel@tonic-gate  * display the fragment list. For debugging purposes.
75*7c478bd9Sstevel@tonic-gate  */
76*7c478bd9Sstevel@tonic-gate static void
77*7c478bd9Sstevel@tonic-gate frag_disp(uint16_t size)
78*7c478bd9Sstevel@tonic-gate {
79*7c478bd9Sstevel@tonic-gate 	int	i;
80*7c478bd9Sstevel@tonic-gate 	uint_t	total = 0;
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate 	printf("Dumping fragment info: (%d)\n\n", fragments);
83*7c478bd9Sstevel@tonic-gate 	printf("More:\tOffset:\tDatap:\t\tIPid:\t\tIPlen:\tIPhlen:\n");
84*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < FRAG_MAX; i++) {
85*7c478bd9Sstevel@tonic-gate 		if (fragment[i].mp == NULL)
86*7c478bd9Sstevel@tonic-gate 			continue;
87*7c478bd9Sstevel@tonic-gate 		printf("%d\t%d\t0x%x\t%d\t\t%d\t%d\n", fragment[i].more,
88*7c478bd9Sstevel@tonic-gate 		    fragment[i].offset, fragment[i].mp->b_rptr,
89*7c478bd9Sstevel@tonic-gate 		    fragment[i].ipid, fragment[i].iplen, fragment[i].iphlen);
90*7c478bd9Sstevel@tonic-gate 		total += (fragment[i].iplen - fragment[i].iphlen);
91*7c478bd9Sstevel@tonic-gate 	}
92*7c478bd9Sstevel@tonic-gate 	printf("Total length is: %d. It should be: %d\n\n", total, size);
93*7c478bd9Sstevel@tonic-gate }
94*7c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate /*
97*7c478bd9Sstevel@tonic-gate  * This function returns index of fragment 0 of the current fragmented DGRAM
98*7c478bd9Sstevel@tonic-gate  * (which would contain the transport header). Return the fragment number
99*7c478bd9Sstevel@tonic-gate  * for success, -1 if we don't yet have the first fragment.
100*7c478bd9Sstevel@tonic-gate  */
101*7c478bd9Sstevel@tonic-gate static int
102*7c478bd9Sstevel@tonic-gate frag_first(void)
103*7c478bd9Sstevel@tonic-gate {
104*7c478bd9Sstevel@tonic-gate 	int		i;
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	if (fragments == 0)
107*7c478bd9Sstevel@tonic-gate 		return (-1);
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < FRAG_MAX; i++) {
110*7c478bd9Sstevel@tonic-gate 		if (fragment[i].mp != NULL && fragment[i].offset == 0)
111*7c478bd9Sstevel@tonic-gate 			return (i);
112*7c478bd9Sstevel@tonic-gate 	}
113*7c478bd9Sstevel@tonic-gate 	return (-1);
114*7c478bd9Sstevel@tonic-gate }
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate /*
117*7c478bd9Sstevel@tonic-gate  * This function returns index of the last fragment of the current DGRAM.
118*7c478bd9Sstevel@tonic-gate  * Returns the fragment number for success, -1 if we don't yet have the
119*7c478bd9Sstevel@tonic-gate  * last fragment.
120*7c478bd9Sstevel@tonic-gate  */
121*7c478bd9Sstevel@tonic-gate static int
122*7c478bd9Sstevel@tonic-gate frag_last(void)
123*7c478bd9Sstevel@tonic-gate {
124*7c478bd9Sstevel@tonic-gate 	int		i;
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	if (fragments == 0)
127*7c478bd9Sstevel@tonic-gate 		return (-1);
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < FRAG_MAX; i++) {
130*7c478bd9Sstevel@tonic-gate 		if (fragment[i].mp != NULL && !fragment[i].more)
131*7c478bd9Sstevel@tonic-gate 			return (i);
132*7c478bd9Sstevel@tonic-gate 	}
133*7c478bd9Sstevel@tonic-gate 	return (-1);
134*7c478bd9Sstevel@tonic-gate }
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate /*
137*7c478bd9Sstevel@tonic-gate  * This function adds a fragment to the current pkt fragment list. Returns
138*7c478bd9Sstevel@tonic-gate  * FRAG_NOSLOTS if there are no more slots, FRAG_DUP if the fragment is
139*7c478bd9Sstevel@tonic-gate  * a duplicate, or FRAG_SUCCESS if it is successful.
140*7c478bd9Sstevel@tonic-gate  */
141*7c478bd9Sstevel@tonic-gate static int
142*7c478bd9Sstevel@tonic-gate frag_add(int16_t offset, mblk_t *mp, uint16_t ipid,
143*7c478bd9Sstevel@tonic-gate     int16_t iplen, int16_t iphlen, uint8_t ipp)
144*7c478bd9Sstevel@tonic-gate {
145*7c478bd9Sstevel@tonic-gate 	int	i;
146*7c478bd9Sstevel@tonic-gate 	int16_t	true_offset = IPV4_OFFSET(offset);
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	/* first pass - look for duplicates */
149*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < FRAG_MAX; i++) {
150*7c478bd9Sstevel@tonic-gate 		if (fragment[i].mp != NULL &&
151*7c478bd9Sstevel@tonic-gate 		    fragment[i].offset == true_offset)
152*7c478bd9Sstevel@tonic-gate 			return (FRAG_DUP);
153*7c478bd9Sstevel@tonic-gate 	}
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	/* second pass - fill in empty slot */
156*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < FRAG_MAX; i++) {
157*7c478bd9Sstevel@tonic-gate 		if (fragment[i].mp == NULL) {
158*7c478bd9Sstevel@tonic-gate 			fragment[i].more = (offset & IP_MF);
159*7c478bd9Sstevel@tonic-gate 			fragment[i].offset = true_offset;
160*7c478bd9Sstevel@tonic-gate 			fragment[i].mp = mp;
161*7c478bd9Sstevel@tonic-gate 			fragment[i].ipid = ipid;
162*7c478bd9Sstevel@tonic-gate 			fragment[i].iplen = iplen;
163*7c478bd9Sstevel@tonic-gate 			fragment[i].iphlen = iphlen;
164*7c478bd9Sstevel@tonic-gate 			fragment[i].ipp = ipp;
165*7c478bd9Sstevel@tonic-gate 			fragments++;
166*7c478bd9Sstevel@tonic-gate 			return (FRAG_SUCCESS);
167*7c478bd9Sstevel@tonic-gate 		}
168*7c478bd9Sstevel@tonic-gate 	}
169*7c478bd9Sstevel@tonic-gate 	return (FRAG_NOSLOTS);
170*7c478bd9Sstevel@tonic-gate }
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate /*
173*7c478bd9Sstevel@tonic-gate  * Nuke a fragment.
174*7c478bd9Sstevel@tonic-gate  */
175*7c478bd9Sstevel@tonic-gate static void
176*7c478bd9Sstevel@tonic-gate frag_free(int index)
177*7c478bd9Sstevel@tonic-gate {
178*7c478bd9Sstevel@tonic-gate 	if (fragment[index].mp != NULL) {
179*7c478bd9Sstevel@tonic-gate 		freeb(fragment[index].mp);
180*7c478bd9Sstevel@tonic-gate 		fragments--;
181*7c478bd9Sstevel@tonic-gate 	}
182*7c478bd9Sstevel@tonic-gate 	bzero((caddr_t)&fragment[index], sizeof (struct ip_frag));
183*7c478bd9Sstevel@tonic-gate }
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate /*
186*7c478bd9Sstevel@tonic-gate  * zero the frag list.
187*7c478bd9Sstevel@tonic-gate  */
188*7c478bd9Sstevel@tonic-gate static void
189*7c478bd9Sstevel@tonic-gate frag_flush(void)
190*7c478bd9Sstevel@tonic-gate {
191*7c478bd9Sstevel@tonic-gate 	int i;
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < FRAG_MAX; i++)
194*7c478bd9Sstevel@tonic-gate 		frag_free(i);
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	fragments = 0;
197*7c478bd9Sstevel@tonic-gate }
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate /*
200*7c478bd9Sstevel@tonic-gate  * Analyze the fragment list - see if we captured all our fragments.
201*7c478bd9Sstevel@tonic-gate  *
202*7c478bd9Sstevel@tonic-gate  * Returns TRUE if we've got all the fragments, and FALSE if we don't.
203*7c478bd9Sstevel@tonic-gate  */
204*7c478bd9Sstevel@tonic-gate static int
205*7c478bd9Sstevel@tonic-gate frag_chk(void)
206*7c478bd9Sstevel@tonic-gate {
207*7c478bd9Sstevel@tonic-gate 	int		i, first_frag, last_frag;
208*7c478bd9Sstevel@tonic-gate 	int16_t		actual, total;
209*7c478bd9Sstevel@tonic-gate 	uint16_t	ip_id;
210*7c478bd9Sstevel@tonic-gate 	uint8_t		ipp;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	if (fragments == 0 || (first_frag = frag_first()) < 0 ||
213*7c478bd9Sstevel@tonic-gate 	    (last_frag = frag_last()) < 0)
214*7c478bd9Sstevel@tonic-gate 		return (FALSE);
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	/*
217*7c478bd9Sstevel@tonic-gate 	 * Validate the ipid's of our fragments - nuke those that don't
218*7c478bd9Sstevel@tonic-gate 	 * match the id of the first fragment or don't match the IP
219*7c478bd9Sstevel@tonic-gate 	 * protocol of the first fragment.
220*7c478bd9Sstevel@tonic-gate 	 */
221*7c478bd9Sstevel@tonic-gate 	ip_id = fragment[first_frag].ipid;
222*7c478bd9Sstevel@tonic-gate 	ipp = fragment[first_frag].ipp;
223*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < FRAG_MAX; i++) {
224*7c478bd9Sstevel@tonic-gate 		if (fragment[i].mp != NULL && ip_id != fragment[i].ipid &&
225*7c478bd9Sstevel@tonic-gate 			fragment[i].ipp != ipp) {
226*7c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG
227*7c478bd9Sstevel@tonic-gate 			printf("ipv4: Frag id mismatch: %x != %x\n",
228*7c478bd9Sstevel@tonic-gate 			    fragment[i].ipid, ip_id);
229*7c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */
230*7c478bd9Sstevel@tonic-gate 			frag_free(i);
231*7c478bd9Sstevel@tonic-gate 		}
232*7c478bd9Sstevel@tonic-gate 	}
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 	if (frag_last() < 0)
235*7c478bd9Sstevel@tonic-gate 		return (FALSE);
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	total = fragment[last_frag].offset + fragment[last_frag].iplen -
238*7c478bd9Sstevel@tonic-gate 	    fragment[last_frag].iphlen;
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	for (i = 0, actual = 0; i < FRAG_MAX; i++)
241*7c478bd9Sstevel@tonic-gate 		actual += (fragment[i].iplen - fragment[i].iphlen);
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate #ifdef FRAG_DEBUG
244*7c478bd9Sstevel@tonic-gate 	frag_disp(total);
245*7c478bd9Sstevel@tonic-gate #endif /* FRAG_DEBUG */
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	return (total == actual);
248*7c478bd9Sstevel@tonic-gate }
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate /*
251*7c478bd9Sstevel@tonic-gate  * Load the assembled fragments into igp. Returns 0 for success, nonzero
252*7c478bd9Sstevel@tonic-gate  * otherwise.
253*7c478bd9Sstevel@tonic-gate  */
254*7c478bd9Sstevel@tonic-gate static int
255*7c478bd9Sstevel@tonic-gate frag_load(struct inetgram *igp)
256*7c478bd9Sstevel@tonic-gate {
257*7c478bd9Sstevel@tonic-gate 	int	i;
258*7c478bd9Sstevel@tonic-gate 	int16_t	len;
259*7c478bd9Sstevel@tonic-gate 	uint_t	total_len;
260*7c478bd9Sstevel@tonic-gate 	boolean_t first_frag = B_FALSE;
261*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
262*7c478bd9Sstevel@tonic-gate 	struct ip *iph;
263*7c478bd9Sstevel@tonic-gate 	int first_iph_len;
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	if (fragments == 0)
266*7c478bd9Sstevel@tonic-gate 		return (ENOENT);
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	mp = igp->igm_mp;
269*7c478bd9Sstevel@tonic-gate 	/* Get the IP header length of the first fragment. */
270*7c478bd9Sstevel@tonic-gate 	i = frag_first();
271*7c478bd9Sstevel@tonic-gate 	assert(i >= 0);
272*7c478bd9Sstevel@tonic-gate 	first_iph_len = fragment[i].iphlen;
273*7c478bd9Sstevel@tonic-gate 	for (i = 0, len = 0, total_len = 0; i < FRAG_MAX; i++) {
274*7c478bd9Sstevel@tonic-gate 		if (fragment[i].mp != NULL) {
275*7c478bd9Sstevel@tonic-gate 			/*
276*7c478bd9Sstevel@tonic-gate 			 * Copy just the data (omit the ip header of all
277*7c478bd9Sstevel@tonic-gate 			 * fragments except the first one which contains
278*7c478bd9Sstevel@tonic-gate 			 * all the info...)
279*7c478bd9Sstevel@tonic-gate 			 */
280*7c478bd9Sstevel@tonic-gate 			if (fragment[i].offset == 0) {
281*7c478bd9Sstevel@tonic-gate 				len = fragment[i].iplen;
282*7c478bd9Sstevel@tonic-gate 				first_frag = B_TRUE;
283*7c478bd9Sstevel@tonic-gate 			} else {
284*7c478bd9Sstevel@tonic-gate 				len = fragment[i].iplen - fragment[i].iphlen;
285*7c478bd9Sstevel@tonic-gate 			}
286*7c478bd9Sstevel@tonic-gate 			total_len += len;
287*7c478bd9Sstevel@tonic-gate 			if (total_len > mp->b_size)
288*7c478bd9Sstevel@tonic-gate 				return (E2BIG);
289*7c478bd9Sstevel@tonic-gate 			if (first_frag) {
290*7c478bd9Sstevel@tonic-gate 				bcopy((caddr_t)(fragment[i].mp->b_rptr),
291*7c478bd9Sstevel@tonic-gate 				    (caddr_t)mp->b_rptr, len);
292*7c478bd9Sstevel@tonic-gate 				first_frag = B_FALSE;
293*7c478bd9Sstevel@tonic-gate 			} else {
294*7c478bd9Sstevel@tonic-gate 				bcopy((caddr_t)(fragment[i].mp->b_rptr +
295*7c478bd9Sstevel@tonic-gate 				    fragment[i].iphlen),
296*7c478bd9Sstevel@tonic-gate 				    (caddr_t)(mp->b_rptr + first_iph_len +
297*7c478bd9Sstevel@tonic-gate 				    fragment[i].offset), len);
298*7c478bd9Sstevel@tonic-gate 			}
299*7c478bd9Sstevel@tonic-gate 			mp->b_wptr += len;
300*7c478bd9Sstevel@tonic-gate 		}
301*7c478bd9Sstevel@tonic-gate 	}
302*7c478bd9Sstevel@tonic-gate 	/* Fix the total length in the IP header. */
303*7c478bd9Sstevel@tonic-gate 	iph = (struct ip *)mp->b_rptr;
304*7c478bd9Sstevel@tonic-gate 	iph->ip_len = htons(total_len);
305*7c478bd9Sstevel@tonic-gate 	return (0);
306*7c478bd9Sstevel@tonic-gate }
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate /*
309*7c478bd9Sstevel@tonic-gate  * Locate a routing table entry based upon arguments. IP addresses expected
310*7c478bd9Sstevel@tonic-gate  * in network order. Returns index for success, -1 if entry not found.
311*7c478bd9Sstevel@tonic-gate  */
312*7c478bd9Sstevel@tonic-gate static int
313*7c478bd9Sstevel@tonic-gate find_route(uint8_t *flagp, struct in_addr *destp, struct in_addr *gatewayp)
314*7c478bd9Sstevel@tonic-gate {
315*7c478bd9Sstevel@tonic-gate 	int i, table_entry = -1;
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	for (i = 0; table_entry == -1 && i < IPV4_ROUTE_TABLE_SIZE; i++) {
318*7c478bd9Sstevel@tonic-gate 		if (flagp != NULL) {
319*7c478bd9Sstevel@tonic-gate 			if (*flagp & table[i].flag)
320*7c478bd9Sstevel@tonic-gate 				table_entry = i;
321*7c478bd9Sstevel@tonic-gate 		}
322*7c478bd9Sstevel@tonic-gate 		if (destp != NULL) {
323*7c478bd9Sstevel@tonic-gate 			if (destp->s_addr == table[i].dest.s_addr)
324*7c478bd9Sstevel@tonic-gate 				table_entry = i;
325*7c478bd9Sstevel@tonic-gate 			else
326*7c478bd9Sstevel@tonic-gate 				table_entry = -1;
327*7c478bd9Sstevel@tonic-gate 		}
328*7c478bd9Sstevel@tonic-gate 		if (gatewayp != NULL) {
329*7c478bd9Sstevel@tonic-gate 			if (gatewayp->s_addr == table[i].gateway.s_addr)
330*7c478bd9Sstevel@tonic-gate 				table_entry = i;
331*7c478bd9Sstevel@tonic-gate 			else
332*7c478bd9Sstevel@tonic-gate 				table_entry = -1;
333*7c478bd9Sstevel@tonic-gate 		}
334*7c478bd9Sstevel@tonic-gate 	}
335*7c478bd9Sstevel@tonic-gate 	return (table_entry);
336*7c478bd9Sstevel@tonic-gate }
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate /*
339*7c478bd9Sstevel@tonic-gate  * ADD or DEL a routing table entry. Returns 0 for success, -1 and errno
340*7c478bd9Sstevel@tonic-gate  * otherwise. IP addresses are expected in network order.
341*7c478bd9Sstevel@tonic-gate  */
342*7c478bd9Sstevel@tonic-gate int
343*7c478bd9Sstevel@tonic-gate ipv4_route(int cmd, uint8_t flag, struct in_addr *destp,
344*7c478bd9Sstevel@tonic-gate     struct in_addr *gatewayp)
345*7c478bd9Sstevel@tonic-gate {
346*7c478bd9Sstevel@tonic-gate 	static	int	routing_table_initialized;
347*7c478bd9Sstevel@tonic-gate 	int		index;
348*7c478bd9Sstevel@tonic-gate 	uint8_t 	tmp_flag;
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	if (gatewayp == NULL) {
351*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
352*7c478bd9Sstevel@tonic-gate 		return (-1);
353*7c478bd9Sstevel@tonic-gate 	}
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	/* initialize routing table */
356*7c478bd9Sstevel@tonic-gate 	if (routing_table_initialized == 0) {
357*7c478bd9Sstevel@tonic-gate 		for (index = 0; index < IPV4_ROUTE_TABLE_SIZE; index++)
358*7c478bd9Sstevel@tonic-gate 			table[index].flag = RT_UNUSED;
359*7c478bd9Sstevel@tonic-gate 		routing_table_initialized = 1;
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
363*7c478bd9Sstevel@tonic-gate 	case IPV4_ADD_ROUTE:
364*7c478bd9Sstevel@tonic-gate 		tmp_flag = (uint8_t)RT_UNUSED;
365*7c478bd9Sstevel@tonic-gate 		if ((index = find_route(&tmp_flag, NULL, NULL)) == -1) {
366*7c478bd9Sstevel@tonic-gate 			dprintf("ipv4_route: routing table full.\n");
367*7c478bd9Sstevel@tonic-gate 			errno = ENOSPC;
368*7c478bd9Sstevel@tonic-gate 			return (-1);
369*7c478bd9Sstevel@tonic-gate 		}
370*7c478bd9Sstevel@tonic-gate 		table[index].flag = flag;
371*7c478bd9Sstevel@tonic-gate 		if (destp != NULL)
372*7c478bd9Sstevel@tonic-gate 			table[index].dest.s_addr = destp->s_addr;
373*7c478bd9Sstevel@tonic-gate 		else
374*7c478bd9Sstevel@tonic-gate 			table[index].dest.s_addr = htonl(INADDR_ANY);
375*7c478bd9Sstevel@tonic-gate 		table[index].gateway.s_addr = gatewayp->s_addr;
376*7c478bd9Sstevel@tonic-gate 		break;
377*7c478bd9Sstevel@tonic-gate 	case IPV4_BAD_ROUTE:
378*7c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
379*7c478bd9Sstevel@tonic-gate 	case IPV4_DEL_ROUTE:
380*7c478bd9Sstevel@tonic-gate 		if ((index = find_route(&flag, destp, gatewayp)) == -1) {
381*7c478bd9Sstevel@tonic-gate 			dprintf("ipv4_route: No such routing entry.\n");
382*7c478bd9Sstevel@tonic-gate 			errno = ENOENT;
383*7c478bd9Sstevel@tonic-gate 			return (-1);
384*7c478bd9Sstevel@tonic-gate 		}
385*7c478bd9Sstevel@tonic-gate 		if (cmd == IPV4_DEL_ROUTE) {
386*7c478bd9Sstevel@tonic-gate 			table[index].flag = RT_UNUSED;
387*7c478bd9Sstevel@tonic-gate 			table[index].dest.s_addr = htonl(INADDR_ANY);
388*7c478bd9Sstevel@tonic-gate 			table[index].gateway.s_addr = htonl(INADDR_ANY);
389*7c478bd9Sstevel@tonic-gate 		} else
390*7c478bd9Sstevel@tonic-gate 			table[index].flag = RT_NG;
391*7c478bd9Sstevel@tonic-gate 	default:
392*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
393*7c478bd9Sstevel@tonic-gate 		return (-1);
394*7c478bd9Sstevel@tonic-gate 	}
395*7c478bd9Sstevel@tonic-gate 	return (0);
396*7c478bd9Sstevel@tonic-gate }
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate /*
399*7c478bd9Sstevel@tonic-gate  * Return gateway to destination. Returns gateway IP address in network order
400*7c478bd9Sstevel@tonic-gate  * for success, NULL if no route to destination exists.
401*7c478bd9Sstevel@tonic-gate  */
402*7c478bd9Sstevel@tonic-gate struct in_addr *
403*7c478bd9Sstevel@tonic-gate ipv4_get_route(uint8_t flag, struct in_addr *destp, struct in_addr *gatewayp)
404*7c478bd9Sstevel@tonic-gate {
405*7c478bd9Sstevel@tonic-gate 	int index;
406*7c478bd9Sstevel@tonic-gate 	if ((index = find_route(&flag, destp, gatewayp)) == -1)
407*7c478bd9Sstevel@tonic-gate 		return (NULL);
408*7c478bd9Sstevel@tonic-gate 	return (&table[index].gateway);
409*7c478bd9Sstevel@tonic-gate }
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate /*
412*7c478bd9Sstevel@tonic-gate  * Initialize the IPv4 generic parts of the socket, as well as the routing
413*7c478bd9Sstevel@tonic-gate  * table.
414*7c478bd9Sstevel@tonic-gate  */
415*7c478bd9Sstevel@tonic-gate void
416*7c478bd9Sstevel@tonic-gate ipv4_socket_init(struct inetboot_socket *isp)
417*7c478bd9Sstevel@tonic-gate {
418*7c478bd9Sstevel@tonic-gate 	isp->input[NETWORK_LVL] = ipv4_input;
419*7c478bd9Sstevel@tonic-gate 	isp->output[NETWORK_LVL] = ipv4_output;
420*7c478bd9Sstevel@tonic-gate 	isp->close[NETWORK_LVL] = NULL;
421*7c478bd9Sstevel@tonic-gate 	isp->headerlen[NETWORK_LVL] = ipv4_header_len;
422*7c478bd9Sstevel@tonic-gate }
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate /*
425*7c478bd9Sstevel@tonic-gate  * Initialize a raw ipv4 socket.
426*7c478bd9Sstevel@tonic-gate  */
427*7c478bd9Sstevel@tonic-gate void
428*7c478bd9Sstevel@tonic-gate ipv4_raw_socket(struct inetboot_socket *isp, uint8_t proto)
429*7c478bd9Sstevel@tonic-gate {
430*7c478bd9Sstevel@tonic-gate 	isp->type = INETBOOT_RAW;
431*7c478bd9Sstevel@tonic-gate 	if (proto == 0)
432*7c478bd9Sstevel@tonic-gate 		isp->proto = IPPROTO_IP;
433*7c478bd9Sstevel@tonic-gate 	else
434*7c478bd9Sstevel@tonic-gate 		isp->proto = proto;
435*7c478bd9Sstevel@tonic-gate 	isp->input[TRANSPORT_LVL] = NULL;
436*7c478bd9Sstevel@tonic-gate 	isp->output[TRANSPORT_LVL] = NULL;
437*7c478bd9Sstevel@tonic-gate 	isp->headerlen[TRANSPORT_LVL] = NULL;
438*7c478bd9Sstevel@tonic-gate 	isp->ports = NULL;
439*7c478bd9Sstevel@tonic-gate }
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate /*
442*7c478bd9Sstevel@tonic-gate  * Return the size of an IPv4 header (no options)
443*7c478bd9Sstevel@tonic-gate  */
444*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
445*7c478bd9Sstevel@tonic-gate int
446*7c478bd9Sstevel@tonic-gate ipv4_header_len(struct inetgram *igm)
447*7c478bd9Sstevel@tonic-gate {
448*7c478bd9Sstevel@tonic-gate 	return (sizeof (struct ip));
449*7c478bd9Sstevel@tonic-gate }
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate /*
452*7c478bd9Sstevel@tonic-gate  * Set our source address.
453*7c478bd9Sstevel@tonic-gate  * Argument is assumed to be host order.
454*7c478bd9Sstevel@tonic-gate  */
455*7c478bd9Sstevel@tonic-gate void
456*7c478bd9Sstevel@tonic-gate ipv4_setipaddr(struct in_addr *ip)
457*7c478bd9Sstevel@tonic-gate {
458*7c478bd9Sstevel@tonic-gate 	myip.s_addr = htonl(ip->s_addr);
459*7c478bd9Sstevel@tonic-gate }
460*7c478bd9Sstevel@tonic-gate 
461*7c478bd9Sstevel@tonic-gate /*
462*7c478bd9Sstevel@tonic-gate  * Returns our current source address in host order.
463*7c478bd9Sstevel@tonic-gate  */
464*7c478bd9Sstevel@tonic-gate void
465*7c478bd9Sstevel@tonic-gate ipv4_getipaddr(struct in_addr *ip)
466*7c478bd9Sstevel@tonic-gate {
467*7c478bd9Sstevel@tonic-gate 	ip->s_addr = ntohl(myip.s_addr);
468*7c478bd9Sstevel@tonic-gate }
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate /*
471*7c478bd9Sstevel@tonic-gate  * Set our netmask.
472*7c478bd9Sstevel@tonic-gate  * Argument is assumed to be host order.
473*7c478bd9Sstevel@tonic-gate  */
474*7c478bd9Sstevel@tonic-gate void
475*7c478bd9Sstevel@tonic-gate ipv4_setnetmask(struct in_addr *ip)
476*7c478bd9Sstevel@tonic-gate {
477*7c478bd9Sstevel@tonic-gate 	netmask_set = B_TRUE;
478*7c478bd9Sstevel@tonic-gate 	netmask.s_addr = htonl(ip->s_addr);
479*7c478bd9Sstevel@tonic-gate 	mynet.s_addr = netmask.s_addr & myip.s_addr; /* implicit */
480*7c478bd9Sstevel@tonic-gate }
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate void
483*7c478bd9Sstevel@tonic-gate ipv4_getnetid(struct in_addr *my_netid)
484*7c478bd9Sstevel@tonic-gate {
485*7c478bd9Sstevel@tonic-gate 	struct in_addr my_netmask;
486*7c478bd9Sstevel@tonic-gate 	if (mynet.s_addr != 0)
487*7c478bd9Sstevel@tonic-gate 		my_netid->s_addr = ntohl(mynet.s_addr);
488*7c478bd9Sstevel@tonic-gate 	else {
489*7c478bd9Sstevel@tonic-gate 		ipv4_getnetmask(&my_netmask);
490*7c478bd9Sstevel@tonic-gate 		my_netid->s_addr = my_netmask.s_addr & ntohl(myip.s_addr);
491*7c478bd9Sstevel@tonic-gate 	}
492*7c478bd9Sstevel@tonic-gate }
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate /*
495*7c478bd9Sstevel@tonic-gate  * Returns our current netmask in host order.
496*7c478bd9Sstevel@tonic-gate  * Neither OBP nor the standalone DHCP client mandate
497*7c478bd9Sstevel@tonic-gate  * that the netmask be specified, so in the absence of
498*7c478bd9Sstevel@tonic-gate  * a netmask, we attempt to derive it using class-based
499*7c478bd9Sstevel@tonic-gate  * heuristics.
500*7c478bd9Sstevel@tonic-gate  */
501*7c478bd9Sstevel@tonic-gate void
502*7c478bd9Sstevel@tonic-gate ipv4_getnetmask(struct in_addr *ip)
503*7c478bd9Sstevel@tonic-gate {
504*7c478bd9Sstevel@tonic-gate 	if (netmask_set || (myip.s_addr == 0))
505*7c478bd9Sstevel@tonic-gate 		ip->s_addr = ntohl(netmask.s_addr);
506*7c478bd9Sstevel@tonic-gate 	else {
507*7c478bd9Sstevel@tonic-gate 		/* base the netmask on our IP address */
508*7c478bd9Sstevel@tonic-gate 		if (IN_CLASSA(ntohl(myip.s_addr)))
509*7c478bd9Sstevel@tonic-gate 			ip->s_addr = ntohl(IN_CLASSA_NET);
510*7c478bd9Sstevel@tonic-gate 		else if (IN_CLASSB(ntohl(myip.s_addr)))
511*7c478bd9Sstevel@tonic-gate 			ip->s_addr = ntohl(IN_CLASSB_NET);
512*7c478bd9Sstevel@tonic-gate 		else
513*7c478bd9Sstevel@tonic-gate 			ip->s_addr = ntohl(IN_CLASSC_NET);
514*7c478bd9Sstevel@tonic-gate 	}
515*7c478bd9Sstevel@tonic-gate }
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate /*
518*7c478bd9Sstevel@tonic-gate  * Set our default router.
519*7c478bd9Sstevel@tonic-gate  * Argument is assumed to be host order, and *MUST* be on the same network
520*7c478bd9Sstevel@tonic-gate  * as our source IP address.
521*7c478bd9Sstevel@tonic-gate  */
522*7c478bd9Sstevel@tonic-gate void
523*7c478bd9Sstevel@tonic-gate ipv4_setdefaultrouter(struct in_addr *ip)
524*7c478bd9Sstevel@tonic-gate {
525*7c478bd9Sstevel@tonic-gate 	defaultrouter.s_addr = htonl(ip->s_addr);
526*7c478bd9Sstevel@tonic-gate }
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate /*
529*7c478bd9Sstevel@tonic-gate  * Returns our current default router in host order.
530*7c478bd9Sstevel@tonic-gate  */
531*7c478bd9Sstevel@tonic-gate void
532*7c478bd9Sstevel@tonic-gate ipv4_getdefaultrouter(struct in_addr *ip)
533*7c478bd9Sstevel@tonic-gate {
534*7c478bd9Sstevel@tonic-gate 	ip->s_addr = ntohl(defaultrouter.s_addr);
535*7c478bd9Sstevel@tonic-gate }
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate /*
538*7c478bd9Sstevel@tonic-gate  * Toggle promiscuous flag. If set, client disregards destination IP
539*7c478bd9Sstevel@tonic-gate  * address. Otherwise, only limited broadcast, network broadcast, and
540*7c478bd9Sstevel@tonic-gate  * unicast traffic get through. Returns previous setting.
541*7c478bd9Sstevel@tonic-gate  */
542*7c478bd9Sstevel@tonic-gate int
543*7c478bd9Sstevel@tonic-gate ipv4_setpromiscuous(int toggle)
544*7c478bd9Sstevel@tonic-gate {
545*7c478bd9Sstevel@tonic-gate 	int old = promiscuous;
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	promiscuous = toggle;
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 	return (old);
550*7c478bd9Sstevel@tonic-gate }
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate /*
553*7c478bd9Sstevel@tonic-gate  * Set IP TTL.
554*7c478bd9Sstevel@tonic-gate  */
555*7c478bd9Sstevel@tonic-gate void
556*7c478bd9Sstevel@tonic-gate ipv4_setmaxttl(uint8_t cttl)
557*7c478bd9Sstevel@tonic-gate {
558*7c478bd9Sstevel@tonic-gate 	ttl = cttl;
559*7c478bd9Sstevel@tonic-gate }
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate /*
562*7c478bd9Sstevel@tonic-gate  * Convert an ipv4 address to dotted notation.
563*7c478bd9Sstevel@tonic-gate  * Returns ptr to statically allocated buffer containing dotted string.
564*7c478bd9Sstevel@tonic-gate  */
565*7c478bd9Sstevel@tonic-gate char *
566*7c478bd9Sstevel@tonic-gate inet_ntoa(struct in_addr ip)
567*7c478bd9Sstevel@tonic-gate {
568*7c478bd9Sstevel@tonic-gate 	uint8_t *p;
569*7c478bd9Sstevel@tonic-gate 	static char ipaddr[16];
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	p = (uint8_t *)&ip.s_addr;
572*7c478bd9Sstevel@tonic-gate 	(void) sprintf(ipaddr, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
573*7c478bd9Sstevel@tonic-gate 	return (ipaddr);
574*7c478bd9Sstevel@tonic-gate }
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate /*
577*7c478bd9Sstevel@tonic-gate  * Construct a transport datagram from a series of IP fragments (igp == NULL)
578*7c478bd9Sstevel@tonic-gate  * or from a single IP datagram (igp != NULL). Return the address of the
579*7c478bd9Sstevel@tonic-gate  * contructed transport datagram.
580*7c478bd9Sstevel@tonic-gate  */
581*7c478bd9Sstevel@tonic-gate struct inetgram *
582*7c478bd9Sstevel@tonic-gate make_trans_datagram(int index, struct inetgram *igp, struct in_addr ipsrc,
583*7c478bd9Sstevel@tonic-gate     struct in_addr ipdst, uint16_t iphlen)
584*7c478bd9Sstevel@tonic-gate {
585*7c478bd9Sstevel@tonic-gate 	uint16_t	trans_len, *transp, new_len;
586*7c478bd9Sstevel@tonic-gate 	int		first_frag, last_frag;
587*7c478bd9Sstevel@tonic-gate 	boolean_t	fragmented;
588*7c478bd9Sstevel@tonic-gate 	struct inetgram	*ngp;
589*7c478bd9Sstevel@tonic-gate 	struct ip	*iph;
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate 	fragmented = (igp == NULL);
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 	ngp = (struct inetgram *)bkmem_zalloc(sizeof (struct inetgram));
594*7c478bd9Sstevel@tonic-gate 	if (ngp == NULL) {
595*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
596*7c478bd9Sstevel@tonic-gate 		if (fragmented)
597*7c478bd9Sstevel@tonic-gate 			frag_flush();
598*7c478bd9Sstevel@tonic-gate 		return (NULL);
599*7c478bd9Sstevel@tonic-gate 	}
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate 	if (fragmented) {
602*7c478bd9Sstevel@tonic-gate 		last_frag = frag_last();
603*7c478bd9Sstevel@tonic-gate 		trans_len = fragment[last_frag].offset +
604*7c478bd9Sstevel@tonic-gate 		    fragment[last_frag].iplen - fragment[last_frag].iphlen;
605*7c478bd9Sstevel@tonic-gate 		first_frag = frag_first();
606*7c478bd9Sstevel@tonic-gate 		/*
607*7c478bd9Sstevel@tonic-gate 		 * The returned buffer contains the IP header of the
608*7c478bd9Sstevel@tonic-gate 		 * first fragment.
609*7c478bd9Sstevel@tonic-gate 		 */
610*7c478bd9Sstevel@tonic-gate 		trans_len += fragment[first_frag].iphlen;
611*7c478bd9Sstevel@tonic-gate 		transp = (uint16_t *)(fragment[first_frag].mp->b_rptr +
612*7c478bd9Sstevel@tonic-gate 		    fragment[first_frag].iphlen);
613*7c478bd9Sstevel@tonic-gate 	} else {
614*7c478bd9Sstevel@tonic-gate 		/*
615*7c478bd9Sstevel@tonic-gate 		 * Note that igm_len may not be the real length of an
616*7c478bd9Sstevel@tonic-gate 		 * IP packet because some network interface, such as
617*7c478bd9Sstevel@tonic-gate 		 * Ethernet, as a minimum frame size.  So we should not
618*7c478bd9Sstevel@tonic-gate 		 * use the interface frame size to determine the
619*7c478bd9Sstevel@tonic-gate 		 * length of an IP packet.  We should use the IP
620*7c478bd9Sstevel@tonic-gate 		 * length field in the IP header.
621*7c478bd9Sstevel@tonic-gate 		 */
622*7c478bd9Sstevel@tonic-gate 		iph = (struct ip *)igp->igm_mp->b_rptr;
623*7c478bd9Sstevel@tonic-gate 		trans_len = ntohs(iph->ip_len);
624*7c478bd9Sstevel@tonic-gate 		transp = (uint16_t *)(igp->igm_mp->b_rptr + iphlen);
625*7c478bd9Sstevel@tonic-gate 	}
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate 	ngp->igm_saddr.sin_addr.s_addr = ipsrc.s_addr;
628*7c478bd9Sstevel@tonic-gate 	ngp->igm_saddr.sin_port = sockets[index].ports(transp, SOURCE);
629*7c478bd9Sstevel@tonic-gate 	ngp->igm_target.s_addr = ipdst.s_addr;
630*7c478bd9Sstevel@tonic-gate 	ngp->igm_level = TRANSPORT_LVL;
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	/*
633*7c478bd9Sstevel@tonic-gate 	 * Align to 16bit value.  Checksum code may require an extra byte
634*7c478bd9Sstevel@tonic-gate 	 * for padding.
635*7c478bd9Sstevel@tonic-gate 	 */
636*7c478bd9Sstevel@tonic-gate 	new_len = ((trans_len + sizeof (int16_t) - 1) &
637*7c478bd9Sstevel@tonic-gate 	    ~(sizeof (int16_t) - 1));
638*7c478bd9Sstevel@tonic-gate 	if ((ngp->igm_mp = allocb(new_len, 0)) == NULL) {
639*7c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
640*7c478bd9Sstevel@tonic-gate 		bkmem_free((caddr_t)ngp, sizeof (struct inetgram));
641*7c478bd9Sstevel@tonic-gate 		if (fragmented)
642*7c478bd9Sstevel@tonic-gate 			frag_flush();
643*7c478bd9Sstevel@tonic-gate 		return (NULL);
644*7c478bd9Sstevel@tonic-gate 	}
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate 	if (fragmented) {
647*7c478bd9Sstevel@tonic-gate 		if (frag_load(ngp) != 0) {
648*7c478bd9Sstevel@tonic-gate 			freeb(ngp->igm_mp);
649*7c478bd9Sstevel@tonic-gate 			bkmem_free((caddr_t)ngp, sizeof (struct inetgram));
650*7c478bd9Sstevel@tonic-gate 			frag_flush();
651*7c478bd9Sstevel@tonic-gate 			return (NULL);
652*7c478bd9Sstevel@tonic-gate 		}
653*7c478bd9Sstevel@tonic-gate 		frag_flush();
654*7c478bd9Sstevel@tonic-gate 	} else {
655*7c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)(igp->igm_mp->b_rptr),
656*7c478bd9Sstevel@tonic-gate 		    (caddr_t)ngp->igm_mp->b_rptr, trans_len);
657*7c478bd9Sstevel@tonic-gate 		ngp->igm_mp->b_wptr += trans_len;
658*7c478bd9Sstevel@tonic-gate 	}
659*7c478bd9Sstevel@tonic-gate 	return (ngp);
660*7c478bd9Sstevel@tonic-gate }
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate /*
663*7c478bd9Sstevel@tonic-gate  * ipv4_input: Pull in IPv4 datagrams addressed to us. Handle IP fragmentation
664*7c478bd9Sstevel@tonic-gate  * (fragments received in any order) and ICMP at this level.
665*7c478bd9Sstevel@tonic-gate  *
666*7c478bd9Sstevel@tonic-gate  * Note that because our network is serviced by polling when we expect
667*7c478bd9Sstevel@tonic-gate  * something (upon a referenced socket), we don't go through the work of
668*7c478bd9Sstevel@tonic-gate  * locating the appropriate socket a datagram is destined for. We'll only
669*7c478bd9Sstevel@tonic-gate  * accept data for the referenced socket. This means we don't have
670*7c478bd9Sstevel@tonic-gate  * asynchronous networking, but since we can't service the net using an
671*7c478bd9Sstevel@tonic-gate  * interrupt handler, it doesn't do us any good to try to service datagrams
672*7c478bd9Sstevel@tonic-gate  * destined for sockets other than the referenced one. Data is handled in
673*7c478bd9Sstevel@tonic-gate  * a fifo manner.
674*7c478bd9Sstevel@tonic-gate  *
675*7c478bd9Sstevel@tonic-gate  * The mac layer will grab all frames for us. If we find we don't have all
676*7c478bd9Sstevel@tonic-gate  * the necessary fragments to reassemble the datagram, we'll call the mac
677*7c478bd9Sstevel@tonic-gate  * layer again for FRAG_ATTEMPTS to see if it has any more frames.
678*7c478bd9Sstevel@tonic-gate  *
679*7c478bd9Sstevel@tonic-gate  * Supported protocols: IPPROTO_IP, IPPROTO_ICMP, IPPROTO_UDP.
680*7c478bd9Sstevel@tonic-gate  *
681*7c478bd9Sstevel@tonic-gate  * Returns: number of NETWORK_LVL datagrams placed on socket , -1 if error
682*7c478bd9Sstevel@tonic-gate  * occurred.
683*7c478bd9Sstevel@tonic-gate  *
684*7c478bd9Sstevel@tonic-gate  * Note: errno is set to ETIMEDOUT if fragment reassembly fails.
685*7c478bd9Sstevel@tonic-gate  */
686*7c478bd9Sstevel@tonic-gate int
687*7c478bd9Sstevel@tonic-gate ipv4_input(int index)
688*7c478bd9Sstevel@tonic-gate {
689*7c478bd9Sstevel@tonic-gate 	int			datagrams = 0;
690*7c478bd9Sstevel@tonic-gate 	int			frag_stat, input_attempts = 0;
691*7c478bd9Sstevel@tonic-gate 	uint16_t		iphlen, iplen, ip_id;
692*7c478bd9Sstevel@tonic-gate 	int16_t			curr_off;
693*7c478bd9Sstevel@tonic-gate 	struct ip		*iphp;
694*7c478bd9Sstevel@tonic-gate 	struct inetgram		*igp, *newgp = NULL, *ipv4_listp = NULL;
695*7c478bd9Sstevel@tonic-gate 	struct in_addr		ipdst, ipsrc;
696*7c478bd9Sstevel@tonic-gate 	mblk_t			*mp;
697*7c478bd9Sstevel@tonic-gate 	enum SockType		type;
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
700*7c478bd9Sstevel@tonic-gate 	printf("ipv4_input(%d): start ######################################\n",
701*7c478bd9Sstevel@tonic-gate 	    index);
702*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 	frag_flush();
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate ipv4_try_again:
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	while ((igp = sockets[index].inq) != NULL) {
709*7c478bd9Sstevel@tonic-gate 		if (igp->igm_level != NETWORK_LVL) {
710*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
711*7c478bd9Sstevel@tonic-gate 			printf("ipv4_input(%d): unexpected frame type: %d\n",
712*7c478bd9Sstevel@tonic-gate 			    index, igp->igm_level);
713*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
714*7c478bd9Sstevel@tonic-gate 			del_gram(&sockets[index].inq, igp, TRUE);
715*7c478bd9Sstevel@tonic-gate 			continue;
716*7c478bd9Sstevel@tonic-gate 		}
717*7c478bd9Sstevel@tonic-gate 		iphp = (struct ip *)igp->igm_mp->b_rptr;
718*7c478bd9Sstevel@tonic-gate 		if (iphp->ip_v != IPVERSION) {
719*7c478bd9Sstevel@tonic-gate 			dprintf("ipv4_input(%d): IPv%d datagram discarded\n",
720*7c478bd9Sstevel@tonic-gate 			index, iphp->ip_v);
721*7c478bd9Sstevel@tonic-gate 			del_gram(&sockets[index].inq, igp, TRUE);
722*7c478bd9Sstevel@tonic-gate 			continue;
723*7c478bd9Sstevel@tonic-gate 		}
724*7c478bd9Sstevel@tonic-gate 		iphlen = iphp->ip_hl << 2;
725*7c478bd9Sstevel@tonic-gate 		if (iphlen < sizeof (struct ip)) {
726*7c478bd9Sstevel@tonic-gate 			dprintf("ipv4_input(%d): IP msg too short (%d < %u)\n",
727*7c478bd9Sstevel@tonic-gate 			    index, iphlen, (uint_t)sizeof (struct ip));
728*7c478bd9Sstevel@tonic-gate 			del_gram(&sockets[index].inq, igp, TRUE);
729*7c478bd9Sstevel@tonic-gate 			continue;
730*7c478bd9Sstevel@tonic-gate 		}
731*7c478bd9Sstevel@tonic-gate 		iplen = ntohs(iphp->ip_len);
732*7c478bd9Sstevel@tonic-gate 		if (iplen > msgdsize(igp->igm_mp)) {
733*7c478bd9Sstevel@tonic-gate 			dprintf("ipv4_input(%d): IP len/buffer mismatch "
734*7c478bd9Sstevel@tonic-gate 			    "(%d > %lu)\n", index, iplen, igp->igm_mp->b_size);
735*7c478bd9Sstevel@tonic-gate 			del_gram(&sockets[index].inq, igp, TRUE);
736*7c478bd9Sstevel@tonic-gate 			continue;
737*7c478bd9Sstevel@tonic-gate 		}
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)&(iphp->ip_dst), (caddr_t)&ipdst,
740*7c478bd9Sstevel@tonic-gate 		    sizeof (ipdst));
741*7c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)&(iphp->ip_src), (caddr_t)&ipsrc,
742*7c478bd9Sstevel@tonic-gate 		    sizeof (ipsrc));
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 		/* igp->igm_mp->b_datap is guaranteed to be 64 bit aligned] */
745*7c478bd9Sstevel@tonic-gate 		if (ipv4cksum((uint16_t *)iphp, iphlen) != 0) {
746*7c478bd9Sstevel@tonic-gate 			dprintf("ipv4_input(%d): Bad IP header checksum "
747*7c478bd9Sstevel@tonic-gate 			    "(to %s)\n", index, inet_ntoa(ipdst));
748*7c478bd9Sstevel@tonic-gate 			del_gram(&sockets[index].inq, igp, TRUE);
749*7c478bd9Sstevel@tonic-gate 			continue;
750*7c478bd9Sstevel@tonic-gate 		}
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 		if (!promiscuous) {
753*7c478bd9Sstevel@tonic-gate 			/* validate destination address */
754*7c478bd9Sstevel@tonic-gate 			if (ipdst.s_addr != htonl(INADDR_BROADCAST) &&
755*7c478bd9Sstevel@tonic-gate 			    ipdst.s_addr != (mynet.s_addr | ~netmask.s_addr) &&
756*7c478bd9Sstevel@tonic-gate 			    ipdst.s_addr != myip.s_addr) {
757*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
758*7c478bd9Sstevel@tonic-gate 				printf("ipv4_input(%d): msg to %s discarded.\n",
759*7c478bd9Sstevel@tonic-gate 				    index, inet_ntoa(ipdst));
760*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
761*7c478bd9Sstevel@tonic-gate 				/* not ours */
762*7c478bd9Sstevel@tonic-gate 				del_gram(&sockets[index].inq, igp, TRUE);
763*7c478bd9Sstevel@tonic-gate 				continue;
764*7c478bd9Sstevel@tonic-gate 			}
765*7c478bd9Sstevel@tonic-gate 		}
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 		/* Intercept ICMP first */
768*7c478bd9Sstevel@tonic-gate 		if (!promiscuous && (iphp->ip_p == IPPROTO_ICMP)) {
769*7c478bd9Sstevel@tonic-gate 			icmp4(igp, iphp, iphlen, ipsrc);
770*7c478bd9Sstevel@tonic-gate 			del_gram(&sockets[index].inq, igp, TRUE);
771*7c478bd9Sstevel@tonic-gate 			continue;
772*7c478bd9Sstevel@tonic-gate 		}
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
775*7c478bd9Sstevel@tonic-gate 		printf("ipv4_input(%d): processing ID: 0x%x protocol %d "
776*7c478bd9Sstevel@tonic-gate 		    "(0x%x) (0x%x,%d)\n",
777*7c478bd9Sstevel@tonic-gate 		    index, ntohs(iphp->ip_id), iphp->ip_p, igp, igp->igm_mp,
778*7c478bd9Sstevel@tonic-gate 		    igp->igm_mp->b_size);
779*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
780*7c478bd9Sstevel@tonic-gate 		type = sockets[index].type;
781*7c478bd9Sstevel@tonic-gate 		if (type == INETBOOT_RAW) {
782*7c478bd9Sstevel@tonic-gate 			/* No fragmentation - Just the raw packet. */
783*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
784*7c478bd9Sstevel@tonic-gate 			printf("ipv4_input(%d): Raw packet.\n", index);
785*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
786*7c478bd9Sstevel@tonic-gate 			del_gram(&sockets[index].inq, igp, FALSE);
787*7c478bd9Sstevel@tonic-gate 			add_grams(&ipv4_listp, igp);
788*7c478bd9Sstevel@tonic-gate 			igp->igm_mp->b_rptr += iphlen;
789*7c478bd9Sstevel@tonic-gate 			igp->igm_mp->b_wptr = igp->igm_mp->b_rptr + iplen;
790*7c478bd9Sstevel@tonic-gate 			datagrams++;
791*7c478bd9Sstevel@tonic-gate 			continue;
792*7c478bd9Sstevel@tonic-gate 		}
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 		if ((type == INETBOOT_DGRAM && iphp->ip_p != IPPROTO_UDP) ||
795*7c478bd9Sstevel@tonic-gate 		    (type == INETBOOT_STREAM && iphp->ip_p != IPPROTO_TCP)) {
796*7c478bd9Sstevel@tonic-gate 			/* Wrong protocol. */
797*7c478bd9Sstevel@tonic-gate 			dprintf("ipv4_input(%d): unexpected protocol: "
798*7c478bd9Sstevel@tonic-gate 			    "%d for socket type %d\n", index, iphp->ip_p, type);
799*7c478bd9Sstevel@tonic-gate 			del_gram(&sockets[index].inq, igp, TRUE);
800*7c478bd9Sstevel@tonic-gate 			continue;
801*7c478bd9Sstevel@tonic-gate 		}
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 		/*
804*7c478bd9Sstevel@tonic-gate 		 * The following code is common to both STREAM and DATAGRAM
805*7c478bd9Sstevel@tonic-gate 		 * sockets.
806*7c478bd9Sstevel@tonic-gate 		 */
807*7c478bd9Sstevel@tonic-gate 
808*7c478bd9Sstevel@tonic-gate 		/*
809*7c478bd9Sstevel@tonic-gate 		 * Once we process the first fragment, we won't have
810*7c478bd9Sstevel@tonic-gate 		 * the transport header, so we'll have to  match on
811*7c478bd9Sstevel@tonic-gate 		 * IP id.
812*7c478bd9Sstevel@tonic-gate 		 */
813*7c478bd9Sstevel@tonic-gate 		curr_off = ntohs(iphp->ip_off);
814*7c478bd9Sstevel@tonic-gate 		if ((curr_off & ~(IP_DF | IP_MF)) == 0) {
815*7c478bd9Sstevel@tonic-gate 			uint16_t	*transp;
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 			/* Validate transport header. */
818*7c478bd9Sstevel@tonic-gate 			mp = igp->igm_mp;
819*7c478bd9Sstevel@tonic-gate 			if ((mp->b_wptr - mp->b_rptr - iphlen) <
820*7c478bd9Sstevel@tonic-gate 			    sockets[index].headerlen[TRANSPORT_LVL](igp)) {
821*7c478bd9Sstevel@tonic-gate 				dprintf("ipv4_input(%d): datagram 0 "
822*7c478bd9Sstevel@tonic-gate 				    "too small to hold transport header "
823*7c478bd9Sstevel@tonic-gate 				    "(from %s)\n", index, inet_ntoa(ipsrc));
824*7c478bd9Sstevel@tonic-gate 				del_gram(&sockets[index].inq, igp, TRUE);
825*7c478bd9Sstevel@tonic-gate 				continue;
826*7c478bd9Sstevel@tonic-gate 			}
827*7c478bd9Sstevel@tonic-gate 
828*7c478bd9Sstevel@tonic-gate 			/*
829*7c478bd9Sstevel@tonic-gate 			 * check alignment - transport elements are 16
830*7c478bd9Sstevel@tonic-gate 			 * bit aligned..
831*7c478bd9Sstevel@tonic-gate 			 */
832*7c478bd9Sstevel@tonic-gate 			transp = (uint16_t *)(mp->b_rptr + iphlen);
833*7c478bd9Sstevel@tonic-gate 			if ((uintptr_t)transp % sizeof (uint16_t)) {
834*7c478bd9Sstevel@tonic-gate 				dprintf("ipv4_input(%d): Transport "
835*7c478bd9Sstevel@tonic-gate 				    "header is not 16-bit aligned "
836*7c478bd9Sstevel@tonic-gate 				    "(0x%lx, from %s)\n", index, (long)transp,
837*7c478bd9Sstevel@tonic-gate 				    inet_ntoa(ipsrc));
838*7c478bd9Sstevel@tonic-gate 				del_gram(&sockets[index].inq, igp, TRUE);
839*7c478bd9Sstevel@tonic-gate 				continue;
840*7c478bd9Sstevel@tonic-gate 			}
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 			if (curr_off & IP_MF) {
843*7c478bd9Sstevel@tonic-gate 				/* fragment 0 of fragmented datagram */
844*7c478bd9Sstevel@tonic-gate 				ip_id = ntohs(iphp->ip_id);
845*7c478bd9Sstevel@tonic-gate 				frag_stat = frag_add(curr_off, igp->igm_mp,
846*7c478bd9Sstevel@tonic-gate 				    ip_id, iplen, iphlen, iphp->ip_p);
847*7c478bd9Sstevel@tonic-gate 				if (frag_stat != FRAG_SUCCESS) {
848*7c478bd9Sstevel@tonic-gate #ifdef	FRAG_DEBUG
849*7c478bd9Sstevel@tonic-gate 					if (frag_stat == FRAG_DUP) {
850*7c478bd9Sstevel@tonic-gate 						printf("ipv4_input"
851*7c478bd9Sstevel@tonic-gate 						    "(%d): Frag dup.\n", index);
852*7c478bd9Sstevel@tonic-gate 					} else {
853*7c478bd9Sstevel@tonic-gate 						printf("ipv4_input"
854*7c478bd9Sstevel@tonic-gate 						    "(%d): too many "
855*7c478bd9Sstevel@tonic-gate 						    "frags\n", index);
856*7c478bd9Sstevel@tonic-gate 					}
857*7c478bd9Sstevel@tonic-gate #endif	/* FRAG_DEBUG */
858*7c478bd9Sstevel@tonic-gate 					del_gram(&sockets[index].inq,
859*7c478bd9Sstevel@tonic-gate 					    igp, TRUE);
860*7c478bd9Sstevel@tonic-gate 					continue;
861*7c478bd9Sstevel@tonic-gate 				}
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 				del_gram(&sockets[index].inq, igp, FALSE);
864*7c478bd9Sstevel@tonic-gate 				/* keep the data, lose the inetgram */
865*7c478bd9Sstevel@tonic-gate 				bkmem_free((caddr_t)igp,
866*7c478bd9Sstevel@tonic-gate 				    sizeof (struct inetgram));
867*7c478bd9Sstevel@tonic-gate #ifdef	FRAG_DEBUG
868*7c478bd9Sstevel@tonic-gate 				printf("ipv4_input(%d): Frag/Off/Id "
869*7c478bd9Sstevel@tonic-gate 				    "(%d/%d/%x)\n", index, fragments,
870*7c478bd9Sstevel@tonic-gate 				    IPV4_OFFSET(curr_off), ip_id);
871*7c478bd9Sstevel@tonic-gate #endif	/* FRAG_DEBUG */
872*7c478bd9Sstevel@tonic-gate 			} else {
873*7c478bd9Sstevel@tonic-gate 				/* Single, unfragmented datagram */
874*7c478bd9Sstevel@tonic-gate 				newgp = make_trans_datagram(index, igp,
875*7c478bd9Sstevel@tonic-gate 				    ipsrc, ipdst, iphlen);
876*7c478bd9Sstevel@tonic-gate 				if (newgp != NULL) {
877*7c478bd9Sstevel@tonic-gate 					add_grams(&ipv4_listp, newgp);
878*7c478bd9Sstevel@tonic-gate 					datagrams++;
879*7c478bd9Sstevel@tonic-gate 				}
880*7c478bd9Sstevel@tonic-gate 				del_gram(&sockets[index].inq, igp,
881*7c478bd9Sstevel@tonic-gate 				    TRUE);
882*7c478bd9Sstevel@tonic-gate 				continue;
883*7c478bd9Sstevel@tonic-gate 			}
884*7c478bd9Sstevel@tonic-gate 		} else {
885*7c478bd9Sstevel@tonic-gate 			/* fragments other than 0 */
886*7c478bd9Sstevel@tonic-gate 			frag_stat = frag_add(curr_off, igp->igm_mp,
887*7c478bd9Sstevel@tonic-gate 			    ntohs(iphp->ip_id), iplen, iphlen, iphp->ip_p);
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 			if (frag_stat == FRAG_SUCCESS) {
890*7c478bd9Sstevel@tonic-gate #ifdef	FRAG_DEBUG
891*7c478bd9Sstevel@tonic-gate 				printf("ipv4_input(%d): Frag(%d) "
892*7c478bd9Sstevel@tonic-gate 				    "off(%d) id(%x)\n", index,
893*7c478bd9Sstevel@tonic-gate 				    fragments, IPV4_OFFSET(curr_off),
894*7c478bd9Sstevel@tonic-gate 				    ntohs(iphp->ip_id));
895*7c478bd9Sstevel@tonic-gate #endif	/* FRAG_DEBUG */
896*7c478bd9Sstevel@tonic-gate 				del_gram(&sockets[index].inq, igp, FALSE);
897*7c478bd9Sstevel@tonic-gate 				/* keep the data, lose the inetgram */
898*7c478bd9Sstevel@tonic-gate 				bkmem_free((caddr_t)igp,
899*7c478bd9Sstevel@tonic-gate 				    sizeof (struct inetgram));
900*7c478bd9Sstevel@tonic-gate 			} else {
901*7c478bd9Sstevel@tonic-gate #ifdef	FRAG_DEBUG
902*7c478bd9Sstevel@tonic-gate 				if (frag_stat == FRAG_DUP)
903*7c478bd9Sstevel@tonic-gate 					printf("ipv4_input(%d): Frag "
904*7c478bd9Sstevel@tonic-gate 					    "dup.\n", index);
905*7c478bd9Sstevel@tonic-gate 				else {
906*7c478bd9Sstevel@tonic-gate 					printf("ipv4_input(%d): too "
907*7c478bd9Sstevel@tonic-gate 					    "many frags\n", index);
908*7c478bd9Sstevel@tonic-gate 				}
909*7c478bd9Sstevel@tonic-gate #endif	/* FRAG_DEBUG */
910*7c478bd9Sstevel@tonic-gate 				del_gram(&sockets[index].inq, igp, TRUE);
911*7c478bd9Sstevel@tonic-gate 				continue;
912*7c478bd9Sstevel@tonic-gate 			}
913*7c478bd9Sstevel@tonic-gate 		}
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate 		/*
916*7c478bd9Sstevel@tonic-gate 		 * Determine if we have all of the fragments.
917*7c478bd9Sstevel@tonic-gate 		 *
918*7c478bd9Sstevel@tonic-gate 		 * NOTE: at this point, we've placed the data in the
919*7c478bd9Sstevel@tonic-gate 		 * fragment table, and the inetgram (igp) has been
920*7c478bd9Sstevel@tonic-gate 		 * deleted.
921*7c478bd9Sstevel@tonic-gate 		 */
922*7c478bd9Sstevel@tonic-gate 		if (!frag_chk())
923*7c478bd9Sstevel@tonic-gate 			continue;
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 		newgp = make_trans_datagram(index, NULL, ipsrc, ipdst, iphlen);
926*7c478bd9Sstevel@tonic-gate 		if (newgp == NULL)
927*7c478bd9Sstevel@tonic-gate 			continue;
928*7c478bd9Sstevel@tonic-gate 		add_grams(&ipv4_listp, newgp);
929*7c478bd9Sstevel@tonic-gate 		datagrams++;
930*7c478bd9Sstevel@tonic-gate 	}
931*7c478bd9Sstevel@tonic-gate 	if (ipv4_listp == NULL && fragments != 0) {
932*7c478bd9Sstevel@tonic-gate 		if (++input_attempts > FRAG_ATTEMPTS) {
933*7c478bd9Sstevel@tonic-gate 			dprintf("ipv4_input(%d): reassembly(%d) timed out in "
934*7c478bd9Sstevel@tonic-gate 			    "%d msecs.\n", index, fragments,
935*7c478bd9Sstevel@tonic-gate 			    sockets[index].in_timeout * input_attempts);
936*7c478bd9Sstevel@tonic-gate 			frag_flush();
937*7c478bd9Sstevel@tonic-gate 			errno = ETIMEDOUT;
938*7c478bd9Sstevel@tonic-gate 			return (-1);
939*7c478bd9Sstevel@tonic-gate 		} else {
940*7c478bd9Sstevel@tonic-gate 			/*
941*7c478bd9Sstevel@tonic-gate 			 * Call the media layer again... there may be more
942*7c478bd9Sstevel@tonic-gate 			 * packets waiting.
943*7c478bd9Sstevel@tonic-gate 			 */
944*7c478bd9Sstevel@tonic-gate 			if (sockets[index].input[MEDIA_LVL](index) < 0) {
945*7c478bd9Sstevel@tonic-gate 				/* errno will be set appropriately */
946*7c478bd9Sstevel@tonic-gate 				frag_flush();
947*7c478bd9Sstevel@tonic-gate 				return (-1);
948*7c478bd9Sstevel@tonic-gate 			}
949*7c478bd9Sstevel@tonic-gate 			goto ipv4_try_again;
950*7c478bd9Sstevel@tonic-gate 		}
951*7c478bd9Sstevel@tonic-gate 	}
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	add_grams(&sockets[index].inq, ipv4_listp);
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	return (datagrams);
956*7c478bd9Sstevel@tonic-gate }
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate /*
959*7c478bd9Sstevel@tonic-gate  * ipv4_output: Generate IPv4 datagram(s) for the payload and deliver them.
960*7c478bd9Sstevel@tonic-gate  * Routing is handled here as well, by reusing the saddr field to hold the
961*7c478bd9Sstevel@tonic-gate  * router's IP address.
962*7c478bd9Sstevel@tonic-gate  *
963*7c478bd9Sstevel@tonic-gate  * We don't deal with fragmentation on the outgoing side.
964*7c478bd9Sstevel@tonic-gate  *
965*7c478bd9Sstevel@tonic-gate  * Arguments: index to socket, inetgram to send.
966*7c478bd9Sstevel@tonic-gate  *
967*7c478bd9Sstevel@tonic-gate  * Returns: 0 for success, -1 if error occurred.
968*7c478bd9Sstevel@tonic-gate  */
969*7c478bd9Sstevel@tonic-gate int
970*7c478bd9Sstevel@tonic-gate ipv4_output(int index, struct inetgram *ogp)
971*7c478bd9Sstevel@tonic-gate {
972*7c478bd9Sstevel@tonic-gate 	struct ip	*iphp;
973*7c478bd9Sstevel@tonic-gate 	uint64_t	iphbuffer[sizeof (struct ip)];
974*7c478bd9Sstevel@tonic-gate 
975*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
976*7c478bd9Sstevel@tonic-gate 	printf("ipv4_output(%d): size %d\n", index,
977*7c478bd9Sstevel@tonic-gate 	    ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr);
978*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 	/* we don't deal (yet) with fragmentation. Maybe never will */
981*7c478bd9Sstevel@tonic-gate 	if ((ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr) > mac_get_mtu()) {
982*7c478bd9Sstevel@tonic-gate 		dprintf("ipv4: datagram too big for MAC layer.\n");
983*7c478bd9Sstevel@tonic-gate 		errno = E2BIG;
984*7c478bd9Sstevel@tonic-gate 		return (-1);
985*7c478bd9Sstevel@tonic-gate 	}
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 	if (ogp->igm_level != NETWORK_LVL) {
988*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
989*7c478bd9Sstevel@tonic-gate 		printf("ipv4_output(%d): unexpected frame type: %d\n", index,
990*7c478bd9Sstevel@tonic-gate 		    ogp->igm_level);
991*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
992*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;
993*7c478bd9Sstevel@tonic-gate 		return (-1);
994*7c478bd9Sstevel@tonic-gate 	}
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	if (sockets[index].out_flags & SO_DONTROUTE)
997*7c478bd9Sstevel@tonic-gate 		ogp->igm_oflags |= MSG_DONTROUTE;
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 	iphp = (struct ip *)&iphbuffer;
1000*7c478bd9Sstevel@tonic-gate 	iphp->ip_v = IPVERSION;
1001*7c478bd9Sstevel@tonic-gate 	iphp->ip_hl = sizeof (struct ip) / 4;
1002*7c478bd9Sstevel@tonic-gate 	iphp->ip_tos = 0;
1003*7c478bd9Sstevel@tonic-gate 	iphp->ip_len = htons(ogp->igm_mp->b_wptr - ogp->igm_mp->b_rptr +
1004*7c478bd9Sstevel@tonic-gate 	    sizeof (struct ip));
1005*7c478bd9Sstevel@tonic-gate 	iphp->ip_id = htons(++g_ip_id);
1006*7c478bd9Sstevel@tonic-gate 	iphp->ip_off = htons(IP_DF);
1007*7c478bd9Sstevel@tonic-gate 	iphp->ip_p = sockets[index].proto;
1008*7c478bd9Sstevel@tonic-gate 	iphp->ip_sum = htons(0);
1009*7c478bd9Sstevel@tonic-gate 	iphp->ip_ttl = ttl;
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate 	/* struct copies */
1012*7c478bd9Sstevel@tonic-gate 	iphp->ip_src = myip;
1013*7c478bd9Sstevel@tonic-gate 	iphp->ip_dst = ogp->igm_saddr.sin_addr;
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 	/*
1016*7c478bd9Sstevel@tonic-gate 	 * On local / limited broadcasts, don't route. From a purist's
1017*7c478bd9Sstevel@tonic-gate 	 * perspective, we should be setting the TTL to 1. But
1018*7c478bd9Sstevel@tonic-gate 	 * operational experience has shown that some BOOTP relay agents
1019*7c478bd9Sstevel@tonic-gate 	 * (ciscos) discard our packets. Furthermore, these devices also
1020*7c478bd9Sstevel@tonic-gate 	 * *don't* reset the TTL to MAXTTL on the unicast side of the
1021*7c478bd9Sstevel@tonic-gate 	 * BOOTP relay agent! Sigh. Thus to work correctly in these
1022*7c478bd9Sstevel@tonic-gate 	 * environments, we leave the TTL as it has been been set by
1023*7c478bd9Sstevel@tonic-gate 	 * the application layer, and simply don't check for a route.
1024*7c478bd9Sstevel@tonic-gate 	 */
1025*7c478bd9Sstevel@tonic-gate 	if (iphp->ip_dst.s_addr == htonl(INADDR_BROADCAST) ||
1026*7c478bd9Sstevel@tonic-gate 	    (netmask.s_addr != htonl(INADDR_BROADCAST) &&
1027*7c478bd9Sstevel@tonic-gate 	    iphp->ip_dst.s_addr == (mynet.s_addr | ~netmask.s_addr))) {
1028*7c478bd9Sstevel@tonic-gate 		ogp->igm_oflags |= MSG_DONTROUTE;
1029*7c478bd9Sstevel@tonic-gate 	}
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate 	/* Routing necessary? */
1032*7c478bd9Sstevel@tonic-gate 	if ((ogp->igm_oflags & MSG_DONTROUTE) == 0 &&
1033*7c478bd9Sstevel@tonic-gate 	    ((iphp->ip_dst.s_addr & netmask.s_addr) != mynet.s_addr)) {
1034*7c478bd9Sstevel@tonic-gate 		struct in_addr *rip;
1035*7c478bd9Sstevel@tonic-gate 		if ((rip = ipv4_get_route(RT_HOST, &iphp->ip_dst,
1036*7c478bd9Sstevel@tonic-gate 		    NULL)) == NULL) {
1037*7c478bd9Sstevel@tonic-gate 			rip = ipv4_get_route(RT_DEFAULT, NULL, NULL);
1038*7c478bd9Sstevel@tonic-gate 		}
1039*7c478bd9Sstevel@tonic-gate 		if (rip == NULL) {
1040*7c478bd9Sstevel@tonic-gate 			dprintf("ipv4(%d): No route to %s.\n",
1041*7c478bd9Sstevel@tonic-gate 			    index, inet_ntoa(iphp->ip_dst));
1042*7c478bd9Sstevel@tonic-gate 			errno = EHOSTUNREACH;
1043*7c478bd9Sstevel@tonic-gate 			return (-1);
1044*7c478bd9Sstevel@tonic-gate 		}
1045*7c478bd9Sstevel@tonic-gate 		ogp->igm_router.s_addr = rip->s_addr;
1046*7c478bd9Sstevel@tonic-gate 	} else
1047*7c478bd9Sstevel@tonic-gate 		ogp->igm_router.s_addr = htonl(INADDR_ANY);
1048*7c478bd9Sstevel@tonic-gate 
1049*7c478bd9Sstevel@tonic-gate 	iphp->ip_sum = ipv4cksum((uint16_t *)iphp, sizeof (struct ip));
1050*7c478bd9Sstevel@tonic-gate 	ogp->igm_mp->b_rptr -= sizeof (struct ip);
1051*7c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)iphp, (caddr_t)(ogp->igm_mp->b_rptr),
1052*7c478bd9Sstevel@tonic-gate 	    sizeof (struct ip));
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate 	ogp->igm_level = MEDIA_LVL;
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate 	return (0);
1057*7c478bd9Sstevel@tonic-gate }
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate /*
1060*7c478bd9Sstevel@tonic-gate  * Function to be called by TCP to send out a packet.  This is used
1061*7c478bd9Sstevel@tonic-gate  * when TCP wants to send out packets which it has already filled in
1062*7c478bd9Sstevel@tonic-gate  * most of the header fields.
1063*7c478bd9Sstevel@tonic-gate  */
1064*7c478bd9Sstevel@tonic-gate int
1065*7c478bd9Sstevel@tonic-gate ipv4_tcp_output(int sock_id, mblk_t *pkt)
1066*7c478bd9Sstevel@tonic-gate {
1067*7c478bd9Sstevel@tonic-gate 	struct ip *iph;
1068*7c478bd9Sstevel@tonic-gate 	struct in_addr *rip = NULL;
1069*7c478bd9Sstevel@tonic-gate 	struct inetgram datagram;
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	iph = (struct ip *)pkt->b_rptr;
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	bzero(&datagram, sizeof (struct inetgram));
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate 	/*
1076*7c478bd9Sstevel@tonic-gate 	 * Bootparams doesn't know about subnet masks, so we need to
1077*7c478bd9Sstevel@tonic-gate 	 * explicitly check for this flag.
1078*7c478bd9Sstevel@tonic-gate 	 */
1079*7c478bd9Sstevel@tonic-gate 	if (sockets[sock_id].out_flags & SO_DONTROUTE)
1080*7c478bd9Sstevel@tonic-gate 		datagram.igm_oflags |= MSG_DONTROUTE;
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate 	/* Routing necessary? */
1083*7c478bd9Sstevel@tonic-gate 	if (((datagram.igm_oflags & MSG_DONTROUTE) == 0) &&
1084*7c478bd9Sstevel@tonic-gate 		((iph->ip_dst.s_addr & netmask.s_addr) != mynet.s_addr)) {
1085*7c478bd9Sstevel@tonic-gate 		if ((rip = ipv4_get_route(RT_HOST, &iph->ip_dst,
1086*7c478bd9Sstevel@tonic-gate 		    NULL)) == NULL) {
1087*7c478bd9Sstevel@tonic-gate 			rip = ipv4_get_route(RT_DEFAULT, NULL, NULL);
1088*7c478bd9Sstevel@tonic-gate 		}
1089*7c478bd9Sstevel@tonic-gate 		if (rip == NULL) {
1090*7c478bd9Sstevel@tonic-gate 			dprintf("ipv4(%d): No route to %s.\n",
1091*7c478bd9Sstevel@tonic-gate 			    sock_id, inet_ntoa(iph->ip_dst));
1092*7c478bd9Sstevel@tonic-gate 			errno = EHOSTUNREACH;
1093*7c478bd9Sstevel@tonic-gate 			return (-1);
1094*7c478bd9Sstevel@tonic-gate 		}
1095*7c478bd9Sstevel@tonic-gate 	}
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate 	iph->ip_id = htons(++g_ip_id);
1098*7c478bd9Sstevel@tonic-gate 	iph->ip_sum = ipv4cksum((uint16_t *)iph, sizeof (struct ip));
1099*7c478bd9Sstevel@tonic-gate #if DEBUG > 1
1100*7c478bd9Sstevel@tonic-gate 	printf("ipv4_tcp_output: dump IP packet(%d)\n", iph->ip_len);
1101*7c478bd9Sstevel@tonic-gate 	hexdump((char *)pkt->b_rptr, iph->ip_len);
1102*7c478bd9Sstevel@tonic-gate #endif
1103*7c478bd9Sstevel@tonic-gate 	/* Call the MAC layer output routine to send it out. */
1104*7c478bd9Sstevel@tonic-gate 	datagram.igm_mp = pkt;
1105*7c478bd9Sstevel@tonic-gate 	datagram.igm_level = MEDIA_LVL;
1106*7c478bd9Sstevel@tonic-gate 	if (rip != NULL)
1107*7c478bd9Sstevel@tonic-gate 		datagram.igm_router.s_addr = rip->s_addr;
1108*7c478bd9Sstevel@tonic-gate 	else
1109*7c478bd9Sstevel@tonic-gate 		datagram.igm_router.s_addr = 0;
1110*7c478bd9Sstevel@tonic-gate 	return (mac_state.mac_output(sock_id, &datagram));
1111*7c478bd9Sstevel@tonic-gate }
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate /*
1114*7c478bd9Sstevel@tonic-gate  * Internet address interpretation routine.
1115*7c478bd9Sstevel@tonic-gate  * All the network library routines call this
1116*7c478bd9Sstevel@tonic-gate  * routine to interpret entries in the data bases
1117*7c478bd9Sstevel@tonic-gate  * which are expected to be an address.
1118*7c478bd9Sstevel@tonic-gate  * The value returned is in network order.
1119*7c478bd9Sstevel@tonic-gate  */
1120*7c478bd9Sstevel@tonic-gate in_addr_t
1121*7c478bd9Sstevel@tonic-gate inet_addr(const char *cp)
1122*7c478bd9Sstevel@tonic-gate {
1123*7c478bd9Sstevel@tonic-gate 	uint32_t val, base, n;
1124*7c478bd9Sstevel@tonic-gate 	char c;
1125*7c478bd9Sstevel@tonic-gate 	uint32_t parts[4], *pp = parts;
1126*7c478bd9Sstevel@tonic-gate 
1127*7c478bd9Sstevel@tonic-gate 	if (*cp == '\0')
1128*7c478bd9Sstevel@tonic-gate 		return ((uint32_t)-1); /* disallow null string in cp */
1129*7c478bd9Sstevel@tonic-gate again:
1130*7c478bd9Sstevel@tonic-gate 	/*
1131*7c478bd9Sstevel@tonic-gate 	 * Collect number up to ``.''.
1132*7c478bd9Sstevel@tonic-gate 	 * Values are specified as for C:
1133*7c478bd9Sstevel@tonic-gate 	 * 0x=hex, 0=octal, other=decimal.
1134*7c478bd9Sstevel@tonic-gate 	 */
1135*7c478bd9Sstevel@tonic-gate 	val = 0; base = 10;
1136*7c478bd9Sstevel@tonic-gate 	if (*cp == '0') {
1137*7c478bd9Sstevel@tonic-gate 		if (*++cp == 'x' || *cp == 'X')
1138*7c478bd9Sstevel@tonic-gate 			base = 16, cp++;
1139*7c478bd9Sstevel@tonic-gate 		else
1140*7c478bd9Sstevel@tonic-gate 			base = 8;
1141*7c478bd9Sstevel@tonic-gate 	}
1142*7c478bd9Sstevel@tonic-gate 	while ((c = *cp) != NULL) {
1143*7c478bd9Sstevel@tonic-gate 		if (isdigit(c)) {
1144*7c478bd9Sstevel@tonic-gate 			if ((c - '0') >= base)
1145*7c478bd9Sstevel@tonic-gate 			    break;
1146*7c478bd9Sstevel@tonic-gate 			val = (val * base) + (c - '0');
1147*7c478bd9Sstevel@tonic-gate 			cp++;
1148*7c478bd9Sstevel@tonic-gate 			continue;
1149*7c478bd9Sstevel@tonic-gate 		}
1150*7c478bd9Sstevel@tonic-gate 		if (base == 16 && isxdigit(c)) {
1151*7c478bd9Sstevel@tonic-gate 			val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
1152*7c478bd9Sstevel@tonic-gate 			cp++;
1153*7c478bd9Sstevel@tonic-gate 			continue;
1154*7c478bd9Sstevel@tonic-gate 		}
1155*7c478bd9Sstevel@tonic-gate 		break;
1156*7c478bd9Sstevel@tonic-gate 	}
1157*7c478bd9Sstevel@tonic-gate 	if (*cp == '.') {
1158*7c478bd9Sstevel@tonic-gate 		/*
1159*7c478bd9Sstevel@tonic-gate 		 * Internet format:
1160*7c478bd9Sstevel@tonic-gate 		 *	a.b.c.d
1161*7c478bd9Sstevel@tonic-gate 		 *	a.b.c	(with c treated as 16-bits)
1162*7c478bd9Sstevel@tonic-gate 		 *	a.b	(with b treated as 24 bits)
1163*7c478bd9Sstevel@tonic-gate 		 */
1164*7c478bd9Sstevel@tonic-gate 		if ((pp >= parts + 3) || (val > 0xff)) {
1165*7c478bd9Sstevel@tonic-gate 			return ((uint32_t)-1);
1166*7c478bd9Sstevel@tonic-gate 		}
1167*7c478bd9Sstevel@tonic-gate 		*pp++ = val, cp++;
1168*7c478bd9Sstevel@tonic-gate 		goto again;
1169*7c478bd9Sstevel@tonic-gate 	}
1170*7c478bd9Sstevel@tonic-gate 	/*
1171*7c478bd9Sstevel@tonic-gate 	 * Check for trailing characters.
1172*7c478bd9Sstevel@tonic-gate 	 */
1173*7c478bd9Sstevel@tonic-gate 	if (*cp && !isspace(*cp)) {
1174*7c478bd9Sstevel@tonic-gate 		return ((uint32_t)-1);
1175*7c478bd9Sstevel@tonic-gate 	}
1176*7c478bd9Sstevel@tonic-gate 	*pp++ = val;
1177*7c478bd9Sstevel@tonic-gate 	/*
1178*7c478bd9Sstevel@tonic-gate 	 * Concoct the address according to
1179*7c478bd9Sstevel@tonic-gate 	 * the number of parts specified.
1180*7c478bd9Sstevel@tonic-gate 	 */
1181*7c478bd9Sstevel@tonic-gate 	n = pp - parts;
1182*7c478bd9Sstevel@tonic-gate 	switch (n) {
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	case 1:				/* a -- 32 bits */
1185*7c478bd9Sstevel@tonic-gate 		val = parts[0];
1186*7c478bd9Sstevel@tonic-gate 		break;
1187*7c478bd9Sstevel@tonic-gate 
1188*7c478bd9Sstevel@tonic-gate 	case 2:				/* a.b -- 8.24 bits */
1189*7c478bd9Sstevel@tonic-gate 		if (parts[1] > 0xffffff)
1190*7c478bd9Sstevel@tonic-gate 		    return ((uint32_t)-1);
1191*7c478bd9Sstevel@tonic-gate 		val = (parts[0] << 24) | (parts[1] & 0xffffff);
1192*7c478bd9Sstevel@tonic-gate 		break;
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate 	case 3:				/* a.b.c -- 8.8.16 bits */
1195*7c478bd9Sstevel@tonic-gate 		if (parts[2] > 0xffff)
1196*7c478bd9Sstevel@tonic-gate 		    return ((uint32_t)-1);
1197*7c478bd9Sstevel@tonic-gate 		val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
1198*7c478bd9Sstevel@tonic-gate 			(parts[2] & 0xffff);
1199*7c478bd9Sstevel@tonic-gate 		break;
1200*7c478bd9Sstevel@tonic-gate 
1201*7c478bd9Sstevel@tonic-gate 	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
1202*7c478bd9Sstevel@tonic-gate 		if (parts[3] > 0xff)
1203*7c478bd9Sstevel@tonic-gate 		    return ((uint32_t)-1);
1204*7c478bd9Sstevel@tonic-gate 		val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
1205*7c478bd9Sstevel@tonic-gate 		    ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
1206*7c478bd9Sstevel@tonic-gate 		break;
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	default:
1209*7c478bd9Sstevel@tonic-gate 		return ((uint32_t)-1);
1210*7c478bd9Sstevel@tonic-gate 	}
1211*7c478bd9Sstevel@tonic-gate 	val = htonl(val);
1212*7c478bd9Sstevel@tonic-gate 	return (val);
1213*7c478bd9Sstevel@tonic-gate }
1214*7c478bd9Sstevel@tonic-gate 
1215*7c478bd9Sstevel@tonic-gate void
1216*7c478bd9Sstevel@tonic-gate hexdump(char *data, int datalen)
1217*7c478bd9Sstevel@tonic-gate {
1218*7c478bd9Sstevel@tonic-gate 	char *p;
1219*7c478bd9Sstevel@tonic-gate 	ushort_t *p16 = (ushort_t *)data;
1220*7c478bd9Sstevel@tonic-gate 	char *p8 = data;
1221*7c478bd9Sstevel@tonic-gate 	int i, left, len;
1222*7c478bd9Sstevel@tonic-gate 	int chunk = 16;  /* 16 bytes per line */
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 	printf("\n");
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 	for (p = data; p < data + datalen; p += chunk) {
1227*7c478bd9Sstevel@tonic-gate 		printf("\t%4d: ", (int)(p - data));
1228*7c478bd9Sstevel@tonic-gate 		left = (data + datalen) - p;
1229*7c478bd9Sstevel@tonic-gate 		len = MIN(chunk, left);
1230*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < (len / 2); i++)
1231*7c478bd9Sstevel@tonic-gate 			printf("%04x ", ntohs(*p16++) & 0xffff);
1232*7c478bd9Sstevel@tonic-gate 		if (len % 2) {
1233*7c478bd9Sstevel@tonic-gate 			printf("%02x   ", *((unsigned char *)p16));
1234*7c478bd9Sstevel@tonic-gate 		}
1235*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < (chunk - left) / 2; i++)
1236*7c478bd9Sstevel@tonic-gate 			printf("     ");
1237*7c478bd9Sstevel@tonic-gate 
1238*7c478bd9Sstevel@tonic-gate 		printf("   ");
1239*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < len; i++, p8++)
1240*7c478bd9Sstevel@tonic-gate 			printf("%c", isprint(*p8) ? *p8 : '.');
1241*7c478bd9Sstevel@tonic-gate 		printf("\n");
1242*7c478bd9Sstevel@tonic-gate 	}
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 	printf("\n");
1245*7c478bd9Sstevel@tonic-gate }
1246