Annotation of Net2/net/if_ethersubr.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1982, 1989 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  * 3. All advertising materials mentioning features or use of this software
        !            14:  *    must display the following acknowledgement:
        !            15:  *     This product includes software developed by the University of
        !            16:  *     California, Berkeley and its contributors.
        !            17:  * 4. Neither the name of the University nor the names of its contributors
        !            18:  *    may be used to endorse or promote products derived from this software
        !            19:  *    without specific prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            31:  * SUCH DAMAGE.
        !            32:  *
        !            33:  *     @(#)if_ethersubr.c      7.13 (Berkeley) 4/20/91
        !            34:  */
        !            35: 
        !            36: #include "param.h"
        !            37: #include "systm.h"
        !            38: #include "kernel.h"
        !            39: #include "malloc.h"
        !            40: #include "mbuf.h"
        !            41: #include "protosw.h"
        !            42: #include "socket.h"
        !            43: #include "ioctl.h"
        !            44: #include "errno.h"
        !            45: #include "syslog.h"
        !            46: 
        !            47: #include "if.h"
        !            48: #include "netisr.h"
        !            49: #include "route.h"
        !            50: #include "if_llc.h"
        !            51: #include "if_dl.h"
        !            52: 
        !            53: #include "machine/mtpr.h"
        !            54: 
        !            55: #ifdef INET
        !            56: #include "../netinet/in.h"
        !            57: #include "../netinet/in_var.h"
        !            58: #endif
        !            59: #include "../netinet/if_ether.h"
        !            60: 
        !            61: #ifdef NS
        !            62: #include "../netns/ns.h"
        !            63: #include "../netns/ns_if.h"
        !            64: #endif
        !            65: 
        !            66: #ifdef ISO
        !            67: #include "../netiso/argo_debug.h"
        !            68: #include "../netiso/iso.h"
        !            69: #include "../netiso/iso_var.h"
        !            70: #include "../netiso/iso_snpac.h"
        !            71: #endif
        !            72: 
        !            73: u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
        !            74: extern struct ifnet loif;
        !            75: 
        !            76: /*
        !            77:  * Ethernet output routine.
        !            78:  * Encapsulate a packet of type family for the local net.
        !            79:  * Use trailer local net encapsulation if enough data in first
        !            80:  * packet leaves a multiple of 512 bytes of data in remainder.
        !            81:  * Assumes that ifp is actually pointer to arpcom structure.
        !            82:  */
        !            83: ether_output(ifp, m0, dst, rt)
        !            84:        register struct ifnet *ifp;
        !            85:        struct mbuf *m0;
        !            86:        struct sockaddr *dst;
        !            87:        struct rtentry *rt;
        !            88: {
        !            89:        short type;
        !            90:        int s, error = 0;
        !            91:        u_char edst[6];
        !            92:        struct in_addr idst;
        !            93:        register struct mbuf *m = m0;
        !            94:        struct mbuf *mcopy = (struct mbuf *)0;
        !            95:        register struct ether_header *eh;
        !            96:        int usetrailers, off, len = m->m_pkthdr.len;
        !            97: #define        ac ((struct arpcom *)ifp)
        !            98: 
        !            99:        if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
        !           100:                error = ENETDOWN;
        !           101:                goto bad;
        !           102:        }
        !           103:        ifp->if_lastchange = time;
        !           104:        switch (dst->sa_family) {
        !           105: 
        !           106: #ifdef INET
        !           107:        case AF_INET:
        !           108:                idst = ((struct sockaddr_in *)dst)->sin_addr;
        !           109:                if (!arpresolve(ac, m, &idst, edst, &usetrailers))
        !           110:                        return (0);     /* if not yet resolved */
        !           111:                if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
        !           112:                        mcopy = m_copy(m, 0, (int)M_COPYALL);
        !           113:                off = m->m_pkthdr.len - m->m_len;
        !           114:                if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
        !           115:                    (m->m_flags & M_EXT) == 0 &&
        !           116:                    m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) {
        !           117:                        type = ETHERTYPE_TRAIL + (off>>9);
        !           118:                        m->m_data -= 2 * sizeof (u_short);
        !           119:                        m->m_len += 2 * sizeof (u_short);
        !           120:                        len += 2 * sizeof (u_short);
        !           121:                        *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
        !           122:                        *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
        !           123:                        goto gottrailertype;
        !           124:                }
        !           125:                type = ETHERTYPE_IP;
        !           126:                goto gottype;
        !           127: #endif
        !           128: #ifdef NS
        !           129:        case AF_NS:
        !           130:                type = ETHERTYPE_NS;
        !           131:                bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
        !           132:                    (caddr_t)edst, sizeof (edst));
        !           133:                if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
        !           134:                        return (looutput(ifp, m, dst, rt));
        !           135:                if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1))
        !           136:                        mcopy = m_copy(m, 0, (int)M_COPYALL);
        !           137:                goto gottype;
        !           138: #endif
        !           139: #ifdef ISO
        !           140:        case AF_ISO: {
        !           141:                int     snpalen;
        !           142:                struct  llc *l;
        !           143: 
        !           144:        iso_again:
        !           145:                if (rt && rt->rt_gateway && (rt->rt_flags & RTF_UP)) {
        !           146:                        if (rt->rt_flags & RTF_GATEWAY) {
        !           147:                                if (rt->rt_llinfo) {
        !           148:                                        rt = (struct rtentry *)rt->rt_llinfo;
        !           149:                                        goto iso_again;
        !           150:                                }
        !           151:                        } else {
        !           152:                                register struct sockaddr_dl *sdl = 
        !           153:                                        (struct sockaddr_dl *)rt->rt_gateway;
        !           154:                                if (sdl && sdl->sdl_family == AF_LINK
        !           155:                                    && sdl->sdl_alen > 0) {
        !           156:                                        bcopy(LLADDR(sdl), (char *)edst,
        !           157:                                                                sizeof(edst));
        !           158:                                        goto iso_resolved;
        !           159:                                }
        !           160:                        }
        !           161:                }
        !           162:                if ((error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
        !           163:                                        (char *)edst, &snpalen)) > 0)
        !           164:                        goto bad; /* Not Resolved */
        !           165:        iso_resolved:
        !           166:                if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
        !           167:                    (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
        !           168:                        M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
        !           169:                        if (mcopy) {
        !           170:                                eh = mtod(mcopy, struct ether_header *);
        !           171:                                bcopy((caddr_t)edst,
        !           172:                                      (caddr_t)eh->ether_dhost, sizeof (edst));
        !           173:                                bcopy((caddr_t)ac->ac_enaddr,
        !           174:                                      (caddr_t)eh->ether_shost, sizeof (edst));
        !           175:                        }
        !           176:                }
        !           177:                M_PREPEND(m, 3, M_DONTWAIT);
        !           178:                if (m == NULL)
        !           179:                        return (0);
        !           180:                type = m->m_pkthdr.len;
        !           181:                l = mtod(m, struct llc *);
        !           182:                l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
        !           183:                l->llc_control = LLC_UI;
        !           184:                len += 3;
        !           185:                IFDEBUG(D_ETHER)
        !           186:                        int i;
        !           187:                        printf("unoutput: sending pkt to: ");
        !           188:                        for (i=0; i<6; i++)
        !           189:                                printf("%x ", edst[i] & 0xff);
        !           190:                        printf("\n");
        !           191:                ENDDEBUG
        !           192:                } goto gottype;
        !           193: #endif ISO
        !           194: #ifdef RMP
        !           195:        case AF_RMP:
        !           196:                /*
        !           197:                 *  This is IEEE 802.3 -- the Ethernet `type' field is
        !           198:                 *  really a `length' field.
        !           199:                 */
        !           200:                type = m->m_len;
        !           201:                bcopy((caddr_t)dst->sa_data, (caddr_t)edst, sizeof(edst));
        !           202:                break;
        !           203: #endif
        !           204: 
        !           205:        case AF_UNSPEC:
        !           206:                eh = (struct ether_header *)dst->sa_data;
        !           207:                bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
        !           208:                type = eh->ether_type;
        !           209:                goto gottype;
        !           210: 
        !           211:        default:
        !           212:                printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
        !           213:                        dst->sa_family);
        !           214:                error = EAFNOSUPPORT;
        !           215:                goto bad;
        !           216:        }
        !           217: 
        !           218: gottrailertype:
        !           219:        /*
        !           220:         * Packet to be sent as trailer: move first packet
        !           221:         * (control information) to end of chain.
        !           222:         */
        !           223:        while (m->m_next)
        !           224:                m = m->m_next;
        !           225:        m->m_next = m0;
        !           226:        m = m0->m_next;
        !           227:        m0->m_next = 0;
        !           228: 
        !           229: gottype:
        !           230:        if (mcopy)
        !           231:                (void) looutput(ifp, mcopy, dst, rt);
        !           232:        /*
        !           233:         * Add local net header.  If no space in first mbuf,
        !           234:         * allocate another.
        !           235:         */
        !           236:        M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
        !           237:        if (m == 0) {
        !           238:                error = ENOBUFS;
        !           239:                goto bad;
        !           240:        }
        !           241:        eh = mtod(m, struct ether_header *);
        !           242:        type = htons((u_short)type);
        !           243:        bcopy((caddr_t)&type,(caddr_t)&eh->ether_type,
        !           244:                sizeof(eh->ether_type));
        !           245:        bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
        !           246:        bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
        !           247:            sizeof(eh->ether_shost));
        !           248:        s = splimp();
        !           249:        /*
        !           250:         * Queue message on interface, and start output if interface
        !           251:         * not yet active.
        !           252:         */
        !           253:        if (IF_QFULL(&ifp->if_snd)) {
        !           254:                IF_DROP(&ifp->if_snd);
        !           255:                splx(s);
        !           256:                error = ENOBUFS;
        !           257:                goto bad;
        !           258:        }
        !           259:        IF_ENQUEUE(&ifp->if_snd, m);
        !           260:        if ((ifp->if_flags & IFF_OACTIVE) == 0)
        !           261:                (*ifp->if_start)(ifp);
        !           262:        splx(s);
        !           263:        ifp->if_obytes += len + sizeof (struct ether_header);
        !           264:        if (edst[0] & 1)
        !           265:                ifp->if_omcasts++;
        !           266:        return (error);
        !           267: 
        !           268: bad:
        !           269:        if (m)
        !           270:                m_freem(m);
        !           271:        return (error);
        !           272: }
        !           273: 
        !           274: /*
        !           275:  * Process a received Ethernet packet;
        !           276:  * the packet is in the mbuf chain m without
        !           277:  * the ether header, which is provided separately.
        !           278:  */
        !           279: ether_input(ifp, eh, m)
        !           280:        struct ifnet *ifp;
        !           281:        register struct ether_header *eh;
        !           282:        struct mbuf *m;
        !           283: {
        !           284:        register struct ifqueue *inq;
        !           285:        register struct llc *l;
        !           286:        int s;
        !           287: 
        !           288:        ifp->if_lastchange = time;
        !           289:        ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
        !           290:        if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
        !           291:            sizeof(etherbroadcastaddr)) == 0)
        !           292:                m->m_flags |= M_BCAST;
        !           293:        else if (eh->ether_dhost[0] & 1)
        !           294:                m->m_flags |= M_MCAST;
        !           295:        if (m->m_flags & (M_BCAST|M_MCAST))
        !           296:                ifp->if_imcasts++;
        !           297: 
        !           298:        switch (eh->ether_type) {
        !           299: #ifdef INET
        !           300:        case ETHERTYPE_IP:
        !           301:                schednetisr(NETISR_IP);
        !           302:                inq = &ipintrq;
        !           303:                break;
        !           304: 
        !           305:        case ETHERTYPE_ARP:
        !           306:                arpinput((struct arpcom *)ifp, m);
        !           307:                return;
        !           308: #endif
        !           309: #ifdef NS
        !           310:        case ETHERTYPE_NS:
        !           311:                schednetisr(NETISR_NS);
        !           312:                inq = &nsintrq;
        !           313:                break;
        !           314: 
        !           315: #endif
        !           316:        default:
        !           317: #ifdef ISO
        !           318:                if (eh->ether_type > ETHERMTU)
        !           319:                        goto dropanyway;
        !           320:                l = mtod(m, struct llc *);
        !           321:                switch (l->llc_control) {
        !           322:                case LLC_UI:
        !           323:                /* LLC_UI_P forbidden in class 1 service */
        !           324:                    if ((l->llc_dsap == LLC_ISO_LSAP) &&
        !           325:                        (l->llc_ssap == LLC_ISO_LSAP)) {
        !           326:                                /* LSAP for ISO */
        !           327:                        if (m->m_pkthdr.len > eh->ether_type)
        !           328:                                m_adj(m, eh->ether_type - m->m_pkthdr.len);
        !           329:                        m->m_data += 3;         /* XXX */
        !           330:                        m->m_len -= 3;          /* XXX */
        !           331:                        m->m_pkthdr.len -= 3;   /* XXX */
        !           332:                        M_PREPEND(m, sizeof *eh, M_DONTWAIT);
        !           333:                        if (m == 0)
        !           334:                                return;
        !           335:                        *mtod(m, struct ether_header *) = *eh;
        !           336:                        IFDEBUG(D_ETHER)
        !           337:                            printf("clnp packet");
        !           338:                        ENDDEBUG
        !           339:                        schednetisr(NETISR_ISO);
        !           340:                        inq = &clnlintrq;
        !           341:                        break;
        !           342:                    }
        !           343:                    goto dropanyway;
        !           344: 
        !           345:                case LLC_XID:
        !           346:                case LLC_XID_P:
        !           347:                    if(m->m_len < 6)
        !           348:                        goto dropanyway;
        !           349:                    l->llc_window = 0;
        !           350:                    l->llc_fid = 9;
        !           351:                    l->llc_class = 1;
        !           352:                    l->llc_dsap = l->llc_ssap = 0;
        !           353:                    /* Fall through to */
        !           354:                case LLC_TEST:
        !           355:                case LLC_TEST_P:
        !           356:                {
        !           357:                    struct sockaddr sa;
        !           358:                    register struct ether_header *eh2;
        !           359:                    int i;
        !           360:                    u_char c = l->llc_dsap;
        !           361:                    l->llc_dsap = l->llc_ssap;
        !           362:                    l->llc_ssap = c;
        !           363:                    if (m->m_flags & (M_BCAST | M_MCAST))
        !           364:                        bcopy((caddr_t)ac->ac_enaddr,
        !           365:                              (caddr_t)eh->ether_dhost, 6);
        !           366:                    sa.sa_family = AF_UNSPEC;
        !           367:                    sa.sa_len = sizeof(sa);
        !           368:                    eh2 = (struct ether_header *)sa.sa_data;
        !           369:                    for (i = 0; i < 6; i++) {
        !           370:                        eh2->ether_shost[i] = c = eh->ether_dhost[i];
        !           371:                        eh2->ether_dhost[i] = 
        !           372:                                eh->ether_dhost[i] = eh->ether_shost[i];
        !           373:                        eh->ether_shost[i] = c;
        !           374:                    }
        !           375:                    ifp->if_output(ifp, m, &sa);
        !           376:                    return;
        !           377:                }
        !           378:                dropanyway:
        !           379:                default:
        !           380:                    m_freem(m);
        !           381:                    return;
        !           382:            }
        !           383: #else
        !           384:            m_freem(m);
        !           385:            return;
        !           386: #endif ISO
        !           387:        }
        !           388: 
        !           389:        s = splimp();
        !           390:        if (IF_QFULL(inq)) {
        !           391:                IF_DROP(inq);
        !           392:                m_freem(m);
        !           393:        } else
        !           394:                IF_ENQUEUE(inq, m);
        !           395:        splx(s);
        !           396: }
        !           397: 
        !           398: /*
        !           399:  * Convert Ethernet address to printable (loggable) representation.
        !           400:  */
        !           401: static char digits[] = "0123456789abcdef";
        !           402: char *
        !           403: ether_sprintf(ap)
        !           404:        register u_char *ap;
        !           405: {
        !           406:        register i;
        !           407:        static char etherbuf[18];
        !           408:        register char *cp = etherbuf;
        !           409: 
        !           410:        for (i = 0; i < 6; i++) {
        !           411:                *cp++ = digits[*ap >> 4];
        !           412:                *cp++ = digits[*ap++ & 0xf];
        !           413:                *cp++ = ':';
        !           414:        }
        !           415:        *--cp = 0;
        !           416:        return (etherbuf);
        !           417: }

unix.superglobalmegacorp.com

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