Annotation of 43BSD/sys/netinet/if_ether.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1982, 1986 Regents of the University of California.
                      3:  * All rights reserved.  The Berkeley software License Agreement
                      4:  * specifies the terms and conditions for redistribution.
                      5:  *
                      6:  *     @(#)if_ether.c  7.1.1.1 (Berkeley) 2/27/87
                      7:  */
                      8: 
                      9: /*
                     10:  * Ethernet address resolution protocol.
                     11:  */
                     12: 
                     13: #include "param.h"
                     14: #include "systm.h"
                     15: #include "mbuf.h"
                     16: #include "socket.h"
                     17: #include "time.h"
                     18: #include "kernel.h"
                     19: #include "errno.h"
                     20: #include "ioctl.h"
                     21: #include "syslog.h"
                     22: 
                     23: #include "../net/if.h"
                     24: #include "in.h"
                     25: #include "in_systm.h"
                     26: #include "ip.h"
                     27: #include "if_ether.h"
                     28: 
                     29: #define        ARPTAB_BSIZ     9               /* bucket size */
                     30: #define        ARPTAB_NB       19              /* number of buckets */
                     31: #define        ARPTAB_SIZE     (ARPTAB_BSIZ * ARPTAB_NB)
                     32: struct arptab arptab[ARPTAB_SIZE];
                     33: int    arptab_size = ARPTAB_SIZE;      /* for arp command */
                     34: 
                     35: /*
                     36:  * ARP trailer negotiation.  Trailer protocol is not IP specific,
                     37:  * but ARP request/response use IP addresses.
                     38:  */
                     39: #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
                     40: 
                     41: #define        ARPTAB_HASH(a) \
                     42:        ((u_long)(a) % ARPTAB_NB)
                     43: 
                     44: #define        ARPTAB_LOOK(at,addr) { \
                     45:        register n; \
                     46:        at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
                     47:        for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
                     48:                if (at->at_iaddr.s_addr == addr) \
                     49:                        break; \
                     50:        if (n >= ARPTAB_BSIZ) \
                     51:                at = 0; \
                     52: }
                     53: 
                     54: /* timer values */
                     55: #define        ARPT_AGE        (60*1)  /* aging timer, 1 min. */
                     56: #define        ARPT_KILLC      20      /* kill completed entry in 20 mins. */
                     57: #define        ARPT_KILLI      3       /* kill incomplete entry in 3 minutes */
                     58: 
                     59: u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
                     60: extern struct ifnet loif;
                     61: 
                     62: /*
                     63:  * Timeout routine.  Age arp_tab entries once a minute.
                     64:  */
                     65: arptimer()
                     66: {
                     67:        register struct arptab *at;
                     68:        register i;
                     69: 
                     70:        timeout(arptimer, (caddr_t)0, ARPT_AGE * hz);
                     71:        at = &arptab[0];
                     72:        for (i = 0; i < ARPTAB_SIZE; i++, at++) {
                     73:                if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
                     74:                        continue;
                     75:                if (++at->at_timer < ((at->at_flags&ATF_COM) ?
                     76:                    ARPT_KILLC : ARPT_KILLI))
                     77:                        continue;
                     78:                /* timer has expired, clear entry */
                     79:                arptfree(at);
                     80:        }
                     81: }
                     82: 
                     83: /*
                     84:  * Broadcast an ARP packet, asking who has addr on interface ac.
                     85:  */
                     86: arpwhohas(ac, addr)
                     87:        register struct arpcom *ac;
                     88:        struct in_addr *addr;
                     89: {
                     90:        register struct mbuf *m;
                     91:        register struct ether_header *eh;
                     92:        register struct ether_arp *ea;
                     93:        struct sockaddr sa;
                     94: 
                     95:        if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL)
                     96:                return;
                     97:        m->m_len = sizeof *ea;
                     98:        m->m_off = MMAXOFF - m->m_len;
                     99:        ea = mtod(m, struct ether_arp *);
                    100:        eh = (struct ether_header *)sa.sa_data;
                    101:        bzero((caddr_t)ea, sizeof (*ea));
                    102:        bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
                    103:            sizeof(eh->ether_dhost));
                    104:        eh->ether_type = ETHERTYPE_ARP;         /* if_output will swap */
                    105:        ea->arp_hrd = htons(ARPHRD_ETHER);
                    106:        ea->arp_pro = htons(ETHERTYPE_IP);
                    107:        ea->arp_hln = sizeof(ea->arp_sha);      /* hardware address length */
                    108:        ea->arp_pln = sizeof(ea->arp_spa);      /* protocol address length */
                    109:        ea->arp_op = htons(ARPOP_REQUEST);
                    110:        bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
                    111:           sizeof(ea->arp_sha));
                    112:        bcopy((caddr_t)&ac->ac_ipaddr, (caddr_t)ea->arp_spa,
                    113:           sizeof(ea->arp_spa));
                    114:        bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
                    115:        sa.sa_family = AF_UNSPEC;
                    116:        (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
                    117: }
                    118: 
                    119: int    useloopback = 1;        /* use loopback interface for local traffic */
                    120: 
                    121: /*
                    122:  * Resolve an IP address into an ethernet address.  If success, 
                    123:  * desten is filled in.  If there is no entry in arptab,
                    124:  * set one up and broadcast a request for the IP address.
                    125:  * Hold onto this mbuf and resend it once the address
                    126:  * is finally resolved.  A return value of 1 indicates
                    127:  * that desten has been filled in and the packet should be sent
                    128:  * normally; a 0 return indicates that the packet has been
                    129:  * taken over here, either now or for later transmission.
                    130:  *
                    131:  * We do some (conservative) locking here at splimp, since
                    132:  * arptab is also altered from input interrupt service (ecintr/ilintr
                    133:  * calls arpinput when ETHERTYPE_ARP packets come in).
                    134:  */
                    135: arpresolve(ac, m, destip, desten, usetrailers)
                    136:        register struct arpcom *ac;
                    137:        struct mbuf *m;
                    138:        register struct in_addr *destip;
                    139:        register u_char *desten;
                    140:        int *usetrailers;
                    141: {
                    142:        register struct arptab *at;
                    143:        register struct ifnet *ifp;
                    144:        struct sockaddr_in sin;
                    145:        int s, lna;
                    146: 
                    147:        *usetrailers = 0;
                    148:        if (in_broadcast(*destip)) {    /* broadcast address */
                    149:                bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
                    150:                    sizeof(etherbroadcastaddr));
                    151:                return (1);
                    152:        }
                    153:        lna = in_lnaof(*destip);
                    154:        ifp = &ac->ac_if;
                    155:        /* if for us, use software loopback driver if up */
                    156:        if (destip->s_addr == ac->ac_ipaddr.s_addr) {
                    157:                if (useloopback) {
                    158:                        sin.sin_family = AF_INET;
                    159:                        sin.sin_addr = *destip;
                    160:                        (void) looutput(&loif, m, (struct sockaddr *)&sin);
                    161:                        /*
                    162:                         * The packet has already been sent and freed.
                    163:                         */
                    164:                        return (0);
                    165:                } else {
                    166:                        bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten,
                    167:                            sizeof(ac->ac_enaddr));
                    168:                        return (1);
                    169:                }
                    170:        }
                    171:        s = splimp();
                    172:        ARPTAB_LOOK(at, destip->s_addr);
                    173:        if (at == 0) {                  /* not found */
                    174:                if (ifp->if_flags & IFF_NOARP) {
                    175:                        bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
                    176:                        desten[3] = (lna >> 16) & 0x7f;
                    177:                        desten[4] = (lna >> 8) & 0xff;
                    178:                        desten[5] = lna & 0xff;
                    179:                        splx(s);
                    180:                        return (1);
                    181:                } else {
                    182:                        at = arptnew(destip);
                    183:                        at->at_hold = m;
                    184:                        arpwhohas(ac, destip);
                    185:                        splx(s);
                    186:                        return (0);
                    187:                }
                    188:        }
                    189:        at->at_timer = 0;               /* restart the timer */
                    190:        if (at->at_flags & ATF_COM) {   /* entry IS complete */
                    191:                bcopy((caddr_t)at->at_enaddr, (caddr_t)desten,
                    192:                    sizeof(at->at_enaddr));
                    193:                if (at->at_flags & ATF_USETRAILERS)
                    194:                        *usetrailers = 1;
                    195:                splx(s);
                    196:                return (1);
                    197:        }
                    198:        /*
                    199:         * There is an arptab entry, but no ethernet address
                    200:         * response yet.  Replace the held mbuf with this
                    201:         * latest one.
                    202:         */
                    203:        if (at->at_hold)
                    204:                m_freem(at->at_hold);
                    205:        at->at_hold = m;
                    206:        arpwhohas(ac, destip);          /* ask again */
                    207:        splx(s);
                    208:        return (0);
                    209: }
                    210: 
                    211: /*
                    212:  * Called from 10 Mb/s Ethernet interrupt handlers
                    213:  * when ether packet type ETHERTYPE_ARP
                    214:  * is received.  Common length and type checks are done here,
                    215:  * then the protocol-specific routine is called.
                    216:  */
                    217: arpinput(ac, m)
                    218:        struct arpcom *ac;
                    219:        struct mbuf *m;
                    220: {
                    221:        register struct arphdr *ar;
                    222: 
                    223:        if (ac->ac_if.if_flags & IFF_NOARP)
                    224:                goto out;
                    225:        IF_ADJ(m);
                    226:        if (m->m_len < sizeof(struct arphdr))
                    227:                goto out;
                    228:        ar = mtod(m, struct arphdr *);
                    229:        if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
                    230:                goto out;
                    231:        if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
                    232:                goto out;
                    233: 
                    234:        switch (ntohs(ar->ar_pro)) {
                    235: 
                    236:        case ETHERTYPE_IP:
                    237:        case ETHERTYPE_IPTRAILERS:
                    238:                in_arpinput(ac, m);
                    239:                return;
                    240: 
                    241:        default:
                    242:                break;
                    243:        }
                    244: out:
                    245:        m_freem(m);
                    246: }
                    247: 
                    248: /*
                    249:  * ARP for Internet protocols on 10 Mb/s Ethernet.
                    250:  * Algorithm is that given in RFC 826.
                    251:  * In addition, a sanity check is performed on the sender
                    252:  * protocol address, to catch impersonators.
                    253:  * We also handle negotiations for use of trailer protocol:
                    254:  * ARP replies for protocol type ETHERTYPE_TRAIL are sent
                    255:  * along with IP replies if we want trailers sent to us,
                    256:  * and also send them in response to IP replies.
                    257:  * This allows either end to announce the desire to receive
                    258:  * trailer packets.
                    259:  * We reply to requests for ETHERTYPE_TRAIL protocol as well,
                    260:  * but don't normally send requests.
                    261:  */
                    262: in_arpinput(ac, m)
                    263:        register struct arpcom *ac;
                    264:        struct mbuf *m;
                    265: {
                    266:        register struct ether_arp *ea;
                    267:        struct ether_header *eh;
                    268:        register struct arptab *at;  /* same as "merge" flag */
                    269:        struct mbuf *mcopy = 0;
                    270:        struct sockaddr_in sin;
                    271:        struct sockaddr sa;
                    272:        struct in_addr isaddr, itaddr, myaddr;
                    273:        int proto, op, s;
                    274: 
                    275:        myaddr = ac->ac_ipaddr;
                    276:        ea = mtod(m, struct ether_arp *);
                    277:        proto = ntohs(ea->arp_pro);
                    278:        op = ntohs(ea->arp_op);
                    279:        isaddr.s_addr = ((struct in_addr *)ea->arp_spa)->s_addr;
                    280:        itaddr.s_addr = ((struct in_addr *)ea->arp_tpa)->s_addr;
                    281:        if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
                    282:          sizeof (ea->arp_sha)))
                    283:                goto out;       /* it's from me, ignore it. */
                    284:        if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
                    285:            sizeof (ea->arp_sha))) {
                    286:                log(LOG_ERR,
                    287:                    "arp: ether address is broadcast for IP address %x!\n",
                    288:                    ntohl(isaddr.s_addr));
                    289:                goto out;
                    290:        }
                    291:        if (isaddr.s_addr == myaddr.s_addr) {
                    292:                log(LOG_ERR, "%s: %s\n",
                    293:                        "duplicate IP address!! sent from ethernet address",
                    294:                        ether_sprintf(ea->arp_sha));
                    295:                itaddr = myaddr;
                    296:                if (op == ARPOP_REQUEST)
                    297:                        goto reply;
                    298:                goto out;
                    299:        }
                    300:        s = splimp();
                    301:        ARPTAB_LOOK(at, isaddr.s_addr);
                    302:        if (at) {
                    303:                bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
                    304:                    sizeof(ea->arp_sha));
                    305:                at->at_flags |= ATF_COM;
                    306:                if (at->at_hold) {
                    307:                        sin.sin_family = AF_INET;
                    308:                        sin.sin_addr = isaddr;
                    309:                        (*ac->ac_if.if_output)(&ac->ac_if, 
                    310:                            at->at_hold, (struct sockaddr *)&sin);
                    311:                        at->at_hold = 0;
                    312:                }
                    313:        }
                    314:        if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
                    315:                /* ensure we have a table entry */
                    316:                at = arptnew(&isaddr);
                    317:                bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
                    318:                    sizeof(ea->arp_sha));
                    319:                at->at_flags |= ATF_COM;
                    320:        }
                    321:        splx(s);
                    322: reply:
                    323:        switch (proto) {
                    324: 
                    325:        case ETHERTYPE_IPTRAILERS:
                    326:                /* partner says trailers are OK */
                    327:                if (at)
                    328:                        at->at_flags |= ATF_USETRAILERS;
                    329:                /*
                    330:                 * Reply to request iff we want trailers.
                    331:                 */
                    332:                if (op != ARPOP_REQUEST || ac->ac_if.if_flags & IFF_NOTRAILERS)
                    333:                        goto out;
                    334:                break;
                    335: 
                    336:        case ETHERTYPE_IP:
                    337:                /*
                    338:                 * Reply if this is an IP request, or if we want to send
                    339:                 * a trailer response.
                    340:                 */
                    341:                if (op != ARPOP_REQUEST && ac->ac_if.if_flags & IFF_NOTRAILERS)
                    342:                        goto out;
                    343:        }
                    344:        if (itaddr.s_addr == myaddr.s_addr) {
                    345:                /* I am the target */
                    346:                bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
                    347:                    sizeof(ea->arp_sha));
                    348:                bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
                    349:                    sizeof(ea->arp_sha));
                    350:        } else {
                    351:                ARPTAB_LOOK(at, itaddr.s_addr);
                    352:                if (at == NULL || (at->at_flags & ATF_PUBL) == 0)
                    353:                        goto out;
                    354:                bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
                    355:                    sizeof(ea->arp_sha));
                    356:                bcopy((caddr_t)at->at_enaddr, (caddr_t)ea->arp_sha,
                    357:                    sizeof(ea->arp_sha));
                    358:        }
                    359: 
                    360:        bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
                    361:            sizeof(ea->arp_spa));
                    362:        bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa,
                    363:            sizeof(ea->arp_spa));
                    364:        ea->arp_op = htons(ARPOP_REPLY); 
                    365:        /*
                    366:         * If incoming packet was an IP reply,
                    367:         * we are sending a reply for type IPTRAILERS.
                    368:         * If we are sending a reply for type IP
                    369:         * and we want to receive trailers,
                    370:         * send a trailer reply as well.
                    371:         */
                    372:        if (op == ARPOP_REPLY)
                    373:                ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
                    374:        else if (proto == ETHERTYPE_IP &&
                    375:            (ac->ac_if.if_flags & IFF_NOTRAILERS) == 0)
                    376:                mcopy = m_copy(m, 0, (int)M_COPYALL);
                    377:        eh = (struct ether_header *)sa.sa_data;
                    378:        bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
                    379:            sizeof(eh->ether_dhost));
                    380:        eh->ether_type = ETHERTYPE_ARP;
                    381:        sa.sa_family = AF_UNSPEC;
                    382:        (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
                    383:        if (mcopy) {
                    384:                ea = mtod(mcopy, struct ether_arp *);
                    385:                ea->arp_pro = htons(ETHERTYPE_IPTRAILERS);
                    386:                (*ac->ac_if.if_output)(&ac->ac_if, mcopy, &sa);
                    387:        }
                    388:        return;
                    389: out:
                    390:        m_freem(m);
                    391:        return;
                    392: }
                    393: 
                    394: /*
                    395:  * Free an arptab entry.
                    396:  */
                    397: arptfree(at)
                    398:        register struct arptab *at;
                    399: {
                    400:        int s = splimp();
                    401: 
                    402:        if (at->at_hold)
                    403:                m_freem(at->at_hold);
                    404:        at->at_hold = 0;
                    405:        at->at_timer = at->at_flags = 0;
                    406:        at->at_iaddr.s_addr = 0;
                    407:        splx(s);
                    408: }
                    409: 
                    410: /*
                    411:  * Enter a new address in arptab, pushing out the oldest entry 
                    412:  * from the bucket if there is no room.
                    413:  * This always succeeds since no bucket can be completely filled
                    414:  * with permanent entries (except from arpioctl when testing whether
                    415:  * another permanent entry will fit).
                    416:  */
                    417: struct arptab *
                    418: arptnew(addr)
                    419:        struct in_addr *addr;
                    420: {
                    421:        register n;
                    422:        int oldest = -1;
                    423:        register struct arptab *at, *ato = NULL;
                    424:        static int first = 1;
                    425: 
                    426:        if (first) {
                    427:                first = 0;
                    428:                timeout(arptimer, (caddr_t)0, hz);
                    429:        }
                    430:        at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
                    431:        for (n = 0; n < ARPTAB_BSIZ; n++,at++) {
                    432:                if (at->at_flags == 0)
                    433:                        goto out;        /* found an empty entry */
                    434:                if (at->at_flags & ATF_PERM)
                    435:                        continue;
                    436:                if (at->at_timer > oldest) {
                    437:                        oldest = at->at_timer;
                    438:                        ato = at;
                    439:                }
                    440:        }
                    441:        if (ato == NULL)
                    442:                return (NULL);
                    443:        at = ato;
                    444:        arptfree(at);
                    445: out:
                    446:        at->at_iaddr = *addr;
                    447:        at->at_flags = ATF_INUSE;
                    448:        return (at);
                    449: }
                    450: 
                    451: arpioctl(cmd, data)
                    452:        int cmd;
                    453:        caddr_t data;
                    454: {
                    455:        register struct arpreq *ar = (struct arpreq *)data;
                    456:        register struct arptab *at;
                    457:        register struct sockaddr_in *sin;
                    458:        int s;
                    459: 
                    460:        if (ar->arp_pa.sa_family != AF_INET ||
                    461:            ar->arp_ha.sa_family != AF_UNSPEC)
                    462:                return (EAFNOSUPPORT);
                    463:        sin = (struct sockaddr_in *)&ar->arp_pa;
                    464:        s = splimp();
                    465:        ARPTAB_LOOK(at, sin->sin_addr.s_addr);
                    466:        if (at == NULL) {               /* not found */
                    467:                if (cmd != SIOCSARP) {
                    468:                        splx(s);
                    469:                        return (ENXIO);
                    470:                }
                    471:                if (ifa_ifwithnet(&ar->arp_pa) == NULL) {
                    472:                        splx(s);
                    473:                        return (ENETUNREACH);
                    474:                }
                    475:        }
                    476:        switch (cmd) {
                    477: 
                    478:        case SIOCSARP:          /* set entry */
                    479:                if (at == NULL) {
                    480:                        at = arptnew(&sin->sin_addr);
                    481:                        if (ar->arp_flags & ATF_PERM) {
                    482:                        /* never make all entries in a bucket permanent */
                    483:                                register struct arptab *tat;
                    484:                                
                    485:                                /* try to re-allocate */
                    486:                                tat = arptnew(&sin->sin_addr);
                    487:                                if (tat == NULL) {
                    488:                                        arptfree(at);
                    489:                                        splx(s);
                    490:                                        return (EADDRNOTAVAIL);
                    491:                                }
                    492:                                arptfree(tat);
                    493:                        }
                    494:                }
                    495:                bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_enaddr,
                    496:                    sizeof(at->at_enaddr));
                    497:                at->at_flags = ATF_COM | ATF_INUSE |
                    498:                        (ar->arp_flags & (ATF_PERM|ATF_PUBL));
                    499:                at->at_timer = 0;
                    500:                break;
                    501: 
                    502:        case SIOCDARP:          /* delete entry */
                    503:                arptfree(at);
                    504:                break;
                    505: 
                    506:        case SIOCGARP:          /* get entry */
                    507:                bcopy((caddr_t)at->at_enaddr, (caddr_t)ar->arp_ha.sa_data,
                    508:                    sizeof(at->at_enaddr));
                    509:                ar->arp_flags = at->at_flags;
                    510:                break;
                    511:        }
                    512:        splx(s);
                    513:        return (0);
                    514: }
                    515: 
                    516: /*
                    517:  * Convert Ethernet address to printable (loggable) representation.
                    518:  */
                    519: char *
                    520: ether_sprintf(ap)
                    521:        register u_char *ap;
                    522: {
                    523:        register i;
                    524:        static char etherbuf[18];
                    525:        register char *cp = etherbuf;
                    526:        static char digits[] = "0123456789abcdef";
                    527: 
                    528:        for (i = 0; i < 6; i++) {
                    529:                *cp++ = digits[*ap >> 4];
                    530:                *cp++ = digits[*ap++ & 0xf];
                    531:                *cp++ = ':';
                    532:        }
                    533:        *--cp = 0;
                    534:        return (etherbuf);
                    535: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.