net.c revision 332140
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 * 4. 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__FBSDID("$FreeBSD: stable/11/stand/libsa/net.c 332140 2018-04-06 19:24:04Z kevans $");
40
41#include <sys/param.h>
42#include <sys/socket.h>
43
44#include <string.h>
45
46#include <net/if.h>
47#include <netinet/in.h>
48#include <netinet/if_ether.h>
49#include <netinet/in_systm.h>
50
51#include <netinet/in_pcb.h>
52#include <netinet/ip.h>
53#include <netinet/ip_var.h>
54#include <netinet/udp.h>
55#include <netinet/udp_var.h>
56
57#include "stand.h"
58#include "net.h"
59
60/*
61 * Maximum wait time for sending and receiving before we give up and timeout.
62 * If set to 0, operations will eventually timeout completely, but send/recv
63 * timeouts must progress exponentially from MINTMO to MAXTMO before final
64 * timeout is hit.
65 */
66#ifndef MAXWAIT
67#define MAXWAIT 0	/* seconds */
68#endif
69
70#if MAXWAIT < 0
71#error MAXWAIT must not be a negative number
72#endif
73
74/*
75 * Send a packet and wait for a reply, with exponential backoff.
76 *
77 * The send routine must return the actual number of bytes written,
78 * or -1 on error.
79 *
80 * The receive routine can indicate success by returning the number of
81 * bytes read; it can return 0 to indicate EOF; it can return -1 with a
82 * non-zero errno to indicate failure; finally, it can return -1 with a
83 * zero errno to indicate it isn't done yet.
84 */
85ssize_t
86sendrecv(struct iodesc *d,
87    ssize_t (*sproc)(struct iodesc *, void *, size_t),
88    void *sbuf, size_t ssize,
89    ssize_t (*rproc)(struct iodesc *, void **, void **, time_t, void *),
90    void **pkt, void **payload, void *recv_extra)
91{
92	ssize_t cc;
93	time_t t, tmo, tlast;
94	time_t tref;
95	long tleft;
96
97#ifdef NET_DEBUG
98	if (debug)
99		printf("sendrecv: called\n");
100#endif
101
102	tmo = MINTMO;
103	tlast = 0;
104	tleft = 0;
105	tref = getsecs();
106	t = getsecs();
107	for (;;) {
108		if (MAXWAIT > 0 && (getsecs() - tref) >= MAXWAIT) {
109			errno = ETIMEDOUT;
110			return -1;
111		}
112		if (tleft <= 0) {
113			if (tmo >= MAXTMO) {
114				errno = ETIMEDOUT;
115				return -1;
116			}
117			cc = (*sproc)(d, sbuf, ssize);
118			if (cc != -1 && cc < ssize)
119				panic("sendrecv: short write! (%zd < %zd)",
120				    cc, ssize);
121
122			tleft = tmo;
123			tmo += MINTMO;
124			if (tmo > MAXTMO)
125				tmo = MAXTMO;
126
127			if (cc == -1) {
128				/* Error on transmit; wait before retrying */
129				while ((getsecs() - t) < tmo)
130					;
131				tleft = 0;
132				continue;
133			}
134
135			tlast = t;
136		}
137
138		/* Try to get a packet and process it. */
139		cc = (*rproc)(d, pkt, payload, tleft, recv_extra);
140		/* Return on data, EOF or real error. */
141		if (cc != -1 || (errno != 0 && errno != ETIMEDOUT))
142			return (cc);
143
144		/* Timed out or didn't get the packet we're waiting for */
145		t = getsecs();
146		tleft -= t - tlast;
147		tlast = t;
148	}
149}
150
151/*
152 * Like inet_addr() in the C library, but we only accept base-10.
153 * Return values are in network order.
154 */
155n_long
156inet_addr(char *cp)
157{
158	u_long val;
159	int n;
160	char c;
161	u_int parts[4];
162	u_int *pp = parts;
163
164	for (;;) {
165		/*
166		 * Collect number up to ``.''.
167		 * Values are specified as for C:
168		 * 0x=hex, 0=octal, other=decimal.
169		 */
170		val = 0;
171		while ((c = *cp) != '\0') {
172			if (c >= '0' && c <= '9') {
173				val = (val * 10) + (c - '0');
174				cp++;
175				continue;
176			}
177			break;
178		}
179		if (*cp == '.') {
180			/*
181			 * Internet format:
182			 *	a.b.c.d
183			 *	a.b.c	(with c treated as 16-bits)
184			 *	a.b	(with b treated as 24 bits)
185			 */
186			if (pp >= parts + 3 || val > 0xff)
187				goto bad;
188			*pp++ = val, cp++;
189		} else
190			break;
191	}
192	/*
193	 * Check for trailing characters.
194	 */
195	if (*cp != '\0')
196		goto bad;
197
198	/*
199	 * Concoct the address according to
200	 * the number of parts specified.
201	 */
202	n = pp - parts + 1;
203	switch (n) {
204
205	case 1:				/* a -- 32 bits */
206		break;
207
208	case 2:				/* a.b -- 8.24 bits */
209		if (val > 0xffffff)
210			goto bad;
211		val |= parts[0] << 24;
212		break;
213
214	case 3:				/* a.b.c -- 8.8.16 bits */
215		if (val > 0xffff)
216			goto bad;
217		val |= (parts[0] << 24) | (parts[1] << 16);
218		break;
219
220	case 4:				/* a.b.c.d -- 8.8.8.8 bits */
221		if (val > 0xff)
222			goto bad;
223		val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
224		break;
225	}
226
227	return (htonl(val));
228 bad:
229	return (htonl(INADDR_NONE));
230}
231
232char *
233inet_ntoa(struct in_addr ia)
234{
235	return (intoa(ia.s_addr));
236}
237
238/* Similar to inet_ntoa() */
239char *
240intoa(n_long addr)
241{
242	char *cp;
243	u_int byte;
244	int n;
245	static char buf[17];	/* strlen(".255.255.255.255") + 1 */
246
247	addr = ntohl(addr);
248	cp = &buf[sizeof buf];
249	*--cp = '\0';
250
251	n = 4;
252	do {
253		byte = addr & 0xff;
254		*--cp = byte % 10 + '0';
255		byte /= 10;
256		if (byte > 0) {
257			*--cp = byte % 10 + '0';
258			byte /= 10;
259			if (byte > 0)
260				*--cp = byte + '0';
261		}
262		*--cp = '.';
263		addr >>= 8;
264	} while (--n > 0);
265
266	return (cp+1);
267}
268
269static char *
270number(char *s, int *n)
271{
272	for (*n = 0; isdigit(*s); s++)
273		*n = (*n * 10) + *s - '0';
274	return s;
275}
276
277n_long
278ip_convertaddr(char *p)
279{
280#define IP_ANYADDR	0
281	n_long addr = 0, n;
282
283	if (p == (char *)0 || *p == '\0')
284		return IP_ANYADDR;
285	p = number(p, &n);
286	addr |= (n << 24) & 0xff000000;
287	if (*p == '\0' || *p++ != '.')
288		return IP_ANYADDR;
289	p = number(p, &n);
290	addr |= (n << 16) & 0xff0000;
291	if (*p == '\0' || *p++ != '.')
292		return IP_ANYADDR;
293	p = number(p, &n);
294	addr |= (n << 8) & 0xff00;
295	if (*p == '\0' || *p++ != '.')
296		return IP_ANYADDR;
297	p = number(p, &n);
298	addr |= n & 0xff;
299	if (*p != '\0')
300		return IP_ANYADDR;
301
302	return htonl(addr);
303}
304