Annotation of sys/lib/libsa/net.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: net.c,v 1.13 2003/08/11 06:23:09 deraadt Exp $ */
2: /* $NetBSD: net.c,v 1.14 1996/10/13 02:29:02 christos Exp $ */
3:
4: /*
5: * Copyright (c) 1992 Regents of the University of California.
6: * All rights reserved.
7: *
8: * This software was developed by the Computer Systems Engineering group
9: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10: * contributed to Berkeley.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the University of
23: * California, Lawrence Berkeley Laboratory and its contributors.
24: * 4. Neither the name of the University nor the names of its contributors
25: * may be used to endorse or promote products derived from this software
26: * without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38: * SUCH DAMAGE.
39: *
40: * @(#) Header: net.c,v 1.9 93/08/06 19:32:15 leres Exp (LBL)
41: */
42:
43: #include <sys/param.h>
44: #include <sys/socket.h>
45:
46: #include <net/if.h>
47: #include <netinet/in.h>
48:
49: #include <netinet/in.h>
50: #include <netinet/if_ether.h>
51: #include <netinet/in_systm.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: /* Caller must leave room for ethernet, ip and udp headers in front!! */
61: ssize_t
62: sendudp(struct iodesc *d, void *pkt, size_t len)
63: {
64: ssize_t cc;
65: struct ip *ip;
66: struct udpiphdr *ui;
67: struct udphdr *uh;
68: u_char *ea;
69: struct ip tip;
70:
71: #ifdef NET_DEBUG
72: if (debug) {
73: printf("sendudp: d=%x called.\n", (u_int)d);
74: if (d) {
75: printf("saddr: %s:%d",
76: inet_ntoa(d->myip), ntohs(d->myport));
77: printf(" daddr: %s:%d\n",
78: inet_ntoa(d->destip), ntohs(d->destport));
79: }
80: }
81: #endif
82:
83: uh = (struct udphdr *)pkt - 1;
84: ip = (struct ip *)uh - 1;
85: len += sizeof(*ip) + sizeof(*uh);
86:
87: bzero(ip, sizeof(*ip) + sizeof(*uh));
88:
89: ip->ip_v = IPVERSION; /* half-char */
90: ip->ip_hl = sizeof(*ip) >> 2; /* half-char */
91: ip->ip_len = htons(len);
92: ip->ip_p = IPPROTO_UDP; /* char */
93: ip->ip_ttl = IP_TTL; /* char */
94: ip->ip_src = d->myip;
95: ip->ip_dst = d->destip;
96: ip->ip_sum = in_cksum(ip, sizeof(*ip)); /* short, but special */
97:
98: uh->uh_sport = d->myport;
99: uh->uh_dport = d->destport;
100: uh->uh_ulen = htons(len - sizeof(*ip));
101:
102: /* Calculate checksum (must save and restore ip header) */
103: tip = *ip;
104: ui = (struct udpiphdr *)ip;
105: bzero(ui->ui_x1, sizeof(ui->ui_x1));
106: ui->ui_len = uh->uh_ulen;
107: uh->uh_sum = in_cksum(ui, len);
108: *ip = tip;
109:
110: if (ip->ip_dst.s_addr == INADDR_BROADCAST || ip->ip_src.s_addr == 0 ||
111: netmask == 0 || SAMENET(ip->ip_src, ip->ip_dst, netmask))
112: ea = arpwhohas(d, ip->ip_dst);
113: else
114: ea = arpwhohas(d, gateip);
115:
116: cc = sendether(d, ip, len, ea, ETHERTYPE_IP);
117: if (cc < 0)
118: return (-1);
119: if ((size_t)cc != len)
120: panic("sendudp: bad write (%d != %d)", cc, len);
121: return (cc - (sizeof(*ip) + sizeof(*uh)));
122: }
123:
124: /*
125: * Receive a UDP packet and validate it is for us.
126: * Caller leaves room for the headers (Ether, IP, UDP)
127: */
128: ssize_t
129: readudp(struct iodesc *d, void *pkt, size_t len, time_t tleft)
130: {
131: ssize_t n;
132: size_t hlen;
133: struct ip *ip;
134: struct udphdr *uh;
135: struct udpiphdr *ui;
136: struct ip tip;
137: u_int16_t etype; /* host order */
138:
139: #ifdef NET_DEBUG
140: if (debug)
141: printf("readudp: called\n");
142: #endif
143:
144: uh = (struct udphdr *)pkt - 1;
145: ip = (struct ip *)uh - 1;
146:
147: n = readether(d, ip, len + sizeof(*ip) + sizeof(*uh), tleft, &etype);
148: if (n < 0 || (size_t)n < sizeof(*ip) + sizeof(*uh))
149: return -1;
150:
151: /* Ethernet address checks now in readether() */
152:
153: /* Need to respond to ARP requests. */
154: if (etype == ETHERTYPE_ARP) {
155: struct arphdr *ah = (void *)ip;
156: if (ah->ar_op == htons(ARPOP_REQUEST)) {
157: /* Send ARP reply */
158: arp_reply(d, ah);
159: }
160: return -1;
161: }
162:
163: if (etype != ETHERTYPE_IP) {
164: #ifdef NET_DEBUG
165: if (debug)
166: printf("readudp: not IP. ether_type=%x\n", etype);
167: #endif
168: return -1;
169: }
170:
171: /* Check ip header */
172: if (ip->ip_v != IPVERSION ||
173: ip->ip_p != IPPROTO_UDP) { /* half char */
174: #ifdef NET_DEBUG
175: if (debug)
176: printf("readudp: IP version or not UDP. ip_v=%d ip_p=%d\n", ip->ip_v, ip->ip_p);
177: #endif
178: return -1;
179: }
180:
181: hlen = ip->ip_hl << 2;
182: if (hlen < sizeof(*ip) ||
183: in_cksum(ip, hlen) != 0) {
184: #ifdef NET_DEBUG
185: if (debug)
186: printf("readudp: short hdr or bad cksum.\n");
187: #endif
188: return -1;
189: }
190: NTOHS(ip->ip_len);
191: if (n < ip->ip_len) {
192: #ifdef NET_DEBUG
193: if (debug)
194: printf("readudp: bad length %d < %d.\n", n, ip->ip_len);
195: #endif
196: return -1;
197: }
198: if (d->myip.s_addr && ip->ip_dst.s_addr != d->myip.s_addr) {
199: #ifdef NET_DEBUG
200: if (debug) {
201: printf("readudp: bad saddr %s != ", inet_ntoa(d->myip));
202: printf("%s\n", inet_ntoa(ip->ip_dst));
203: }
204: #endif
205: return -1;
206: }
207:
208: /* If there were ip options, make them go away */
209: if (hlen != sizeof(*ip)) {
210: bcopy(((u_char *)ip) + hlen, uh, len - hlen);
211: ip->ip_len = sizeof(*ip);
212: n -= hlen - sizeof(*ip);
213: }
214: if (uh->uh_dport != d->myport) {
215: #ifdef NET_DEBUG
216: if (debug)
217: printf("readudp: bad dport %d != %d\n",
218: d->myport, ntohs(uh->uh_dport));
219: #endif
220: return -1;
221: }
222:
223: if (uh->uh_sum) {
224: n = ntohs(uh->uh_ulen) + sizeof(*ip);
225: if (n > RECV_SIZE - ETHER_SIZE) {
226: printf("readudp: huge packet, udp len %ld\n", (long)n);
227: return -1;
228: }
229:
230: /* Check checksum (must save and restore ip header) */
231: tip = *ip;
232: ui = (struct udpiphdr *)ip;
233: bzero(ui->ui_x1, sizeof(ui->ui_x1));
234: ui->ui_len = uh->uh_ulen;
235: if (in_cksum(ui, n) != 0) {
236: #ifdef NET_DEBUG
237: if (debug)
238: printf("readudp: bad cksum\n");
239: #endif
240: *ip = tip;
241: return -1;
242: }
243: *ip = tip;
244: }
245: NTOHS(uh->uh_dport);
246: NTOHS(uh->uh_sport);
247: NTOHS(uh->uh_ulen);
248: if (uh->uh_ulen < sizeof(*uh)) {
249: #ifdef NET_DEBUG
250: if (debug)
251: printf("readudp: bad udp len %d < %d\n",
252: uh->uh_ulen, sizeof(*uh));
253: #endif
254: return -1;
255: }
256:
257: n -= sizeof(*ip) + sizeof(*uh);
258: return (n);
259: }
260:
261: /*
262: * Send a packet and wait for a reply, with exponential backoff.
263: *
264: * The send routine must return the actual number of bytes written.
265: *
266: * The receive routine can indicate success by returning the number of
267: * bytes read; it can return 0 to indicate EOF; it can return -1 with a
268: * non-zero errno to indicate failure; finally, it can return -1 with a
269: * zero errno to indicate it isn't done yet.
270: */
271: ssize_t
272: sendrecv(struct iodesc *d, ssize_t (*sproc)(struct iodesc *, void *, size_t),
273: void *sbuf, size_t ssize,
274: ssize_t (*rproc)(struct iodesc *, void *, size_t, time_t),
275: void *rbuf, size_t rsize)
276: {
277: ssize_t cc;
278: time_t t, tmo, tlast;
279: long tleft;
280:
281: #ifdef NET_DEBUG
282: if (debug)
283: printf("sendrecv: called\n");
284: #endif
285:
286: tmo = MINTMO;
287: tlast = tleft = 0;
288: t = getsecs();
289: for (;;) {
290: if (tleft <= 0) {
291: if (tmo >= MAXTMO) {
292: errno = ETIMEDOUT;
293: return -1;
294: }
295: cc = (*sproc)(d, sbuf, ssize);
296: if (cc < 0 || (size_t)cc < ssize)
297: panic("sendrecv: short write! (%d < %d)",
298: cc, ssize);
299:
300: tleft = tmo;
301: tmo <<= 1;
302: if (tmo > MAXTMO)
303: tmo = MAXTMO;
304: tlast = t;
305: }
306:
307: /* Try to get a packet and process it. */
308: cc = (*rproc)(d, rbuf, rsize, tleft);
309: /* Return on data, EOF or real error. */
310: if (cc != -1 || errno != 0)
311: return (cc);
312:
313: /* Timed out or didn't get the packet we're waiting for */
314: t = getsecs();
315: tleft -= t - tlast;
316: tlast = t;
317: }
318: }
319:
320: /*
321: * Like inet_addr() in the C library, but we only accept base-10.
322: * Return values are in network order.
323: */
324: n_long
325: inet_addr(char *cp)
326: {
327: u_long val;
328: int n;
329: char c;
330: u_int parts[4];
331: u_int *pp = parts;
332:
333: for (;;) {
334: /*
335: * Collect number up to ``.''.
336: * Values are specified as for C:
337: * 0x=hex, 0=octal, other=decimal.
338: */
339: val = 0;
340: while ((c = *cp) != '\0') {
341: if (c >= '0' && c <= '9') {
342: val = (val * 10) + (c - '0');
343: cp++;
344: continue;
345: }
346: break;
347: }
348: if (*cp == '.') {
349: /*
350: * Internet format:
351: * a.b.c.d
352: * a.b.c (with c treated as 16-bits)
353: * a.b (with b treated as 24 bits)
354: */
355: if (pp >= parts + 3 || val > 0xff)
356: goto bad;
357: *pp++ = val, cp++;
358: } else
359: break;
360: }
361: /*
362: * Check for trailing characters.
363: */
364: if (*cp != '\0')
365: goto bad;
366:
367: /*
368: * Concoct the address according to
369: * the number of parts specified.
370: */
371: n = pp - parts + 1;
372: switch (n) {
373:
374: case 1: /* a -- 32 bits */
375: break;
376:
377: case 2: /* a.b -- 8.24 bits */
378: if (val > 0xffffff)
379: goto bad;
380: val |= parts[0] << 24;
381: break;
382:
383: case 3: /* a.b.c -- 8.8.16 bits */
384: if (val > 0xffff)
385: goto bad;
386: val |= (parts[0] << 24) | (parts[1] << 16);
387: break;
388:
389: case 4: /* a.b.c.d -- 8.8.8.8 bits */
390: if (val > 0xff)
391: goto bad;
392: val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
393: break;
394: }
395:
396: return (htonl(val));
397: bad:
398: return (htonl(INADDR_NONE));
399: }
400:
401: char *
402: inet_ntoa(struct in_addr ia)
403: {
404: return (intoa(ia.s_addr));
405: }
406:
407: /* Similar to inet_ntoa() */
408: char *
409: intoa(n_long addr)
410: {
411: char *cp;
412: u_int byte;
413: int n;
414: static char buf[sizeof(".255.255.255.255")];
415:
416: NTOHL(addr);
417: cp = &buf[sizeof buf];
418: *--cp = '\0';
419:
420: n = 4;
421: do {
422: byte = addr & 0xff;
423: *--cp = byte % 10 + '0';
424: byte /= 10;
425: if (byte > 0) {
426: *--cp = byte % 10 + '0';
427: byte /= 10;
428: if (byte > 0)
429: *--cp = byte + '0';
430: }
431: *--cp = '.';
432: addr >>= 8;
433: } while (--n > 0);
434:
435: return (cp+1);
436: }
437:
438: static char *
439: number(char *s, int *n)
440: {
441: for (*n = 0; isdigit(*s); s++)
442: *n = (*n * 10) + *s - '0';
443: return s;
444: }
445:
446: n_long
447: ip_convertaddr(char *p)
448: {
449: #define IP_ANYADDR 0
450: n_long addr = 0, n;
451:
452: if (p == (char *)0 || *p == '\0')
453: return IP_ANYADDR;
454: p = number(p, &n);
455: addr |= (n << 24) & 0xff000000;
456: if (*p == '\0' || *p++ != '.')
457: return IP_ANYADDR;
458: p = number(p, &n);
459: addr |= (n << 16) & 0xff0000;
460: if (*p == '\0' || *p++ != '.')
461: return IP_ANYADDR;
462: p = number(p, &n);
463: addr |= (n << 8) & 0xff00;
464: if (*p == '\0' || *p++ != '.')
465: return IP_ANYADDR;
466: p = number(p, &n);
467: addr |= n & 0xff;
468: if (*p != '\0')
469: return IP_ANYADDR;
470:
471: return htonl(addr);
472: }
CVSweb