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

1.1       root        1: /*     if_ether.c      6.2     83/08/28        */
                      2: 
                      3: /*
                      4:  * Ethernet address resolution protocol.
                      5:  */
                      6: 
                      7: #include "../h/param.h"
                      8: #include "../h/systm.h"
                      9: #include "../h/mbuf.h"
                     10: #include "../h/socket.h"
                     11: #include "../h/time.h"
                     12: #include "../h/kernel.h"
                     13: #include "../h/errno.h"
                     14: 
                     15: #include "../net/if.h"
                     16: #include "../netinet/in.h"
                     17: #include "../netinet/if_ether.h"
                     18: 
                     19: 
                     20: /*
                     21:  * Internet to ethernet address resolution table.
                     22:  */
                     23: struct arptab {
                     24:        struct  in_addr at_iaddr;       /* internet address */
                     25:        u_char  at_enaddr[6];           /* ethernet address */
                     26:        struct  mbuf *at_hold;          /* last packet until resolved/timeout */
                     27:        u_char  at_timer;               /* minutes since last reference */
                     28:        u_char  at_flags;               /* flags */
                     29: };
                     30: /* at_flags field values */
                     31: #define        ATF_INUSE       1               /* entry in use */
                     32: #define ATF_COM                2               /* completed entry (enaddr valid) */
                     33: 
                     34: #define        ARPTAB_BSIZ     5               /* bucket size */
                     35: #define        ARPTAB_NB       19              /* number of buckets */
                     36: #define        ARPTAB_SIZE     (ARPTAB_BSIZ * ARPTAB_NB)
                     37: struct arptab arptab[ARPTAB_SIZE];
                     38: 
                     39: #define        ARPTAB_HASH(a) \
                     40:        ((short)((((a) >> 16) ^ (a)) & 0x7fff) % ARPTAB_NB)
                     41: 
                     42: #define        ARPTAB_LOOK(at,addr) { \
                     43:        register n; \
                     44:        at = &arptab[ARPTAB_HASH(addr) * ARPTAB_BSIZ]; \
                     45:        for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) \
                     46:                if (at->at_iaddr.s_addr == addr) \
                     47:                        break; \
                     48:        if (n >= ARPTAB_BSIZ) \
                     49:                at = 0; }
                     50: 
                     51: struct arpcom *arpcom;         /* chain of active ether interfaces */
                     52: int    arpt_age;               /* aging timer */
                     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:  * Local addresses in the range oldmap to infinity are
                     64:  * mapped according to the old mapping scheme.  That is,
                     65:  * mapping of Internet to Ethernet addresses is performed
                     66:  * by taking the high three bytes of the network interface's
                     67:  * address and the low three bytes of the local address part.
                     68:  * This only allows boards from the same manufacturer to
                     69:  * communicate unless the on-board address is overridden
                     70:  * (not possible in many manufacture's hardware).
                     71:  *
                     72:  * NB: setting oldmap to zero completely disables ARP
                     73:  *     (i.e. identical to setting IFF_NOARP with an ioctl).
                     74:  */
                     75: int    oldmap = 1024;
                     76: 
                     77: /*
                     78:  * Attach an ethernet interface to the list "arpcom" where
                     79:  * arptimer() can find it.  If first time 
                     80:  * initialization, start arptimer().
                     81:  */
                     82: arpattach(ac)
                     83:        register struct arpcom *ac;
                     84: {
                     85:        register struct arpcom *acp;
                     86: 
                     87:        for (acp = arpcom; acp != (struct arpcom *)0; acp = acp->ac_ac)
                     88:                if (acp == ac)          /* if already on list */
                     89:                        return;
                     90:        ac->ac_ac = arpcom;
                     91:        arpcom = ac;
                     92:        if (arpcom->ac_ac == 0)         /* very first time */
                     93:                arptimer();
                     94: }
                     95: 
                     96: /*
                     97:  * Timeout routine.  Age arp_tab entries once a minute.
                     98:  */
                     99: arptimer()
                    100: {
                    101:        register struct arptab *at;
                    102:        register i;
                    103: 
                    104:        timeout(arptimer, (caddr_t)0, hz);
                    105: #ifdef notdef
                    106:        if (++arpt_sanity > ARPT_SANITY) {
                    107:                register struct arpcom *ac;
                    108: 
                    109:                /*
                    110:                 * Randomize sanity timer based on my host address.
                    111:                 * Ask who has my own address;  if someone else replies,
                    112:                 * then they are impersonating me.
                    113:                 */
                    114:                arpt_sanity = arpcom->ac_enaddr[5] & 0x3f;
                    115:                for (ac = arpcom; ac != (struct arpcom *)-1; ac = ac->ac_ac)
                    116:                        arpwhohas(ac, &((struct sockaddr_in *)
                    117:                            &ac->ac_if.if_addr)->sin_addr);
                    118:        }
                    119: #endif
                    120:        if (++arpt_age > ARPT_AGE) {
                    121:                arpt_age = 0;
                    122:                at = &arptab[0];
                    123:                for (i = 0; i < ARPTAB_SIZE; i++, at++) {
                    124:                        if (at->at_flags == 0)
                    125:                                continue;
                    126:                        if (++at->at_timer < ((at->at_flags&ATF_COM) ?
                    127:                            ARPT_KILLC : ARPT_KILLI))
                    128:                                continue;
                    129:                        /* timer has expired, clear entry */
                    130:                        arptfree(at);
                    131:                }
                    132:        }
                    133: }
                    134: 
                    135: /*
                    136:  * Broadcast an ARP packet, asking who has addr on interface ac.
                    137:  */
                    138: arpwhohas(ac, addr)
                    139:        register struct arpcom *ac;
                    140:        struct in_addr *addr;
                    141: {
                    142:        register struct mbuf *m;
                    143:        register struct ether_header *eh;
                    144:        register struct ether_arp *ea;
                    145:        struct sockaddr sa;
                    146: 
                    147:        if ((m = m_get(M_DONTWAIT, MT_DATA)) == NULL)
                    148:                return;
                    149:        m->m_len = sizeof *ea + sizeof *eh;
                    150:        m->m_off = MMAXOFF - m->m_len;
                    151:        ea = mtod(m, struct ether_arp *);
                    152:        eh = (struct ether_header *)sa.sa_data;
                    153:        bzero((caddr_t)ea, sizeof (*ea));
                    154:        bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
                    155:           sizeof (etherbroadcastaddr));
                    156:        eh->ether_type = ETHERPUP_ARPTYPE;      /* if_output will swap */
                    157:        ea->arp_hrd = htons(ARPHRD_ETHER);
                    158:        ea->arp_pro = htons(ETHERPUP_IPTYPE);
                    159:        ea->arp_hln = sizeof ea->arp_sha;       /* hardware address length */
                    160:        ea->arp_pln = sizeof ea->arp_spa;       /* protocol address length */
                    161:        ea->arp_op = htons(ARPOP_REQUEST);
                    162:        bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
                    163:           sizeof (ea->arp_sha));
                    164:        bcopy((caddr_t)&((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr,
                    165:           (caddr_t)ea->arp_spa, sizeof (ea->arp_spa));
                    166:        bcopy((caddr_t)addr, (caddr_t)ea->arp_tpa, sizeof (ea->arp_tpa));
                    167:        sa.sa_family = AF_UNSPEC;
                    168:        (void) (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
                    169: }
                    170: 
                    171: /*
                    172:  * Resolve an IP address into an ethernet address.  If success, 
                    173:  * desten is filled in and 1 is returned.  If there is no entry
                    174:  * in arptab, set one up and broadcast a request 
                    175:  * for the IP address;  return 0.  Hold onto this mbuf and 
                    176:  * resend it once the address is finally resolved.
                    177:  *
                    178:  * We do some (conservative) locking here at splimp, since
                    179:  * arptab is also altered from input interrupt service (ecintr/ilintr
                    180:  * calls arpinput when ETHERPUP_ARPTYPE packets come in).
                    181:  */
                    182: arpresolve(ac, m, destip, desten)
                    183:        register struct arpcom *ac;
                    184:        struct mbuf *m;
                    185:        register struct in_addr *destip;
                    186:        register u_char *desten;
                    187: {
                    188:        register struct arptab *at;
                    189:        register struct ifnet *ifp;
                    190:        struct sockaddr_in sin;
                    191:        int s, lna;
                    192: 
                    193:        lna = in_lnaof(*destip);
                    194:        if (lna == INADDR_ANY) {        /* broadcast address */
                    195:                bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
                    196:                   sizeof (etherbroadcastaddr));
                    197:                return (1);
                    198:        }
                    199:        ifp = &ac->ac_if;
                    200:        /* if for us, then use software loopback driver */
                    201:        if (destip->s_addr ==
                    202:            ((struct sockaddr_in *)&ifp->if_addr)-> sin_addr.s_addr) {
                    203:                sin.sin_family = AF_INET;
                    204:                sin.sin_addr = *destip;
                    205:                return (looutput(&loif, m, (struct sockaddr *)&sin));
                    206:        }
                    207:        if ((ifp->if_flags & IFF_NOARP) || lna >= oldmap) {
                    208:                bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);
                    209:                desten[3] = (lna >> 16) & 0x7f;
                    210:                desten[4] = (lna >> 8) & 0xff;
                    211:                desten[5] = lna & 0xff;
                    212:                return (1);
                    213:        }
                    214:        s = splimp();
                    215:        ARPTAB_LOOK(at, destip->s_addr);
                    216:        if (at == 0) {                  /* not found */
                    217:                at = arptnew(destip);
                    218:                at->at_hold = m;
                    219:                arpwhohas(ac, destip);
                    220:                splx(s);
                    221:                return (0);
                    222:        }
                    223:        at->at_timer = 0;               /* restart the timer */
                    224:        if (at->at_flags & ATF_COM) {   /* entry IS complete */
                    225:                bcopy((caddr_t)at->at_enaddr, (caddr_t)desten, 6);
                    226:                splx(s);
                    227:                return (1);
                    228:        }
                    229:        /*
                    230:         * There is an arptab entry, but no ethernet address
                    231:         * response yet.  Replace the held mbuf with this
                    232:         * latest one.
                    233:         */
                    234:        if (at->at_hold)
                    235:                m_freem(at->at_hold);
                    236:        at->at_hold = m;
                    237:        arpwhohas(ac, destip);          /* ask again */
                    238:        splx(s);
                    239:        return (0);
                    240: }
                    241: 
                    242: /*
                    243:  * Find my own IP address.  It will either be waiting for us in
                    244:  * monitor RAM, or can be obtained via broadcast to the file/boot
                    245:  * server (not necessarily using the ARP packet format).
                    246:  *
                    247:  * Unimplemented at present, return 0 and assume that the host
                    248:  * will set his own IP address via the SIOCSIFADDR ioctl.
                    249:  */
                    250: /*ARGSUSED*/
                    251: struct in_addr
                    252: arpmyaddr(ac)
                    253:        register struct arpcom *ac;
                    254: {
                    255:        static struct in_addr addr;
                    256: 
                    257: #ifdef lint
                    258:        ac = ac;
                    259: #endif
                    260:        addr.s_addr = 0;
                    261:        return (addr);
                    262: }
                    263: 
                    264: /*
                    265:  * Called from ecintr/ilintr when ether packet type ETHERPUP_ARP
                    266:  * is received.  Algorithm is exactly that given in RFC 826.
                    267:  * In addition, a sanity check is performed on the sender
                    268:  * protocol address, to catch impersonators.
                    269:  */
                    270: arpinput(ac, m)
                    271:        register struct arpcom *ac;
                    272:        struct mbuf *m;
                    273: {
                    274:        register struct ether_arp *ea;
                    275:        struct ether_header *eh;
                    276:        register struct arptab *at = 0;  /* same as "merge" flag */
                    277:        struct sockaddr_in sin;
                    278:        struct sockaddr sa;
                    279:        struct mbuf *mhold;
                    280:        struct in_addr isaddr,itaddr,myaddr;
                    281: 
                    282:        if (m->m_len < sizeof *ea)
                    283:                goto out;
                    284:        myaddr = ((struct sockaddr_in *)&ac->ac_if.if_addr)->sin_addr;
                    285:        ea = mtod(m, struct ether_arp *);
                    286:        if (ntohs(ea->arp_pro) != ETHERPUP_IPTYPE)
                    287:                goto out;
                    288:        isaddr.s_addr = ((struct in_addr *)ea->arp_spa)->s_addr;
                    289:        itaddr.s_addr = ((struct in_addr *)ea->arp_tpa)->s_addr;
                    290:        if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
                    291:          sizeof (ac->ac_enaddr)))
                    292:                goto out;       /* it's from me, ignore it. */
                    293:        if (isaddr.s_addr == myaddr.s_addr) {
                    294:                printf("duplicate IP address!! sent from ethernet address: ");
                    295:                printf("%x %x %x %x %x %x\n", ea->arp_sha[0], ea->arp_sha[1],
                    296:                    ea->arp_sha[2], ea->arp_sha[3],
                    297:                    ea->arp_sha[4], ea->arp_sha[5]);
                    298:                if (ntohs(ea->arp_op) == ARPOP_REQUEST)
                    299:                        goto reply;
                    300:                goto out;
                    301:        }
                    302:        ARPTAB_LOOK(at, isaddr.s_addr);
                    303:        if (at) {
                    304:                bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
                    305:                   sizeof (ea->arp_sha));
                    306:                at->at_flags |= ATF_COM;
                    307:                if (at->at_hold) {
                    308:                        mhold = at->at_hold;
                    309:                        at->at_hold = 0;
                    310:                        sin.sin_family = AF_INET;
                    311:                        sin.sin_addr = isaddr;
                    312:                        (*ac->ac_if.if_output)(&ac->ac_if, 
                    313:                            mhold, (struct sockaddr *)&sin);
                    314:                }
                    315:        }
                    316:        if (itaddr.s_addr != myaddr.s_addr)
                    317:                goto out;       /* if I am not the target */
                    318:        if (at == 0) {          /* ensure we have a table entry */
                    319:                at = arptnew(&isaddr);
                    320:                bcopy((caddr_t)ea->arp_sha, (caddr_t)at->at_enaddr,
                    321:                   sizeof (ea->arp_sha));
                    322:                at->at_flags |= ATF_COM;
                    323:        }
                    324:        if (ntohs(ea->arp_op) != ARPOP_REQUEST)
                    325:                goto out;
                    326: reply:
                    327:        bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
                    328:           sizeof (ea->arp_sha));
                    329:        bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa,
                    330:           sizeof (ea->arp_spa));
                    331:        bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
                    332:           sizeof (ea->arp_sha));
                    333:        bcopy((caddr_t)&myaddr, (caddr_t)ea->arp_spa,
                    334:           sizeof (ea->arp_spa));
                    335:        ea->arp_op = htons(ARPOP_REPLY);
                    336:        eh = (struct ether_header *)sa.sa_data;
                    337:        bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
                    338:           sizeof (eh->ether_dhost));
                    339:        eh->ether_type = ETHERPUP_ARPTYPE;
                    340:        sa.sa_family = AF_UNSPEC;
                    341:        (*ac->ac_if.if_output)(&ac->ac_if, m, &sa);
                    342:        return;
                    343: out:
                    344:        m_freem(m);
                    345:        return;
                    346: }
                    347: 
                    348: /*
                    349:  * Free an arptab entry.
                    350:  */
                    351: arptfree(at)
                    352:        register struct arptab *at;
                    353: {
                    354:        int s = splimp();
                    355: 
                    356:        if (at->at_hold)
                    357:                m_freem(at->at_hold);
                    358:        at->at_hold = 0;
                    359:        at->at_timer = at->at_flags = 0;
                    360:        at->at_iaddr.s_addr = 0;
                    361:        splx(s);
                    362: }
                    363: 
                    364: /*
                    365:  * Enter a new address in arptab, pushing out the oldest entry 
                    366:  * from the bucket if there is no room.
                    367:  */
                    368: struct arptab *
                    369: arptnew(addr)
                    370:        struct in_addr *addr;
                    371: {
                    372:        register n;
                    373:        int oldest = 0;
                    374:        register struct arptab *at, *ato;
                    375: 
                    376:        ato = at = &arptab[ARPTAB_HASH(addr->s_addr) * ARPTAB_BSIZ];
                    377:        for (n = 0 ; n < ARPTAB_BSIZ ; n++,at++) {
                    378:                if (at->at_flags == 0)
                    379:                        goto out;        /* found an empty entry */
                    380:                if (at->at_timer > oldest) {
                    381:                        oldest = at->at_timer;
                    382:                        ato = at;
                    383:                }
                    384:        }
                    385:        at = ato;
                    386:        arptfree(at);
                    387: out:
                    388:        at->at_iaddr = *addr;
                    389:        at->at_flags = ATF_INUSE;
                    390:        return (at);
                    391: }

unix.superglobalmegacorp.com

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