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