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