/* $NetBSD: net.c,v 1.20 1997/12/26 22:41:30 scottr Exp $ */12/*3* Copyright (c) 1992 Regents of the University of California.4* All rights reserved.5*6* This software was developed by the Computer Systems Engineering group7* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and8* contributed to Berkeley.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18* 3. Neither the name of the University nor the names of its contributors19* may be used to endorse or promote products derived from this software20* without specific prior written permission.21*22* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND23* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE24* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE25* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE26* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL27* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS28* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)29* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT30* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY31* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF32* SUCH DAMAGE.33*/3435#include <sys/param.h>36#include <sys/socket.h>3738#include <string.h>3940#include <net/if.h>41#include <netinet/in.h>42#include <netinet/if_ether.h>43#include <netinet/in_systm.h>4445#include <netinet/ip.h>46#include <netinet/ip_var.h>47#include <netinet/udp.h>48#include <netinet/udp_var.h>4950#include "stand.h"51#include "net.h"5253/*54* Maximum wait time for sending and receiving before we give up and timeout.55* If set to 0, operations will eventually timeout completely, but send/recv56* timeouts must progress exponentially from MINTMO to MAXTMO before final57* timeout is hit.58*/59#ifndef MAXWAIT60#define MAXWAIT 300 /* seconds */61#endif6263#if MAXWAIT < 064#error MAXWAIT must not be a negative number65#endif6667/*68* Send a packet and wait for a reply, with exponential backoff.69*70* The send routine must return the actual number of bytes written,71* or -1 on error.72*73* The receive routine can indicate success by returning the number of74* bytes read; it can return 0 to indicate EOF; it can return -1 with a75* non-zero errno to indicate failure; finally, it can return -1 with a76* zero errno to indicate it isn't done yet.77*/78ssize_t79sendrecv(struct iodesc *d,80ssize_t (*sproc)(struct iodesc *, void *, size_t),81void *sbuf, size_t ssize,82ssize_t (*rproc)(struct iodesc *, void **, void **, time_t, void *),83void **pkt, void **payload, void *recv_extra)84{85ssize_t cc;86time_t t, tmo, tlast;87time_t tref;88long tleft;8990#ifdef NET_DEBUG91if (debug)92printf("sendrecv: called\n");93#endif9495tmo = MINTMO;96tlast = 0;97tleft = 0;98tref = t = getsecs();99for (;;) {100if (MAXWAIT > 0 && (t - tref) >= MAXWAIT) {101errno = ETIMEDOUT;102return -1;103}104if (tleft <= 0) {105if (tmo >= MAXTMO) {106errno = ETIMEDOUT;107return -1;108}109cc = (*sproc)(d, sbuf, ssize);110if (cc != -1 && cc < ssize)111panic("sendrecv: short write! (%zd < %zd)",112cc, ssize);113114tleft = tmo;115tmo += MINTMO;116if (tmo > MAXTMO)117tmo = MAXTMO;118119if (cc == -1) {120/* Error on transmit; wait before retrying */121while ((getsecs() - t) < tmo)122;123tleft = 0;124continue;125}126127tlast = t;128}129130/* Try to get a packet and process it. */131cc = (*rproc)(d, pkt, payload, tleft, recv_extra);132/* Return on data, EOF or real error. */133if (cc != -1 || (errno != 0 && errno != ETIMEDOUT))134return (cc);135136/* Timed out or didn't get the packet we're waiting for */137t = getsecs();138tleft -= t - tlast;139tlast = t;140}141}142143/*144* Like inet_addr() in the C library, but we only accept base-10.145* Return values are in network order.146*/147n_long148inet_addr(char *cp)149{150u_long val;151int n;152char c;153u_int parts[4];154u_int *pp = parts;155156for (;;) {157/*158* Collect number up to ``.''.159* Values are specified as for C:160* 0x=hex, 0=octal, other=decimal.161*/162val = 0;163while ((c = *cp) != '\0') {164if (c >= '0' && c <= '9') {165val = (val * 10) + (c - '0');166cp++;167continue;168}169break;170}171if (*cp == '.') {172/*173* Internet format:174* a.b.c.d175* a.b.c (with c treated as 16-bits)176* a.b (with b treated as 24 bits)177*/178if (pp >= parts + 3 || val > 0xff)179goto bad;180*pp++ = val, cp++;181} else182break;183}184/*185* Check for trailing characters.186*/187if (*cp != '\0')188goto bad;189190/*191* Concoct the address according to192* the number of parts specified.193*/194n = pp - parts + 1;195switch (n) {196197case 1: /* a -- 32 bits */198break;199200case 2: /* a.b -- 8.24 bits */201if (val > 0xffffff)202goto bad;203val |= parts[0] << 24;204break;205206case 3: /* a.b.c -- 8.8.16 bits */207if (val > 0xffff)208goto bad;209val |= (parts[0] << 24) | (parts[1] << 16);210break;211212case 4: /* a.b.c.d -- 8.8.8.8 bits */213if (val > 0xff)214goto bad;215val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);216break;217}218219return (htonl(val));220bad:221return (htonl(INADDR_NONE));222}223224char *225inet_ntoa(struct in_addr ia)226{227return (intoa(ia.s_addr));228}229230/* Similar to inet_ntoa() */231char *232intoa(n_long addr)233{234char *cp;235u_int byte;236int n;237static char buf[17]; /* strlen(".255.255.255.255") + 1 */238239addr = ntohl(addr);240cp = &buf[sizeof buf];241*--cp = '\0';242243n = 4;244do {245byte = addr & 0xff;246*--cp = byte % 10 + '0';247byte /= 10;248if (byte > 0) {249*--cp = byte % 10 + '0';250byte /= 10;251if (byte > 0)252*--cp = byte + '0';253}254*--cp = '.';255addr >>= 8;256} while (--n > 0);257258return (cp+1);259}260261static char *262number(char *s, n_long *n)263{264for (*n = 0; isdigit(*s); s++)265*n = (*n * 10) + *s - '0';266return s;267}268269n_long270ip_convertaddr(char *p)271{272#define IP_ANYADDR 0273n_long addr = 0, n;274275if (p == NULL || *p == '\0')276return IP_ANYADDR;277p = number(p, &n);278addr |= (n << 24) & 0xff000000;279if (*p == '\0' || *p++ != '.')280return IP_ANYADDR;281p = number(p, &n);282addr |= (n << 16) & 0xff0000;283if (*p == '\0' || *p++ != '.')284return IP_ANYADDR;285p = number(p, &n);286addr |= (n << 8) & 0xff00;287if (*p == '\0' || *p++ != '.')288return IP_ANYADDR;289p = number(p, &n);290addr |= n & 0xff;291if (*p != '\0')292return IP_ANYADDR;293294return htonl(addr);295}296297298