xref: /titanic_52/usr/src/boot/lib/libstand/net.c (revision 4a5d661a82b942b6538acd26209d959ce98b593a)
1*4a5d661aSToomas Soome /*	$NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $	*/
2*4a5d661aSToomas Soome 
3*4a5d661aSToomas Soome /*
4*4a5d661aSToomas Soome  * Copyright (c) 1992 Regents of the University of California.
5*4a5d661aSToomas Soome  * All rights reserved.
6*4a5d661aSToomas Soome  *
7*4a5d661aSToomas Soome  * This software was developed by the Computer Systems Engineering group
8*4a5d661aSToomas Soome  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9*4a5d661aSToomas Soome  * contributed to Berkeley.
10*4a5d661aSToomas Soome  *
11*4a5d661aSToomas Soome  * Redistribution and use in source and binary forms, with or without
12*4a5d661aSToomas Soome  * modification, are permitted provided that the following conditions
13*4a5d661aSToomas Soome  * are met:
14*4a5d661aSToomas Soome  * 1. Redistributions of source code must retain the above copyright
15*4a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer.
16*4a5d661aSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
17*4a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
18*4a5d661aSToomas Soome  *    documentation and/or other materials provided with the distribution.
19*4a5d661aSToomas Soome  * 4. Neither the name of the University nor the names of its contributors
20*4a5d661aSToomas Soome  *    may be used to endorse or promote products derived from this software
21*4a5d661aSToomas Soome  *    without specific prior written permission.
22*4a5d661aSToomas Soome  *
23*4a5d661aSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24*4a5d661aSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25*4a5d661aSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26*4a5d661aSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27*4a5d661aSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28*4a5d661aSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29*4a5d661aSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30*4a5d661aSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31*4a5d661aSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32*4a5d661aSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33*4a5d661aSToomas Soome  * SUCH DAMAGE.
34*4a5d661aSToomas Soome  *
35*4a5d661aSToomas Soome  * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp  (LBL)
36*4a5d661aSToomas Soome  */
37*4a5d661aSToomas Soome 
38*4a5d661aSToomas Soome #include <sys/cdefs.h>
39*4a5d661aSToomas Soome __FBSDID("$FreeBSD$");
40*4a5d661aSToomas Soome 
41*4a5d661aSToomas Soome #include <sys/param.h>
42*4a5d661aSToomas Soome #include <sys/socket.h>
43*4a5d661aSToomas Soome 
44*4a5d661aSToomas Soome #include <string.h>
45*4a5d661aSToomas Soome 
46*4a5d661aSToomas Soome #include <net/if.h>
47*4a5d661aSToomas Soome #include <netinet/in.h>
48*4a5d661aSToomas Soome #include <netinet/if_ether.h>
49*4a5d661aSToomas Soome #include <netinet/in_systm.h>
50*4a5d661aSToomas Soome 
51*4a5d661aSToomas Soome #include <netinet/in_pcb.h>
52*4a5d661aSToomas Soome #include <netinet/ip.h>
53*4a5d661aSToomas Soome #include <netinet/ip_var.h>
54*4a5d661aSToomas Soome #include <netinet/udp.h>
55*4a5d661aSToomas Soome #include <netinet/udp_var.h>
56*4a5d661aSToomas Soome 
57*4a5d661aSToomas Soome #include "stand.h"
58*4a5d661aSToomas Soome #include "net.h"
59*4a5d661aSToomas Soome 
60*4a5d661aSToomas Soome /*
61*4a5d661aSToomas Soome  * Send a packet and wait for a reply, with exponential backoff.
62*4a5d661aSToomas Soome  *
63*4a5d661aSToomas Soome  * The send routine must return the actual number of bytes written,
64*4a5d661aSToomas Soome  * or -1 on error.
65*4a5d661aSToomas Soome  *
66*4a5d661aSToomas Soome  * The receive routine can indicate success by returning the number of
67*4a5d661aSToomas Soome  * bytes read; it can return 0 to indicate EOF; it can return -1 with a
68*4a5d661aSToomas Soome  * non-zero errno to indicate failure; finally, it can return -1 with a
69*4a5d661aSToomas Soome  * zero errno to indicate it isn't done yet.
70*4a5d661aSToomas Soome  */
71*4a5d661aSToomas Soome ssize_t
72*4a5d661aSToomas Soome sendrecv(struct iodesc *d,
73*4a5d661aSToomas Soome 	ssize_t (*sproc)(struct iodesc *, void *, size_t),
74*4a5d661aSToomas Soome 	void *sbuf, size_t ssize,
75*4a5d661aSToomas Soome 	ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t),
76*4a5d661aSToomas Soome 	void *rbuf, size_t rsize)
77*4a5d661aSToomas Soome {
78*4a5d661aSToomas Soome 	ssize_t cc;
79*4a5d661aSToomas Soome 	time_t t, tmo, tlast;
80*4a5d661aSToomas Soome 	long tleft;
81*4a5d661aSToomas Soome 
82*4a5d661aSToomas Soome #ifdef NET_DEBUG
83*4a5d661aSToomas Soome 	if (debug)
84*4a5d661aSToomas Soome 		printf("sendrecv: called\n");
85*4a5d661aSToomas Soome #endif
86*4a5d661aSToomas Soome 
87*4a5d661aSToomas Soome 	tmo = MINTMO;
88*4a5d661aSToomas Soome 	tlast = 0;
89*4a5d661aSToomas Soome 	tleft = 0;
90*4a5d661aSToomas Soome 	t = getsecs();
91*4a5d661aSToomas Soome 	for (;;) {
92*4a5d661aSToomas Soome 		if (tleft <= 0) {
93*4a5d661aSToomas Soome 			if (tmo >= MAXTMO) {
94*4a5d661aSToomas Soome 				errno = ETIMEDOUT;
95*4a5d661aSToomas Soome 				return -1;
96*4a5d661aSToomas Soome 			}
97*4a5d661aSToomas Soome 			cc = (*sproc)(d, sbuf, ssize);
98*4a5d661aSToomas Soome 			if (cc != -1 && cc < ssize)
99*4a5d661aSToomas Soome 				panic("sendrecv: short write! (%zd < %zd)",
100*4a5d661aSToomas Soome 				    cc, ssize);
101*4a5d661aSToomas Soome 
102*4a5d661aSToomas Soome 			tleft = tmo;
103*4a5d661aSToomas Soome 			tmo += MINTMO;
104*4a5d661aSToomas Soome 			if (tmo > MAXTMO)
105*4a5d661aSToomas Soome 				tmo = MAXTMO;
106*4a5d661aSToomas Soome 
107*4a5d661aSToomas Soome 			if (cc == -1) {
108*4a5d661aSToomas Soome 				/* Error on transmit; wait before retrying */
109*4a5d661aSToomas Soome 				while ((getsecs() - t) < tmo)
110*4a5d661aSToomas Soome 					;
111*4a5d661aSToomas Soome 				tleft = 0;
112*4a5d661aSToomas Soome 				continue;
113*4a5d661aSToomas Soome 			}
114*4a5d661aSToomas Soome 
115*4a5d661aSToomas Soome 			tlast = t;
116*4a5d661aSToomas Soome 		}
117*4a5d661aSToomas Soome 
118*4a5d661aSToomas Soome 		/* Try to get a packet and process it. */
119*4a5d661aSToomas Soome 		cc = (*rproc)(d, rbuf, rsize, tleft);
120*4a5d661aSToomas Soome 		/* Return on data, EOF or real error. */
121*4a5d661aSToomas Soome 		if (cc != -1 || errno != 0)
122*4a5d661aSToomas Soome 			return (cc);
123*4a5d661aSToomas Soome 
124*4a5d661aSToomas Soome 		/* Timed out or didn't get the packet we're waiting for */
125*4a5d661aSToomas Soome 		t = getsecs();
126*4a5d661aSToomas Soome 		tleft -= t - tlast;
127*4a5d661aSToomas Soome 		tlast = t;
128*4a5d661aSToomas Soome 	}
129*4a5d661aSToomas Soome }
130*4a5d661aSToomas Soome 
131*4a5d661aSToomas Soome /*
132*4a5d661aSToomas Soome  * Like inet_addr() in the C library, but we only accept base-10.
133*4a5d661aSToomas Soome  * Return values are in network order.
134*4a5d661aSToomas Soome  */
135*4a5d661aSToomas Soome n_long
136*4a5d661aSToomas Soome inet_addr(char *cp)
137*4a5d661aSToomas Soome {
138*4a5d661aSToomas Soome 	u_long val;
139*4a5d661aSToomas Soome 	int n;
140*4a5d661aSToomas Soome 	char c;
141*4a5d661aSToomas Soome 	u_int parts[4];
142*4a5d661aSToomas Soome 	u_int *pp = parts;
143*4a5d661aSToomas Soome 
144*4a5d661aSToomas Soome 	for (;;) {
145*4a5d661aSToomas Soome 		/*
146*4a5d661aSToomas Soome 		 * Collect number up to ``.''.
147*4a5d661aSToomas Soome 		 * Values are specified as for C:
148*4a5d661aSToomas Soome 		 * 0x=hex, 0=octal, other=decimal.
149*4a5d661aSToomas Soome 		 */
150*4a5d661aSToomas Soome 		val = 0;
151*4a5d661aSToomas Soome 		while ((c = *cp) != '\0') {
152*4a5d661aSToomas Soome 			if (c >= '0' && c <= '9') {
153*4a5d661aSToomas Soome 				val = (val * 10) + (c - '0');
154*4a5d661aSToomas Soome 				cp++;
155*4a5d661aSToomas Soome 				continue;
156*4a5d661aSToomas Soome 			}
157*4a5d661aSToomas Soome 			break;
158*4a5d661aSToomas Soome 		}
159*4a5d661aSToomas Soome 		if (*cp == '.') {
160*4a5d661aSToomas Soome 			/*
161*4a5d661aSToomas Soome 			 * Internet format:
162*4a5d661aSToomas Soome 			 *	a.b.c.d
163*4a5d661aSToomas Soome 			 *	a.b.c	(with c treated as 16-bits)
164*4a5d661aSToomas Soome 			 *	a.b	(with b treated as 24 bits)
165*4a5d661aSToomas Soome 			 */
166*4a5d661aSToomas Soome 			if (pp >= parts + 3 || val > 0xff)
167*4a5d661aSToomas Soome 				goto bad;
168*4a5d661aSToomas Soome 			*pp++ = val, cp++;
169*4a5d661aSToomas Soome 		} else
170*4a5d661aSToomas Soome 			break;
171*4a5d661aSToomas Soome 	}
172*4a5d661aSToomas Soome 	/*
173*4a5d661aSToomas Soome 	 * Check for trailing characters.
174*4a5d661aSToomas Soome 	 */
175*4a5d661aSToomas Soome 	if (*cp != '\0')
176*4a5d661aSToomas Soome 		goto bad;
177*4a5d661aSToomas Soome 
178*4a5d661aSToomas Soome 	/*
179*4a5d661aSToomas Soome 	 * Concoct the address according to
180*4a5d661aSToomas Soome 	 * the number of parts specified.
181*4a5d661aSToomas Soome 	 */
182*4a5d661aSToomas Soome 	n = pp - parts + 1;
183*4a5d661aSToomas Soome 	switch (n) {
184*4a5d661aSToomas Soome 
185*4a5d661aSToomas Soome 	case 1:				/* a -- 32 bits */
186*4a5d661aSToomas Soome 		break;
187*4a5d661aSToomas Soome 
188*4a5d661aSToomas Soome 	case 2:				/* a.b -- 8.24 bits */
189*4a5d661aSToomas Soome 		if (val > 0xffffff)
190*4a5d661aSToomas Soome 			goto bad;
191*4a5d661aSToomas Soome 		val |= parts[0] << 24;
192*4a5d661aSToomas Soome 		break;
193*4a5d661aSToomas Soome 
194*4a5d661aSToomas Soome 	case 3:				/* a.b.c -- 8.8.16 bits */
195*4a5d661aSToomas Soome 		if (val > 0xffff)
196*4a5d661aSToomas Soome 			goto bad;
197*4a5d661aSToomas Soome 		val |= (parts[0] << 24) | (parts[1] << 16);
198*4a5d661aSToomas Soome 		break;
199*4a5d661aSToomas Soome 
200*4a5d661aSToomas Soome 	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
201*4a5d661aSToomas Soome 		if (val > 0xff)
202*4a5d661aSToomas Soome 			goto bad;
203*4a5d661aSToomas Soome 		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
204*4a5d661aSToomas Soome 		break;
205*4a5d661aSToomas Soome 	}
206*4a5d661aSToomas Soome 
207*4a5d661aSToomas Soome 	return (htonl(val));
208*4a5d661aSToomas Soome  bad:
209*4a5d661aSToomas Soome 	return (htonl(INADDR_NONE));
210*4a5d661aSToomas Soome }
211*4a5d661aSToomas Soome 
212*4a5d661aSToomas Soome char *
213*4a5d661aSToomas Soome inet_ntoa(struct in_addr ia)
214*4a5d661aSToomas Soome {
215*4a5d661aSToomas Soome 	return (intoa(ia.s_addr));
216*4a5d661aSToomas Soome }
217*4a5d661aSToomas Soome 
218*4a5d661aSToomas Soome /* Similar to inet_ntoa() */
219*4a5d661aSToomas Soome char *
220*4a5d661aSToomas Soome intoa(n_long addr)
221*4a5d661aSToomas Soome {
222*4a5d661aSToomas Soome 	char *cp;
223*4a5d661aSToomas Soome 	u_int byte;
224*4a5d661aSToomas Soome 	int n;
225*4a5d661aSToomas Soome 	static char buf[17];	/* strlen(".255.255.255.255") + 1 */
226*4a5d661aSToomas Soome 
227*4a5d661aSToomas Soome 	addr = ntohl(addr);
228*4a5d661aSToomas Soome 	cp = &buf[sizeof buf];
229*4a5d661aSToomas Soome 	*--cp = '\0';
230*4a5d661aSToomas Soome 
231*4a5d661aSToomas Soome 	n = 4;
232*4a5d661aSToomas Soome 	do {
233*4a5d661aSToomas Soome 		byte = addr & 0xff;
234*4a5d661aSToomas Soome 		*--cp = byte % 10 + '0';
235*4a5d661aSToomas Soome 		byte /= 10;
236*4a5d661aSToomas Soome 		if (byte > 0) {
237*4a5d661aSToomas Soome 			*--cp = byte % 10 + '0';
238*4a5d661aSToomas Soome 			byte /= 10;
239*4a5d661aSToomas Soome 			if (byte > 0)
240*4a5d661aSToomas Soome 				*--cp = byte + '0';
241*4a5d661aSToomas Soome 		}
242*4a5d661aSToomas Soome 		*--cp = '.';
243*4a5d661aSToomas Soome 		addr >>= 8;
244*4a5d661aSToomas Soome 	} while (--n > 0);
245*4a5d661aSToomas Soome 
246*4a5d661aSToomas Soome 	return (cp+1);
247*4a5d661aSToomas Soome }
248*4a5d661aSToomas Soome 
249*4a5d661aSToomas Soome static char *
250*4a5d661aSToomas Soome number(char *s, int *n)
251*4a5d661aSToomas Soome {
252*4a5d661aSToomas Soome 	for (*n = 0; isdigit(*s); s++)
253*4a5d661aSToomas Soome 		*n = (*n * 10) + *s - '0';
254*4a5d661aSToomas Soome 	return s;
255*4a5d661aSToomas Soome }
256*4a5d661aSToomas Soome 
257*4a5d661aSToomas Soome n_long
258*4a5d661aSToomas Soome ip_convertaddr(char *p)
259*4a5d661aSToomas Soome {
260*4a5d661aSToomas Soome #define IP_ANYADDR	0
261*4a5d661aSToomas Soome 	n_long addr = 0, n;
262*4a5d661aSToomas Soome 
263*4a5d661aSToomas Soome 	if (p == (char *)0 || *p == '\0')
264*4a5d661aSToomas Soome 		return IP_ANYADDR;
265*4a5d661aSToomas Soome 	p = number(p, &n);
266*4a5d661aSToomas Soome 	addr |= (n << 24) & 0xff000000;
267*4a5d661aSToomas Soome 	if (*p == '\0' || *p++ != '.')
268*4a5d661aSToomas Soome 		return IP_ANYADDR;
269*4a5d661aSToomas Soome 	p = number(p, &n);
270*4a5d661aSToomas Soome 	addr |= (n << 16) & 0xff0000;
271*4a5d661aSToomas Soome 	if (*p == '\0' || *p++ != '.')
272*4a5d661aSToomas Soome 		return IP_ANYADDR;
273*4a5d661aSToomas Soome 	p = number(p, &n);
274*4a5d661aSToomas Soome 	addr |= (n << 8) & 0xff00;
275*4a5d661aSToomas Soome 	if (*p == '\0' || *p++ != '.')
276*4a5d661aSToomas Soome 		return IP_ANYADDR;
277*4a5d661aSToomas Soome 	p = number(p, &n);
278*4a5d661aSToomas Soome 	addr |= n & 0xff;
279*4a5d661aSToomas Soome 	if (*p != '\0')
280*4a5d661aSToomas Soome 		return IP_ANYADDR;
281*4a5d661aSToomas Soome 
282*4a5d661aSToomas Soome 	return htonl(addr);
283*4a5d661aSToomas Soome }
284