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