akaros/kern/drivers/dev/ether.c
<<
>>
Prefs
   1/* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
   2 * Portions Copyright © 1997-1999 Vita Nuova Limited
   3 * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
   4 *                                (www.vitanuova.com)
   5 * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
   6 *
   7 * Modified for the Akaros operating system:
   8 * Copyright (c) 2013-2014 The Regents of the University of California
   9 * Copyright (c) 2013-2015 Google Inc.
  10 *
  11 * Permission is hereby granted, free of charge, to any person obtaining a copy
  12 * of this software and associated documentation files (the "Software"), to deal
  13 * in the Software without restriction, including without limitation the rights
  14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15 * copies of the Software, and to permit persons to whom the Software is
  16 * furnished to do so, subject to the following conditions:
  17 *
  18 * The above copyright notice and this permission notice shall be included in
  19 * all copies or substantial portions of the Software.
  20 *
  21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  27 * SOFTWARE. */
  28
  29#include <slab.h>
  30#include <kmalloc.h>
  31#include <kref.h>
  32#include <string.h>
  33#include <stdio.h>
  34#include <assert.h>
  35#include <error.h>
  36#include <cpio.h>
  37#include <pmap.h>
  38#include <smp.h>
  39#include <net/ip.h>
  40
  41struct dev etherdevtab;
  42
  43static char *devname(void)
  44{
  45        return etherdevtab.name;
  46}
  47
  48enum {
  49        Type8021Q = 0x8100,     /* value of type field for 802.1[pQ] tags */
  50};
  51
  52static struct ether *etherxx[MaxEther]; /* real controllers */
  53static struct ether *vlanalloc(struct ether *, int);
  54static void vlanoq(struct ether *, struct block *);
  55
  56struct chan *etherattach(char *spec)
  57{
  58        ERRSTACK(1);
  59        uint32_t ctlrno;
  60        char *p;
  61        struct chan *chan;
  62        struct ether *ether, *vlan;
  63        int vlanid;
  64
  65        ctlrno = 0;
  66        vlanid = 0;
  67        if (spec && *spec) {
  68                ctlrno = strtoul(spec, &p, 0);
  69                /* somebody interpret this for me. */
  70                if (((ctlrno == 0) && (p == spec)) ||
  71                        (ctlrno >= MaxEther) || ((*p) && (*p != '.')))
  72                        error(EINVAL, ERROR_FIXME);
  73                if (*p == '.') {        /* vlan */
  74                        vlanid = strtoul(p + 1, &p, 0);
  75                        if (vlanid <= 0 || vlanid > 0xFFF || *p)
  76                                error(EINVAL, ERROR_FIXME);
  77                }
  78        }
  79        if ((ether = etherxx[ctlrno]) == 0)
  80                error(ENODEV, ERROR_FIXME);
  81        rlock(&ether->rwlock);
  82        if (waserror()) {
  83                runlock(&ether->rwlock);
  84                nexterror();
  85        }
  86        if (vlanid) {
  87                if (ether->max_mtu < ETHERMAXTU + ETHERHDRSIZE + 4)
  88                        error(EFAIL, "interface cannot support 802.1 tags");
  89                vlan = vlanalloc(ether, vlanid);
  90                chan = devattach(devname(), spec);
  91                chan->dev = ctlrno + (vlanid << 8);
  92                chan->aux = vlan;
  93                poperror();
  94                runlock(&ether->rwlock);
  95                return chan;
  96        }
  97        chan = devattach(devname(), spec);
  98        chan->dev = ctlrno;
  99        chan->aux = ether;
 100        if (ether->attach)
 101                ether->attach(ether);
 102        poperror();
 103        runlock(&ether->rwlock);
 104        return chan;
 105}
 106
 107static void ethershutdown(void)
 108{
 109        struct ether *ether;
 110        int i;
 111
 112        for (i = 0; i < MaxEther; i++) {
 113                ether = etherxx[i];
 114                if (ether != NULL && ether->detach != NULL)
 115                        ether->detach(ether);
 116        }
 117}
 118
 119static struct walkqid *etherwalk(struct chan *chan, struct chan *nchan,
 120                                 char **name, unsigned int nname)
 121{
 122        ERRSTACK(1);
 123        struct walkqid *wq;
 124        struct ether *ether;
 125
 126        ether = chan->aux;
 127        rlock(&ether->rwlock);
 128        if (waserror()) {
 129                runlock(&ether->rwlock);
 130                nexterror();
 131        }
 132        wq = netifwalk(ether, chan, nchan, name, nname);
 133        if (wq && wq->clone != NULL && wq->clone != chan)
 134                wq->clone->aux = ether;
 135        poperror();
 136        runlock(&ether->rwlock);
 137        return wq;
 138}
 139
 140static size_t etherstat(struct chan *chan, uint8_t *dp, size_t n)
 141{
 142        ERRSTACK(1);
 143        size_t s;
 144        struct ether *ether;
 145
 146        ether = chan->aux;
 147        rlock(&ether->rwlock);
 148        if (waserror()) {
 149                runlock(&ether->rwlock);
 150                nexterror();
 151        }
 152        s = netifstat(ether, chan, dp, n);
 153        poperror();
 154        runlock(&ether->rwlock);
 155        return s;
 156}
 157
 158static struct chan *etheropen(struct chan *chan, int omode)
 159{
 160        ERRSTACK(1);
 161        struct chan *c;
 162        struct ether *ether;
 163
 164        ether = chan->aux;
 165        rlock(&ether->rwlock);
 166        if (waserror()) {
 167                runlock(&ether->rwlock);
 168                nexterror();
 169        }
 170        c = netifopen(ether, chan, omode);
 171        poperror();
 172        runlock(&ether->rwlock);
 173        return c;
 174}
 175
 176static void etherclose(struct chan *chan)
 177{
 178        ERRSTACK(1);
 179        struct ether *ether;
 180
 181        ether = chan->aux;
 182        rlock(&ether->rwlock);
 183        if (waserror()) {
 184                runlock(&ether->rwlock);
 185                nexterror();
 186        }
 187        netifclose(ether, chan);
 188        poperror();
 189        runlock(&ether->rwlock);
 190}
 191
 192static size_t etherread(struct chan *chan, void *buf, size_t n, off64_t off)
 193{
 194        ERRSTACK(1);
 195        struct ether *ether;
 196        uint32_t offset = off;
 197        long r;
 198
 199        ether = chan->aux;
 200        rlock(&ether->rwlock);
 201        if (waserror()) {
 202                runlock(&ether->rwlock);
 203                nexterror();
 204        }
 205        if ((chan->qid.type & QTDIR) == 0 && ether->ifstat) {
 206                /*
 207                 * With some controllers it is necessary to reach
 208                 * into the chip to extract statistics.
 209                 */
 210                if (NETTYPE(chan->qid.path) == Nifstatqid) {
 211                        r = ether->ifstat(ether, buf, n, offset);
 212                        goto out;
 213                }
 214                if (NETTYPE(chan->qid.path) == Nstatqid)
 215                        ether->ifstat(ether, buf, 0, offset);
 216        }
 217        r = netifread(ether, chan, buf, n, offset);
 218out:
 219        poperror();
 220        runlock(&ether->rwlock);
 221        return r;
 222}
 223
 224static struct block *etherbread(struct chan *chan, size_t n, off64_t offset)
 225{
 226        ERRSTACK(1);
 227        struct block *b;
 228        struct ether *ether;
 229
 230        ether = chan->aux;
 231        rlock(&ether->rwlock);
 232        if (waserror()) {
 233                runlock(&ether->rwlock);
 234                nexterror();
 235        }
 236        b = netifbread(ether, chan, n, offset);
 237        poperror();
 238        runlock(&ether->rwlock);
 239        return b;
 240}
 241
 242static size_t etherwstat(struct chan *chan, uint8_t *dp, size_t n)
 243{
 244        ERRSTACK(1);
 245        struct ether *ether;
 246        int r;
 247
 248        ether = chan->aux;
 249        rlock(&ether->rwlock);
 250        if (waserror()) {
 251                runlock(&ether->rwlock);
 252                nexterror();
 253        }
 254        r = netifwstat(ether, chan, dp, n);
 255        poperror();
 256        runlock(&ether->rwlock);
 257        return r;
 258}
 259
 260static void etherrtrace(struct netfile *f, struct etherpkt *pkt, int len)
 261{
 262        uint64_t i, n;
 263        struct block *bp;
 264
 265        if (qwindow(f->in) <= 0)
 266                return;
 267        if (len > 58)
 268                n = 58;
 269        else
 270                n = len;
 271        bp = block_alloc(68, MEM_ATOMIC);
 272        if (bp == NULL)
 273                return;
 274        memmove(bp->wp, pkt->d, n);
 275        /* we're storing 8 bytes here (64 bit); old 9ns was 32 bit for msec */
 276        i = milliseconds();
 277        bp->wp[58] = len >> 8;
 278        bp->wp[59] = len;
 279        bp->wp[60] = i >> 56;
 280        bp->wp[61] = i >> 48;
 281        bp->wp[62] = i >> 40;
 282        bp->wp[63] = i >> 32;
 283        bp->wp[64] = i >> 24;
 284        bp->wp[65] = i >> 16;
 285        bp->wp[66] = i >> 8;
 286        bp->wp[67] = i;
 287        bp->wp += 68;
 288        qpass(f->in, bp);
 289}
 290
 291#ifdef CONFIG_RISCV
 292#warning "Potentially unaligned ethernet addrs!"
 293#endif
 294
 295static inline int eaddrcmp(uint8_t *x, uint8_t *y)
 296{
 297        uint16_t *a = (uint16_t *)x;
 298        uint16_t *b = (uint16_t *)y;
 299
 300        return (a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]);
 301}
 302
 303struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
 304{
 305        struct etherpkt *pkt;
 306        uint16_t type;
 307        int multi, tome, fromme, vlanid, i;
 308        struct netfile **ep, *f, **fp, *fx;
 309        struct block *xbp;
 310        struct ether *vlan;
 311
 312        ether->inpackets++;
 313
 314        pkt = (struct etherpkt *)bp->rp;
 315        /* TODO: we might need to assert more for higher layers, or otherwise
 316         * deal with extra data. */
 317        assert(BHLEN(bp) >= offsetof(struct etherpkt, data));
 318        type = (pkt->type[0] << 8) | pkt->type[1];
 319        if (type == Type8021Q && ether->nvlan) {
 320                vlanid = nhgets(bp->rp + 2 * Eaddrlen + 2) & 0xFFF;
 321                if (vlanid) {
 322                        for (i = 0; i < ARRAY_SIZE(ether->vlans); i++) {
 323                                vlan = ether->vlans[i];
 324                                if (vlan != NULL && vlan->vlanid == vlanid) {
 325                                        /* might have a problem with extra data
 326                                         * here */
 327                                        assert(BHLEN(bp) >= 4 + 2 * Eaddrlen);
 328                                        memmove(bp->rp + 4, bp->rp,
 329                                                2 * Eaddrlen);
 330                                        bp->rp += 4;
 331                                        return etheriq(vlan, bp, fromwire);
 332                                }
 333                        }
 334                        /* allow normal type handling to accept or discard it */
 335                }
 336        }
 337
 338        fx = 0;
 339        ep = &ether->f[Ntypes];
 340
 341        multi = pkt->d[0] & 1;
 342        /* check for valid multcast addresses */
 343        if (multi && eaddrcmp(pkt->d, ether->bcast) != 0
 344                && ether->prom == 0) {
 345                if (!activemulti(ether, pkt->d, sizeof(pkt->d))) {
 346                        if (fromwire) {
 347                                freeb(bp);
 348                                bp = 0;
 349                        }
 350                        return bp;
 351                }
 352        }
 353
 354        /* is it for me? */
 355        tome = eaddrcmp(pkt->d, ether->ea) == 0;
 356        fromme = eaddrcmp(pkt->s, ether->ea) == 0;
 357
 358        /*
 359         * Multiplex the packet to all the connections which want it.
 360         * If the packet is not to be used subsequently (fromwire != 0),
 361         * attempt to simply pass it into one of the connections, thereby
 362         * saving a copy of the data (usual case hopefully).
 363         */
 364        for (fp = ether->f; fp < ep; fp++) {
 365                if ((f = *fp) && (f->type == type || f->type < 0))
 366                        if (tome || multi || f->prom) {
 367                                /* Don't want to hear bridged packets */
 368                                if (f->bridge && !fromwire && !fromme)
 369                                        continue;
 370                                if (f->headersonly) {
 371                                        etherrtrace(f, pkt, BHLEN(bp));
 372                                        continue;
 373                                }
 374                                if (fromwire && fx == 0) {
 375                                        fx = f;
 376                                        continue;
 377                                }
 378                                xbp = copyblock(bp, MEM_ATOMIC);
 379                                if (xbp == 0) {
 380                                        ether->soverflows++;
 381                                        continue;
 382                                }
 383                                if (qpass(f->in, xbp) < 0)
 384                                        ether->soverflows++;
 385                        }
 386        }
 387
 388        if (fx) {
 389                if (qpass(fx->in, bp) < 0)
 390                        ether->soverflows++;
 391                return 0;
 392        }
 393        if (fromwire) {
 394                freeb(bp);
 395                return 0;
 396        }
 397
 398        return bp;
 399}
 400
 401static int etheroq(struct ether *ether, struct block *bp)
 402{
 403        int len, loopback;
 404        struct etherpkt *pkt;
 405        int8_t irq_state = 0;
 406
 407        ether->outpackets++;
 408
 409        if (!(ether->feat & NETF_SG))
 410                bp = linearizeblock(bp);
 411        ptclcsum_finalize(bp, ether->feat);
 412        /*
 413         * Check if the packet has to be placed back onto the input queue,
 414         * i.e. if it's a loopback or broadcast packet or the interface is
 415         * in promiscuous mode.
 416         * If it's a loopback packet indicate to etheriq that the data isn't
 417         * needed and return, etheriq will pass-on or free the block.
 418         * To enable bridging to work, only packets that were originated
 419         * by this interface are fed back.
 420         */
 421        pkt = (struct etherpkt *)bp->rp;
 422        len = BLEN(bp);
 423        loopback = eaddrcmp(pkt->d, ether->ea) == 0;
 424        if (loopback || eaddrcmp(pkt->d, ether->bcast) == 0 || ether->prom) {
 425                disable_irqsave(&irq_state);
 426                etheriq(ether, bp, 0);
 427                enable_irqsave(&irq_state);
 428                if (loopback) {
 429                        freeb(bp);
 430                        return len;
 431                }
 432        }
 433
 434        if (ether->vlanid) {
 435                /* add tag */
 436                bp = padblock(bp, 2 + 2);
 437                memmove(bp->rp, bp->rp + 4, 2 * Eaddrlen);
 438                hnputs(bp->rp + 2 * Eaddrlen, Type8021Q);
 439                /* prio:3 0:1 vid:12 */
 440                hnputs(bp->rp + 2 * Eaddrlen + 2, ether->vlanid & 0xFFF);
 441                ether = ether->ctlr;
 442        }
 443
 444        if ((ether->feat & NETF_PADMIN) == 0 && BLEN(bp) < ether->min_mtu)
 445                bp = adjustblock(bp, ether->min_mtu);
 446
 447        qbwrite(ether->oq, bp);
 448        if (ether->transmit != NULL)
 449                ether->transmit(ether);
 450
 451        return len;
 452}
 453
 454static size_t etherwrite(struct chan *chan, void *buf, size_t n, off64_t unused)
 455{
 456        ERRSTACK(2);
 457        struct ether *ether;
 458        struct block *bp;
 459        int onoff;
 460        struct cmdbuf *cb;
 461        long l;
 462
 463        ether = chan->aux;
 464        rlock(&ether->rwlock);
 465        if (waserror()) {
 466                runlock(&ether->rwlock);
 467                nexterror();
 468        }
 469        if (NETTYPE(chan->qid.path) != Ndataqid) {
 470                l = netifwrite(ether, chan, buf, n);
 471                if (l >= 0)
 472                        goto out;
 473                cb = parsecmd(buf, n);
 474                if (cb->nf < 1) {
 475                        kfree(cb);
 476                        error(EFAIL, "short control request");
 477                }
 478                if (strcmp(cb->f[0], "nonblocking") == 0) {
 479                        if (cb->nf <= 1)
 480                                onoff = 1;
 481                        else
 482                                onoff = atoi(cb->f[1]);
 483                        if (ether->oq != NULL)
 484                                qdropoverflow(ether->oq, onoff);
 485                        kfree(cb);
 486                        goto out;
 487                }
 488                kfree(cb);
 489                if (ether->ctl != NULL) {
 490                        l = ether->ctl(ether, buf, n);
 491                        goto out;
 492                }
 493                error(EINVAL, ERROR_FIXME);
 494        }
 495
 496        if (n > ether->mtu + ETHERHDRSIZE)
 497                error(E2BIG, ERROR_FIXME);
 498        bp = block_alloc(n, MEM_WAIT);
 499        if (waserror()) {
 500                freeb(bp);
 501                nexterror();
 502        }
 503        memmove(bp->rp, buf, n);
 504        memmove(bp->rp + Eaddrlen, ether->ea, Eaddrlen);
 505        bp->wp += n;
 506        poperror();
 507
 508        l = etheroq(ether, bp);
 509out:
 510        poperror();
 511        runlock(&ether->rwlock);
 512        return l;
 513}
 514
 515static size_t etherbwrite(struct chan *chan, struct block *bp, off64_t unused)
 516{
 517        ERRSTACK(1);
 518        struct ether *ether;
 519        long n;
 520
 521        n = BLEN(bp);
 522        if (NETTYPE(chan->qid.path) != Ndataqid) {
 523                if (waserror()) {
 524                        freeb(bp);
 525                        nexterror();
 526                }
 527                n = etherwrite(chan, bp->rp, n, 0);
 528                poperror();
 529                freeb(bp);
 530                return n;
 531        }
 532        ether = chan->aux;
 533        rlock(&ether->rwlock);
 534        if (waserror()) {
 535                runlock(&ether->rwlock);
 536                nexterror();
 537        }
 538        if (n > ether->mtu + ETHERHDRSIZE && (bp->flag & Btso) == 0) {
 539                freeb(bp);
 540                error(E2BIG, ERROR_FIXME);
 541        }
 542        n = etheroq(ether, bp);
 543        poperror();
 544        runlock(&ether->rwlock);
 545        return n;
 546}
 547
 548static void nop(struct ether *unused)
 549{
 550}
 551
 552static long vlanctl(struct ether *ether, void *buf, size_t n)
 553{
 554        uint8_t ea[Eaddrlen];
 555        struct ether *master;
 556        struct cmdbuf *cb;
 557        int i;
 558
 559        cb = parsecmd(buf, n);
 560        if (cb->nf >= 2 && strcmp(cb->f[0], "ea") == 0 &&
 561            parseether(ea, cb->f[1]) == 0) {
 562                kfree(cb);
 563                memmove(ether->ea, ea, Eaddrlen);
 564                memmove(ether->addr, ether->ea, Eaddrlen);
 565                return 0;
 566        }
 567        if (cb->nf == 1 && strcmp(cb->f[0], "disable") == 0) {
 568                master = ether->ctlr;
 569                qlock(&master->vlq);
 570                for (i = 0; i < ARRAY_SIZE(master->vlans); i++)
 571                        if (master->vlans[i] == ether) {
 572                                ether->vlanid = 0;
 573                                master->nvlan--;
 574                                break;
 575                        }
 576                qunlock(&master->vlq);
 577                kfree(cb);
 578                return 0;
 579        }
 580        kfree(cb);
 581        error(EINVAL, ERROR_FIXME);
 582        return -1;      /* not reached */
 583}
 584
 585static struct ether *vlanalloc(struct ether *ether, int id)
 586{
 587        ERRSTACK(1);
 588        struct ether *vlan;
 589        int i, fid;
 590        char name[KNAMELEN];
 591
 592        qlock(&ether->vlq);
 593        if (waserror()) {
 594                qunlock(&ether->vlq);
 595                nexterror();
 596        }
 597        fid = -1;
 598        for (i = 0; i < ARRAY_SIZE(ether->vlans); i++) {
 599                vlan = ether->vlans[i];
 600                if (vlan != NULL && vlan->vlanid == id) {
 601                        poperror();
 602                        qunlock(&ether->vlq);
 603                        return vlan;
 604                }
 605                if (fid < 0 && (vlan == NULL || vlan->vlanid == 0))
 606                        fid = i;
 607        }
 608        if (fid < 0)
 609                error(ENOENT, ERROR_FIXME);
 610        snprintf(name, sizeof(name), "ether%d.%d", ether->ctlrno, id);
 611        vlan = ether->vlans[fid];
 612        if (vlan == NULL) {
 613                vlan = kzmalloc(sizeof(struct ether), 1);
 614                if (vlan == NULL)
 615                        error(ENOMEM, ERROR_FIXME);
 616                rwinit(&vlan->rwlock);
 617                qlock_init(&vlan->vlq);
 618                netifinit(vlan, name, Ntypes, ether->limit);
 619                /* id is still zero, can't be matched */
 620                ether->vlans[fid] = vlan;
 621                ether->nvlan++;
 622        } else
 623                memmove(vlan->name, name, KNAMELEN - 1);
 624        vlan->attach = nop;
 625        vlan->transmit = NULL;
 626        vlan->ctl = vlanctl;
 627        vlan->irq = -1;
 628        vlan->promiscuous = ether->promiscuous;
 629        vlan->multicast = ether->multicast;
 630        vlan->arg = vlan;
 631        vlan->mbps = ether->mbps;
 632        vlan->fullduplex = ether->fullduplex;
 633        vlan->encry = ether->encry;
 634        vlan->mtu = ether->mtu;
 635        vlan->min_mtu = ether->min_mtu;
 636        vlan->max_mtu = ether->max_mtu;
 637        vlan->ctlrno = ether->ctlrno;
 638        vlan->vlanid = id;
 639        vlan->alen = Eaddrlen;
 640        memmove(vlan->addr, ether->addr, sizeof(vlan->addr));
 641        memmove(vlan->bcast, ether->bcast, sizeof(ether->bcast));
 642        vlan->oq = NULL;
 643        vlan->ctlr = ether;
 644        vlan->vlanid = id;
 645        poperror();
 646        qunlock(&ether->vlq);
 647        return vlan;
 648}
 649
 650static struct {
 651        char *type;
 652        int (*reset) (struct ether *);
 653} cards[MaxEther + 1];
 654
 655void addethercard(char *t, int (*r) (struct ether *))
 656{
 657        static int ncard;
 658
 659        if (ncard == MaxEther)
 660                panic("too many ether cards");
 661        cards[ncard].type = t;
 662        cards[ncard].reset = r;
 663        ncard++;
 664}
 665
 666int parseether(uint8_t * to, char *from)
 667{
 668        char nip[4];
 669        char *p;
 670        int i;
 671
 672        p = from;
 673        for (i = 0; i < Eaddrlen; i++) {
 674                if (*p == 0)
 675                        return -1;
 676                nip[0] = *p++;
 677                if (*p == 0)
 678                        return -1;
 679                nip[1] = *p++;
 680                nip[2] = 0;
 681                to[i] = strtoul(nip, 0, 16);
 682                if (*p == ':')
 683                        p++;
 684        }
 685        return 0;
 686}
 687
 688static void etherreset(void)
 689{
 690        struct ether *ether;
 691        int i, n, ctlrno, qsize;
 692        char name[KNAMELEN], buf[128];
 693
 694        for (ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++) {
 695                if (ether == 0)
 696                        ether = kzmalloc(sizeof(struct ether), 0);
 697                memset(ether, 0, sizeof(struct ether));
 698                rwinit(&ether->rwlock);
 699                qlock_init(&ether->vlq);
 700                rendez_init(&ether->link_rz);
 701                ether->ctlrno = ctlrno;
 702                ether->mbps = 10;
 703                ether->mtu = ETHERMAXTU;
 704                ether->min_mtu = ETHERMINTU;
 705                ether->max_mtu = ETHERMAXTU;
 706                /* looked like irq type, we don't have these yet */
 707                //ether->netif.itype = -1;
 708
 709                /* TODO: looks like they expected some init to be done here.  at
 710                 * the very least, ether->type is 0 right now, and needs to be
 711                 * set.  looking around online, it seems to find out ether
 712                 * config settings, so that we can set some flags in the opt
 713                 * parseing below. */
 714                //if(archether(ctlrno, ether) <= 0)
 715                //  continue;
 716
 717                for (n = 0; cards[n].type; n++) {
 718#if 0
 719                        if (cistrcmp(cards[n].type, ether->type))
 720                                continue;
 721                        for (i = 0; i < ether->nopt; i++) {
 722                                if (cistrncmp(ether->opt[i], "ea=", 3) == 0) {
 723                                        if (parseether(ether->ea,
 724                                                       &ether->opt[i][3]) == -1)
 725                                                memset(ether->ea, 0, Eaddrlen);
 726                                } else if (cistrcmp(ether->opt[i], "fullduplex")
 727                                           == 0 || cistrcmp(ether->opt[i],
 728                                                            "10BASE-TFD") == 0)
 729                                        ether->fullduplex = 1;
 730                                else if (cistrcmp(ether->opt[i], "100BASE-TXFD")
 731                                         == 0)
 732                                        ether->mbps = 100;
 733                        }
 734#endif
 735                        if (cards[n].reset(ether))
 736                                continue;
 737                        /* might be fucked a bit - reset() doesn't know the
 738                         * type.  might not even matter, except for debugging */
 739                        ether->type = cards[n].type;
 740                        snprintf(name, sizeof(name), "ether%d", ctlrno);
 741
 742                        i = snprintf(buf, sizeof(buf),
 743                                     "#l%d: %s: %dMbps port 0x%x irq %u",
 744                                     ctlrno, ether->type, ether->mbps,
 745                                     ether->port, ether->irq);
 746                        /* Looks like this is for printing MMIO addrs */
 747#if 0
 748                        if (ether->mem)
 749                                i += snprintf(buf + i, sizeof(buf) - i,
 750                                              " addr 0x%lx", PADDR(ether->mem));
 751                        if (ether->size)
 752                                i += snprintf(buf + i, sizeof(buf) - i,
 753                                              " size 0x%lx", ether->size);
 754#endif
 755                        i += snprintf(buf + i, sizeof(buf) - i,
 756                                      ": %02.2x:%02.2x:%02.2x:%02.2x:%02.2x:%02.2x",
 757                                      ether->ea[0], ether->ea[1], ether->ea[2],
 758                                      ether->ea[3], ether->ea[4], ether->ea[5]);
 759                        snprintf(buf + i, sizeof(buf) - i, "\n");
 760                        printk(buf);
 761
 762                        switch (ether->mbps) {
 763                        case 1 ... 99:
 764                                qsize = 64 * 1024;
 765                                break;
 766                        case 100 ... 999:
 767                                qsize = 256 * 1024;
 768                                break;
 769                        case 1000 ... 9999:
 770                                qsize = 1024 * 1024;
 771                                break;
 772                        default:
 773                                qsize = 8 * 1024 * 1024;
 774                        }
 775                        netifinit(ether, name, Ntypes, qsize);
 776                        if (ether->oq == 0)
 777                                ether->oq = qopen(qsize, Qmsg, 0, 0);
 778                        if (ether->oq == 0)
 779                                panic("etherreset %s", name);
 780                        ether->alen = Eaddrlen;
 781                        memmove(ether->addr, ether->ea, Eaddrlen);
 782                        memset(ether->bcast, 0xFF, Eaddrlen);
 783
 784                        etherxx[ctlrno] = ether;
 785                        ether = 0;
 786                        break;
 787                }
 788        }
 789        if (ether)
 790                kfree(ether);
 791}
 792
 793static void etherpower(int on)
 794{
 795        int i;
 796        struct ether *ether;
 797
 798        /* TODO: fix etherpower.  locking and ether->readers are broken. */
 799        warn("%s needs attention.  had a rough porting from inferno",
 800             __FUNCTION__);
 801        for (i = 0; i < MaxEther; i++) {
 802                if ((ether = etherxx[i]) == NULL || ether->power == NULL)
 803                        continue;
 804                if (on) {
 805                        /* brho: not sure what they are doing.  there seem to be
 806                         * certain assumptions about calling etherpower.  i
 807                         * think they are using canrlock to see if the lock is
 808                         * currently writelocked.  and if it was not lockable,
 809                         * they would assume they had the write lock and could
 810                         * unlock.  this is super fucked up. */
 811                        if (canrlock(&ether->rwlock)) {
 812                                // brho added this
 813                                runlock(&ether->rwlock);
 814                                continue;
 815                        }
 816                        if (ether->power != NULL)
 817                                ether->power(ether, on);
 818                        wunlock(&ether->rwlock);
 819                } else {
 820                        /* readers isn't in the ether struct...
 821                           if(ether->readers)
 822                           continue;
 823                         */
 824                        wlock(&ether->rwlock);
 825                        if (ether->power != NULL)
 826                                ether->power(ether, on);
 827                        /* Keep locked until power goes back on */
 828                }
 829        }
 830}
 831
 832#define ETHERPOLY 0xedb88320
 833
 834/* really slow 32 bit crc for ethers */
 835uint32_t ethercrc(uint8_t * p, int len)
 836{
 837        int i, j;
 838        uint32_t crc, b;
 839
 840        crc = 0xffffffff;
 841        for (i = 0; i < len; i++) {
 842                b = *p++;
 843                for (j = 0; j < 8; j++) {
 844                        crc = (crc >> 1) ^ (((crc ^ b) & 1) ? ETHERPOLY : 0);
 845                        b >>= 1;
 846                }
 847        }
 848        return crc;
 849}
 850
 851struct dev etherdevtab __devtab = {
 852        .name = "ether",
 853
 854        .reset = etherreset,
 855        .init = devinit,
 856        .shutdown = ethershutdown,
 857        .attach = etherattach,
 858        .walk = etherwalk,
 859        .stat = etherstat,
 860        .open = etheropen,
 861        .create = devcreate,
 862        .close = etherclose,
 863        .read = etherread,
 864        .bread = etherbread,
 865        .write = etherwrite,
 866        .bwrite = etherbwrite,
 867        .remove = devremove,
 868        .wstat = etherwstat,
 869        .power = etherpower,
 870        .chaninfo = devchaninfo,
 871};
 872