akaros/user/iplib/readipifc.c
<<
>>
Prefs
   1/*
   2 * This file is part of the UCB release of Plan 9. It is subject to the license
   3 * terms in the LICENSE file found in the top-level directory of this
   4 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
   5 * part of the UCB release of Plan 9, including this file, may be copied,
   6 * modified, propagated, or distributed except according to the terms contained
   7 * in the LICENSE file.
   8 */
   9#include <stdlib.h>
  10
  11#include <iplib/iplib.h>
  12#include <parlib/parlib.h>
  13#include <signal.h>
  14#include <stdio.h>
  15#include <unistd.h>
  16
  17#include <dirent.h>
  18#include <fcntl.h>
  19#include <sys/stat.h>
  20#include <sys/types.h>
  21
  22static uint8_t loopbacknet[IPaddrlen] = {
  23        0, 0, 0, 0,
  24        0, 0, 0, 0,
  25        0, 0, 0xff, 0xff,
  26        127, 0, 0, 0
  27};
  28static uint8_t loopbackmask[IPaddrlen] = {
  29        0xff, 0xff, 0xff, 0xff,
  30        0xff, 0xff, 0xff, 0xff,
  31        0xff, 0xff, 0xff, 0xff,
  32        0xff, 0, 0, 0
  33};
  34
  35#define NFIELD 200
  36#define nelem(x) (sizeof(x) / sizeof(x[0]))
  37static struct ipifc **_readoldipifc(char *buf, struct ipifc **l, int index)
  38{
  39        char *f[NFIELD];
  40        int i, n;
  41        struct ipifc *ifc;
  42        struct iplifc *lifc, **ll;
  43
  44        /* allocate new interface */
  45        *l = ifc = calloc(sizeof(struct ipifc), 1);
  46        if (ifc == NULL)
  47                return l;
  48        l = &ifc->next;
  49        ifc->index = index;
  50
  51        n = tokenize(buf, f, NFIELD);
  52        if (n < 2)
  53                return l;
  54
  55        strncpy(ifc->dev, f[0], sizeof ifc->dev);
  56        ifc->dev[sizeof(ifc->dev) - 1] = 0;
  57        ifc->mtu = strtoul(f[1], NULL, 10);
  58
  59        ll = &ifc->lifc;
  60        for (i = 2; n - i >= 7; i += 7) {
  61                /* allocate new local address */
  62                *ll = lifc = calloc(sizeof(struct iplifc), 1);
  63                ll = &lifc->next;
  64
  65                parseip(lifc->ip, f[i]);
  66                parseipmask(lifc->mask, f[i + 1]);
  67                parseip(lifc->net, f[i + 2]);
  68                ifc->pktin = strtoul(f[i + 3], NULL, 10);
  69                ifc->pktout = strtoul(f[i + 4], NULL, 10);
  70                ifc->errin = strtoul(f[i + 5], NULL, 10);
  71                ifc->errout = strtoul(f[i + 6], NULL, 10);
  72        }
  73        return l;
  74}
  75
  76static char *findfield(char *name, char **f, int n)
  77{
  78        int i;
  79
  80        for (i = 0; i < n - 1; i++)
  81                if (strcmp(f[i], name) == 0)
  82                        return f[i + 1];
  83        return "";
  84}
  85
  86static struct ipifc **_readipifc(char *file, struct ipifc **l, int index)
  87{
  88        int i, n, fd, lines;
  89        char buf[4 * 1024];
  90        char *line[32];
  91        char *f[64];
  92        struct ipifc *ifc, **l0;
  93        struct iplifc *lifc, **ll;
  94
  95        /* read the file */
  96        fd = open(file, O_RDONLY);
  97        if (fd < 0)
  98                return l;
  99        n = 0;
 100        while ((i = read(fd, buf + n, sizeof(buf) - 1 - n)) > 0 &&
 101               n < sizeof(buf) - 1)
 102                n += i;
 103        buf[n] = 0;
 104        close(fd);
 105
 106        if (strncmp(buf, "device", 6) != 0)
 107                return _readoldipifc(buf, l, index);
 108        /* ignore ifcs with no associated device */
 109        if (strncmp(buf + 6, "  ", 2) == 0)
 110                return l;
 111        /* allocate new interface */
 112        *l = ifc = calloc(sizeof(struct ipifc), 1);
 113        if (ifc == NULL)
 114                return l;
 115        l0 = l;
 116        l = &ifc->next;
 117        ifc->index = index;
 118
 119        lines = getfields(buf, line, nelem(line), 1, "\n");
 120
 121        /* pick off device specific info(first line) */
 122        n = tokenize(line[0], f, nelem(f));
 123        if (n % 2 != 0)
 124                goto lose;
 125        strncpy(ifc->dev, findfield("device", f, n), sizeof(ifc->dev));
 126        ifc->dev[sizeof(ifc->dev) - 1] = 0;
 127        if (ifc->dev[0] == 0) {
 128        lose:
 129                free(ifc);
 130                *l0 = NULL;
 131                return l;
 132        }
 133        ifc->mtu = strtoul(findfield("maxtu", f, n), NULL, 10);
 134        ifc->sendra6 = atoi(findfield("sendra", f, n));
 135        ifc->recvra6 = atoi(findfield("recvra", f, n));
 136        ifc->rp.mflag = atoi(findfield("mflag", f, n));
 137        ifc->rp.oflag = atoi(findfield("oflag", f, n));
 138        ifc->rp.maxraint = atoi(findfield("maxraint", f, n));
 139        ifc->rp.minraint = atoi(findfield("minraint", f, n));
 140        ifc->rp.linkmtu = atoi(findfield("linkmtu", f, n));
 141        ifc->rp.reachtime = atoi(findfield("reachtime", f, n));
 142        ifc->rp.rxmitra = atoi(findfield("rxmitra", f, n));
 143        ifc->rp.ttl = atoi(findfield("ttl", f, n));
 144        ifc->rp.routerlt = atoi(findfield("routerlt", f, n));
 145        ifc->pktin = strtoul(findfield("pktin", f, n), NULL, 10);
 146        ifc->pktout = strtoul(findfield("pktout", f, n), NULL, 10);
 147        ifc->errin = strtoul(findfield("errin", f, n), NULL, 10);
 148        ifc->errout = strtoul(findfield("errout", f, n), NULL, 10);
 149
 150        /* now read the addresses */
 151        ll = &ifc->lifc;
 152        for (i = 1; i < lines; i++) {
 153                n = tokenize(line[i], f, nelem(f));
 154                if (n < 5)
 155                        break;
 156
 157                /* allocate new local address */
 158                *ll = lifc = calloc(sizeof(struct iplifc), 1);
 159                ll = &lifc->next;
 160
 161                parseip(lifc->ip, f[0]);
 162                parseipmask(lifc->mask, f[1]);
 163                parseip(lifc->net, f[2]);
 164
 165                lifc->validlt = strtoul(f[3], NULL, 10);
 166                lifc->preflt = strtoul(f[4], NULL, 10);
 167        }
 168
 169        return l;
 170}
 171
 172void free_ipifc(struct ipifc *ifc)
 173{
 174        struct ipifc *next;
 175        struct iplifc *lnext, *lifc;
 176
 177        if (ifc == NULL)
 178                return;
 179        for (; ifc; ifc = next) {
 180                next = ifc->next;
 181                for (lifc = ifc->lifc; lifc; lifc = lnext) {
 182                        lnext = lifc->next;
 183                        free(lifc);
 184                }
 185                free(ifc);
 186        }
 187}
 188
 189/* This will free @ifc when passed in.  Some old Plan 9 programs might rely on
 190 * it still (like our ping, netstat, ipconfig).  It usually ends up be a
 191 * thread-unsafe disaster. */
 192struct ipifc *readipifc(char *net, struct ipifc *ifc, int index)
 193{
 194        int fd, i, n;
 195        struct dir *dir;
 196        char directory[128];
 197        char buf[128];
 198        struct ipifc **l;
 199
 200        free_ipifc(ifc);
 201
 202        l = &ifc;
 203        ifc = NULL;
 204
 205        if (net == 0)
 206                net = "/net";
 207        snprintf(directory, sizeof(directory), "%s/ipifc", net);
 208
 209        if (index >= 0) {
 210                snprintf(buf, sizeof(buf), "%s/%d/status", directory, index);
 211                _readipifc(buf, l, index);
 212        } else {
 213                DIR *d;
 214                struct dirent *de;
 215                d = opendir(directory);
 216                if (!d)
 217                        return NULL;
 218
 219                while (de = readdir(d)) {
 220                        if (strcmp(de->d_name, "clone") == 0)
 221                                continue;
 222                        if (strcmp(de->d_name, "stats") == 0)
 223                                continue;
 224                        snprintf(buf, sizeof(buf), "%s/%s/status", directory,
 225                                 de->d_name);
 226                        l = _readipifc(buf, l, atoi(de->d_name));
 227                }
 228                closedir(d);
 229        }
 230
 231        return ifc;
 232}
 233
 234/* Gets the local interface that isn't the friggin' loopback address.  When
 235 * you're done, free_ipifc(ifc).  Returns 0 on failure. */
 236struct iplifc *get_first_noloop_iplifc(char *net, struct ipifc **ifc)
 237{
 238        struct ipifc *nifc;
 239        struct iplifc *lifc;
 240        uint8_t mynet[IPaddrlen];
 241
 242        *ifc = readipifc(net, NULL, -1);
 243        for (nifc = *ifc; nifc; nifc = nifc->next) {
 244                for (lifc = nifc->lifc; lifc; lifc = lifc->next) {
 245                        maskip(lifc->ip, loopbackmask, mynet);
 246                        if (ipcmp(mynet, loopbacknet) == 0)
 247                                continue;
 248                        if (ipcmp(lifc->ip, IPnoaddr) != 0)
 249                                return lifc;
 250                }
 251        }
 252        free_ipifc(*ifc);
 253        return 0;
 254}
 255