[BACK]Return to net.c CVS log [TXT][DIR] Up to [local] / sys / lib / libsa

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