if_fddisubr.c revision 32350
17055Sdg/* 221830Sjoerg * Copyright (c) 1995, 1996 321830Sjoerg * Matt Thomas <matt@3am-software.com>. All rights reserved. 47055Sdg * Copyright (c) 1982, 1989, 1993 57055Sdg * The Regents of the University of California. All rights reserved. 67055Sdg * 77055Sdg * Redistribution and use in source and binary forms, with or without 87055Sdg * modification, are permitted provided that the following conditions 97055Sdg * are met: 107055Sdg * 1. Redistributions of source code must retain the above copyright 117055Sdg * notice, this list of conditions and the following disclaimer. 127055Sdg * 2. Redistributions in binary form must reproduce the above copyright 137055Sdg * notice, this list of conditions and the following disclaimer in the 147055Sdg * documentation and/or other materials provided with the distribution. 157055Sdg * 3. All advertising materials mentioning features or use of this software 167055Sdg * must display the following acknowledgement: 177055Sdg * This product includes software developed by the University of 187055Sdg * California, Berkeley and its contributors. 197055Sdg * 4. Neither the name of the University nor the names of its contributors 207055Sdg * may be used to endorse or promote products derived from this software 217055Sdg * without specific prior written permission. 227055Sdg * 237055Sdg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 247055Sdg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 257055Sdg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 267055Sdg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 277055Sdg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 287055Sdg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 297055Sdg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 307055Sdg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 317055Sdg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 327055Sdg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 337055Sdg * SUCH DAMAGE. 347055Sdg * 357061Sdg * from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp 3632350Seivind * $Id: if_fddisubr.c,v 1.23 1997/12/15 20:31:01 eivind Exp $ 377055Sdg */ 387055Sdg 3932350Seivind#include "opt_inet.h" 4031742Seivind#include "opt_ipx.h" 4131742Seivind 427055Sdg#include <sys/param.h> 437055Sdg#include <sys/systm.h> 447055Sdg#include <sys/kernel.h> 457055Sdg#include <sys/mbuf.h> 467055Sdg#include <sys/socket.h> 477055Sdg 487055Sdg#include <net/if.h> 497055Sdg#include <net/netisr.h> 507055Sdg#include <net/route.h> 517055Sdg#include <net/if_llc.h> 527055Sdg#include <net/if_dl.h> 537055Sdg#include <net/if_types.h> 547055Sdg 557055Sdg#ifdef INET 567055Sdg#include <netinet/in.h> 577055Sdg#include <netinet/in_var.h> 5832350Seivind#include <netinet/if_ether.h> 597055Sdg#endif 6032350Seivind#include <net/ethernet.h> /* XXX We probably should be able to drop this */ 6132350Seivind#include <net/if_arp.h> 6221830Sjoerg#if defined(__FreeBSD__) 637055Sdg#include <netinet/if_fddi.h> 6421830Sjoerg#else 6521830Sjoerg#include <net/if_fddi.h> 6621830Sjoerg#endif 677055Sdg 6811819Sjulian#ifdef IPX 6921830Sjoerg#include <netipx/ipx.h> 7011819Sjulian#include <netipx/ipx_if.h> 7111819Sjulian#endif 7211819Sjulian 737055Sdg#ifdef NS 747055Sdg#include <netns/ns.h> 757055Sdg#include <netns/ns_if.h> 767055Sdg#endif 777055Sdg 787055Sdg#ifdef DECNET 797055Sdg#include <netdnet/dn.h> 807055Sdg#endif 817055Sdg 827055Sdg#ifdef ISO 837055Sdg#include <netiso/argo_debug.h> 847055Sdg#include <netiso/iso.h> 857055Sdg#include <netiso/iso_var.h> 867055Sdg#include <netiso/iso_snpac.h> 877055Sdg#endif 887055Sdg 897055Sdg#ifdef LLC 907055Sdg#include <netccitt/dll.h> 917055Sdg#include <netccitt/llc_var.h> 927055Sdg#endif 937055Sdg 9421830Sjoerg#ifdef NETATALK 9521830Sjoerg#include <netatalk/at.h> 9621830Sjoerg#include <netatalk/at_var.h> 9721830Sjoerg#include <netatalk/at_extern.h> 9821830Sjoerg 9921830Sjoerg#define llc_snap_org_code llc_un.type_snap.org_code 10021830Sjoerg#define llc_snap_ether_type llc_un.type_snap.ether_type 10121830Sjoerg 10221830Sjoergextern u_char at_org_code[ 3 ]; 10321830Sjoergextern u_char aarp_org_code[ 3 ]; 10421830Sjoerg#endif /* NETATALK */ 10521830Sjoerg 1067055Sdg#if defined(LLC) && defined(CCITT) 1077055Sdgextern struct ifqueue pkintrq; 1087055Sdg#endif 1097055Sdg 11021830Sjoerg#include "bpfilter.h" 11121830Sjoerg 1127055Sdg#define senderr(e) { error = (e); goto bad;} 1137055Sdg 1147055Sdg/* 1157055Sdg * This really should be defined in if_llc.h but in case it isn't. 1167055Sdg */ 1177055Sdg#ifndef llc_snap 1187055Sdg#define llc_snap llc_un.type_snap 1197055Sdg#endif 1207055Sdg 12121830Sjoerg#if defined(__bsdi__) || defined(__NetBSD__) 12221830Sjoerg#define RTALLOC1(a, b) rtalloc1(a, b) 1237055Sdg#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e) 12421830Sjoerg#elif defined(__FreeBSD__) 12521830Sjoerg#define RTALLOC1(a, b) rtalloc1(a, b, 0UL) 1267055Sdg#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e, f) 1277055Sdg#endif 1287055Sdg/* 1297055Sdg * FDDI output routine. 1307055Sdg * Encapsulate a packet of type family for the local net. 1317055Sdg * Use trailer local net encapsulation if enough data in first 1327055Sdg * packet leaves a multiple of 512 bytes of data in remainder. 1337055Sdg * Assumes that ifp is actually pointer to arpcom structure. 1347055Sdg */ 1357055Sdgint 1367055Sdgfddi_output(ifp, m0, dst, rt0) 1377055Sdg register struct ifnet *ifp; 1387055Sdg struct mbuf *m0; 1397055Sdg struct sockaddr *dst; 1407055Sdg struct rtentry *rt0; 1417055Sdg{ 14221830Sjoerg u_int16_t type; 1437055Sdg int s, error = 0; 1447055Sdg u_char edst[6]; 1457055Sdg register struct mbuf *m = m0; 1467055Sdg register struct rtentry *rt; 14721830Sjoerg register struct fddi_header *fh; 1487055Sdg struct mbuf *mcopy = (struct mbuf *)0; 1497055Sdg struct arpcom *ac = (struct arpcom *)ifp; 1507055Sdg 1517055Sdg if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 1527055Sdg senderr(ENETDOWN); 15331264Sbde gettime(&ifp->if_lastchange); 15421830Sjoerg#if !defined(__bsdi__) || _BSDI_VERSION >= 199401 1557055Sdg if (rt = rt0) { 1567055Sdg if ((rt->rt_flags & RTF_UP) == 0) { 1577055Sdg if (rt0 = rt = RTALLOC1(dst, 1)) 1587055Sdg rt->rt_refcnt--; 15921830Sjoerg else 1607055Sdg senderr(EHOSTUNREACH); 1617055Sdg } 1627055Sdg if (rt->rt_flags & RTF_GATEWAY) { 1637055Sdg if (rt->rt_gwroute == 0) 1647055Sdg goto lookup; 1657055Sdg if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 1667055Sdg rtfree(rt); rt = rt0; 1677055Sdg lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 1); 1687055Sdg if ((rt = rt->rt_gwroute) == 0) 1697055Sdg senderr(EHOSTUNREACH); 1707055Sdg } 1717055Sdg } 1727055Sdg if (rt->rt_flags & RTF_REJECT) 1737055Sdg if (rt->rt_rmx.rmx_expire == 0 || 1747055Sdg time.tv_sec < rt->rt_rmx.rmx_expire) 1757055Sdg senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 1767055Sdg } 17721830Sjoerg#endif 1787055Sdg switch (dst->sa_family) { 1797055Sdg 1807055Sdg#ifdef INET 18121830Sjoerg case AF_INET: { 18221830Sjoerg#if !defined(__bsdi__) || _BSDI_VERSION >= 199401 1837055Sdg if (!ARPRESOLVE(ac, rt, m, dst, edst, rt0)) 1847055Sdg return (0); /* if not yet resolved */ 18521830Sjoerg#else 18621830Sjoerg int usetrailers; 18721830Sjoerg if (!arpresolve(ac, m, &((struct sockaddr_in *)dst)->sin_addr, edst, &usetrailers)) 18821830Sjoerg return (0); /* if not yet resolved */ 18921830Sjoerg#endif 1907055Sdg /* If broadcasting on a simplex interface, loopback a copy */ 1917055Sdg if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 1927055Sdg mcopy = m_copy(m, 0, (int)M_COPYALL); 19321830Sjoerg type = htons(ETHERTYPE_IP); 1947055Sdg break; 19521830Sjoerg } 1967055Sdg#endif 19711819Sjulian#ifdef IPX 19811819Sjulian case AF_IPX: 19925653Sjhay { 20025653Sjhay struct ifaddr *ia; 20125653Sjhay 20221830Sjoerg type = htons(ETHERTYPE_IPX); 20311819Sjulian bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 20411819Sjulian (caddr_t)edst, sizeof (edst)); 20525653Sjhay 20625653Sjhay for(ia = ifp->if_addrhead.tqh_first; ia != 0; 20725653Sjhay ia = ia->ifa_link.tqe_next) { 20825653Sjhay if(ia->ifa_addr->sa_family == AF_IPX && 20925653Sjhay !bcmp((caddr_t)edst, 21025653Sjhay (caddr_t)&((struct ipx_ifaddr *)ia)->ia_addr.sipx_addr.x_host, 21125653Sjhay sizeof(edst)) ) 21225653Sjhay return (looutput(ifp, m, dst, rt)); 21325653Sjhay } 21425653Sjhay 21511819Sjulian /* If broadcasting on a simplex interface, loopback a copy */ 21611819Sjulian if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 21711819Sjulian mcopy = m_copy(m, 0, (int)M_COPYALL); 21811819Sjulian break; 21925653Sjhay } 22011819Sjulian#endif 22121830Sjoerg#ifdef NETATALK 22221830Sjoerg case AF_APPLETALK: { 22321830Sjoerg struct at_ifaddr *aa; 22421830Sjoerg if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) { 22521830Sjoerg#ifdef NETATALKDEBUG 22621830Sjoerg extern char *prsockaddr(struct sockaddr *); 22721830Sjoerg printf("aarpresolv: failed for %s\n", prsockaddr(dst)); 22821830Sjoerg#endif 22921830Sjoerg return (0); 23021830Sjoerg } 23121830Sjoerg /* 23221830Sjoerg * ifaddr is the first thing in at_ifaddr 23321830Sjoerg */ 23430834Sjulian if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0) 23521830Sjoerg goto bad; 23621830Sjoerg 23721830Sjoerg /* 23821830Sjoerg * In the phase 2 case, we need to prepend an mbuf for the llc header. 23921830Sjoerg * Since we must preserve the value of m, which is passed to us by 24021830Sjoerg * value, we m_copy() the first mbuf, and use it for our llc header. 24121830Sjoerg */ 24221830Sjoerg if (aa->aa_flags & AFA_PHASE2) { 24321830Sjoerg struct llc llc; 24421830Sjoerg 24521830Sjoerg M_PREPEND(m, sizeof(struct llc), M_WAIT); 24621830Sjoerg if (m == 0) 24721830Sjoerg senderr(ENOBUFS); 24821830Sjoerg llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 24921830Sjoerg llc.llc_control = LLC_UI; 25021830Sjoerg bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code)); 25121830Sjoerg llc.llc_snap_ether_type = htons(ETHERTYPE_AT); 25221830Sjoerg bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); 25321830Sjoerg type = 0; 25421830Sjoerg } else { 25521830Sjoerg type = htons(ETHERTYPE_AT); 25621830Sjoerg } 25721830Sjoerg break; 25821830Sjoerg } 25921830Sjoerg#endif /* NETATALK */ 2607055Sdg#ifdef NS 2617055Sdg case AF_NS: 26221830Sjoerg type = htons(ETHERTYPE_NS); 2637055Sdg bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 2647055Sdg (caddr_t)edst, sizeof (edst)); 2657055Sdg if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))) 2667055Sdg return (looutput(ifp, m, dst, rt)); 2677055Sdg /* If broadcasting on a simplex interface, loopback a copy */ 2687055Sdg if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 2697055Sdg mcopy = m_copy(m, 0, (int)M_COPYALL); 2707055Sdg break; 2717055Sdg#endif 2727055Sdg#ifdef ISO 2737055Sdg case AF_ISO: { 2747055Sdg int snpalen; 2757055Sdg struct llc *l; 2767055Sdg register struct sockaddr_dl *sdl; 2777055Sdg 2787055Sdg if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) && 2797055Sdg sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) { 2807055Sdg bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst)); 2817055Sdg } else if (error = 2827055Sdg iso_snparesolve(ifp, (struct sockaddr_iso *)dst, 2837055Sdg (char *)edst, &snpalen)) 2847055Sdg goto bad; /* Not Resolved */ 2857055Sdg /* If broadcasting on a simplex interface, loopback a copy */ 2867055Sdg if (*edst & 1) 2877055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2887055Sdg if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && 2897055Sdg (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 2907055Sdg M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT); 2917055Sdg if (mcopy) { 2927055Sdg fh = mtod(mcopy, struct fddi_header *); 2937055Sdg bcopy((caddr_t)edst, 2947055Sdg (caddr_t)fh->fddi_dhost, sizeof (edst)); 2957055Sdg bcopy((caddr_t)ac->ac_enaddr, 2967055Sdg (caddr_t)fh->fddi_shost, sizeof (edst)); 2977055Sdg } 2987055Sdg } 2997055Sdg M_PREPEND(m, 3, M_DONTWAIT); 3007055Sdg if (m == NULL) 3017055Sdg return (0); 3027055Sdg type = 0; 3037055Sdg l = mtod(m, struct llc *); 3047055Sdg l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; 3057055Sdg l->llc_control = LLC_UI; 3067055Sdg IFDEBUG(D_ETHER) 3077055Sdg int i; 3087055Sdg printf("unoutput: sending pkt to: "); 3097055Sdg for (i=0; i<6; i++) 3107055Sdg printf("%x ", edst[i] & 0xff); 3117055Sdg printf("\n"); 3127055Sdg ENDDEBUG 3137055Sdg } break; 3147055Sdg#endif /* ISO */ 3157055Sdg#ifdef LLC 3167055Sdg/* case AF_NSAP: */ 3177055Sdg case AF_CCITT: { 31821830Sjoerg register struct sockaddr_dl *sdl = 3197055Sdg (struct sockaddr_dl *) rt -> rt_gateway; 3207055Sdg 32121830Sjoerg if (sdl && sdl->sdl_family != AF_LINK && sdl->sdl_alen <= 0) 32221830Sjoerg goto bad; /* Not a link interface ? Funny ... */ 32321830Sjoerg bcopy(LLADDR(sdl), (char *)edst, sizeof(edst)); 3247055Sdg if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) && 3257055Sdg (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 3267055Sdg M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT); 3277055Sdg if (mcopy) { 3287055Sdg fh = mtod(mcopy, struct fddi_header *); 3297055Sdg bcopy((caddr_t)edst, 3307055Sdg (caddr_t)fh->fddi_dhost, sizeof (edst)); 3317055Sdg bcopy((caddr_t)ac->ac_enaddr, 3327055Sdg (caddr_t)fh->fddi_shost, sizeof (edst)); 3337055Sdg fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 3347055Sdg } 3357055Sdg } 3367055Sdg type = 0; 3377055Sdg#ifdef LLC_DEBUG 3387055Sdg { 3397055Sdg int i; 3407055Sdg register struct llc *l = mtod(m, struct llc *); 3417055Sdg 3427055Sdg printf("fddi_output: sending LLC2 pkt to: "); 3437055Sdg for (i=0; i<6; i++) 3447055Sdg printf("%x ", edst[i] & 0xff); 34521830Sjoerg printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n", 3467055Sdg type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff, 3477055Sdg l->llc_control & 0xff); 3487055Sdg 3497055Sdg } 3507055Sdg#endif /* LLC_DEBUG */ 3517055Sdg } break; 35221830Sjoerg#endif /* LLC */ 3537055Sdg 3547055Sdg case AF_UNSPEC: 3557055Sdg { 3567055Sdg struct ether_header *eh; 3577055Sdg eh = (struct ether_header *)dst->sa_data; 3588384Sdg (void)memcpy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); 3597055Sdg if (*edst & 1) 3607055Sdg m->m_flags |= (M_BCAST|M_MCAST); 3617055Sdg type = eh->ether_type; 3627055Sdg break; 3637055Sdg } 3647055Sdg 3657055Sdg#if NBPFILTER > 0 3667055Sdg case AF_IMPLINK: 3677055Sdg { 3687055Sdg fh = mtod(m, struct fddi_header *); 3697055Sdg error = EPROTONOSUPPORT; 3707055Sdg switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 3717055Sdg case FDDIFC_LLC_ASYNC: { 3727055Sdg /* legal priorities are 0 through 7 */ 3737055Sdg if ((fh->fddi_fc & FDDIFC_Z) > 7) 3747055Sdg goto bad; 3757055Sdg break; 3767055Sdg } 3777055Sdg case FDDIFC_LLC_SYNC: { 3787055Sdg /* FDDIFC_Z bits reserved, must be zero */ 3797055Sdg if (fh->fddi_fc & FDDIFC_Z) 3807055Sdg goto bad; 3817055Sdg break; 3827055Sdg } 3837055Sdg case FDDIFC_SMT: { 3847055Sdg /* FDDIFC_Z bits must be non zero */ 3857055Sdg if ((fh->fddi_fc & FDDIFC_Z) == 0) 3867055Sdg goto bad; 3877055Sdg break; 3887055Sdg } 3897055Sdg default: { 3907055Sdg /* anything else is too dangerous */ 3917055Sdg goto bad; 3927055Sdg } 3937055Sdg } 3947055Sdg error = 0; 3957055Sdg if (fh->fddi_dhost[0] & 1) 3967055Sdg m->m_flags |= (M_BCAST|M_MCAST); 3977055Sdg goto queue_it; 3987055Sdg } 3997055Sdg#endif 4007055Sdg default: 4017055Sdg printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 4027055Sdg dst->sa_family); 4037055Sdg senderr(EAFNOSUPPORT); 4047055Sdg } 4057055Sdg 4067055Sdg 4077055Sdg if (mcopy) 4087055Sdg (void) looutput(ifp, mcopy, dst, rt); 4097055Sdg if (type != 0) { 4107055Sdg register struct llc *l; 4117055Sdg M_PREPEND(m, sizeof (struct llc), M_DONTWAIT); 4127055Sdg if (m == 0) 4137055Sdg senderr(ENOBUFS); 4147055Sdg l = mtod(m, struct llc *); 4157055Sdg l->llc_control = LLC_UI; 4167055Sdg l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 4177055Sdg l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0; 4188384Sdg (void)memcpy((caddr_t) &l->llc_snap.ether_type, (caddr_t) &type, 41921830Sjoerg sizeof(u_int16_t)); 4207055Sdg } 4217055Sdg /* 4227055Sdg * Add local net header. If no space in first mbuf, 4237055Sdg * allocate another. 4247055Sdg */ 4257055Sdg M_PREPEND(m, sizeof (struct fddi_header), M_DONTWAIT); 4267055Sdg if (m == 0) 4277055Sdg senderr(ENOBUFS); 4287055Sdg fh = mtod(m, struct fddi_header *); 4297055Sdg fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 4308384Sdg (void)memcpy((caddr_t)fh->fddi_dhost, (caddr_t)edst, sizeof (edst)); 4317055Sdg queue_it: 4328384Sdg (void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)ac->ac_enaddr, 4337055Sdg sizeof(fh->fddi_shost)); 4347055Sdg s = splimp(); 4357055Sdg /* 4367055Sdg * Queue message on interface, and start output if interface 4377055Sdg * not yet active. 4387055Sdg */ 4397055Sdg if (IF_QFULL(&ifp->if_snd)) { 4407055Sdg IF_DROP(&ifp->if_snd); 4417055Sdg splx(s); 4427055Sdg senderr(ENOBUFS); 4437055Sdg } 4447055Sdg ifp->if_obytes += m->m_pkthdr.len; 4457055Sdg IF_ENQUEUE(&ifp->if_snd, m); 4467055Sdg if ((ifp->if_flags & IFF_OACTIVE) == 0) 4477055Sdg (*ifp->if_start)(ifp); 4487055Sdg splx(s); 4497055Sdg if (m->m_flags & M_MCAST) 4507055Sdg ifp->if_omcasts++; 4517055Sdg return (error); 4527055Sdg 4537055Sdgbad: 4547055Sdg if (m) 4557055Sdg m_freem(m); 4567055Sdg return (error); 4577055Sdg} 4587055Sdg 4597055Sdg/* 4607055Sdg * Process a received FDDI packet; 4617055Sdg * the packet is in the mbuf chain m without 4627055Sdg * the fddi header, which is provided separately. 4637055Sdg */ 4647055Sdgvoid 4657055Sdgfddi_input(ifp, fh, m) 4667055Sdg struct ifnet *ifp; 4677055Sdg register struct fddi_header *fh; 4687055Sdg struct mbuf *m; 4697055Sdg{ 4707055Sdg register struct ifqueue *inq; 4717055Sdg register struct llc *l; 4727055Sdg int s; 4737055Sdg 4747055Sdg if ((ifp->if_flags & IFF_UP) == 0) { 4757055Sdg m_freem(m); 4767055Sdg return; 4777055Sdg } 47831264Sbde gettime(&ifp->if_lastchange); 4797055Sdg ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh); 48021830Sjoerg if (fh->fddi_dhost[0] & 1) { 48121830Sjoerg if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost, 48221830Sjoerg sizeof(fddibroadcastaddr)) == 0) 48321830Sjoerg m->m_flags |= M_BCAST; 48421830Sjoerg else 48521830Sjoerg m->m_flags |= M_MCAST; 4867055Sdg ifp->if_imcasts++; 48723910Sjoerg } else if ((ifp->if_flags & IFF_PROMISC) 48823910Sjoerg && bcmp(((struct arpcom *)ifp)->ac_enaddr, (caddr_t)fh->fddi_dhost, 48923910Sjoerg sizeof(fh->fddi_dhost)) != 0) { 49023910Sjoerg m_freem(m); 49123910Sjoerg return; 49221830Sjoerg } 4937055Sdg 49421830Sjoerg#ifdef M_LINK0 49521830Sjoerg /* 49621830Sjoerg * If this has a LLC priority of 0, then mark it so upper 49721830Sjoerg * layers have a hint that it really came via a FDDI/Ethernet 49821830Sjoerg * bridge. 49921830Sjoerg */ 50021830Sjoerg if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 50121830Sjoerg m->m_flags |= M_LINK0; 50221830Sjoerg#endif 50321830Sjoerg 5047055Sdg l = mtod(m, struct llc *); 5057055Sdg switch (l->llc_dsap) { 50621830Sjoerg#if defined(INET) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK) 5077055Sdg case LLC_SNAP_LSAP: 5087055Sdg { 50921830Sjoerg u_int16_t type; 5107055Sdg if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP) 5117055Sdg goto dropanyway; 51221830Sjoerg#ifdef NETATALK 51321830Sjoerg if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code, 51421830Sjoerg sizeof(at_org_code)) == 0 && 51521830Sjoerg ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { 51621830Sjoerg inq = &atintrq2; 51721830Sjoerg m_adj( m, sizeof( struct llc )); 51821830Sjoerg schednetisr(NETISR_ATALK); 51921830Sjoerg break; 52021830Sjoerg } 52121830Sjoerg 52221830Sjoerg if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, 52321830Sjoerg sizeof(aarp_org_code)) == 0 && 52421830Sjoerg ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { 52521830Sjoerg m_adj( m, sizeof( struct llc )); 52621830Sjoerg aarpinput((struct arpcom *)ifp, m); /* XXX */ 52721830Sjoerg return; 52821830Sjoerg } 52921830Sjoerg#endif /* NETATALK */ 5307055Sdg if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0) 5317055Sdg goto dropanyway; 53221830Sjoerg type = ntohs(l->llc_snap.ether_type); 5337055Sdg m_adj(m, 8); 53421830Sjoerg switch (type) { 5357055Sdg#ifdef INET 5367055Sdg case ETHERTYPE_IP: 5377055Sdg schednetisr(NETISR_IP); 5387055Sdg inq = &ipintrq; 5397055Sdg break; 5407055Sdg 5417055Sdg case ETHERTYPE_ARP: 54221830Sjoerg#if !defined(__bsdi__) || _BSDI_VERSION >= 199401 5437055Sdg schednetisr(NETISR_ARP); 5447055Sdg inq = &arpintrq; 5457055Sdg break; 54621830Sjoerg#else 54721830Sjoerg arpinput((struct arpcom *)ifp, m); 54821830Sjoerg return; 5497055Sdg#endif 55021830Sjoerg#endif 55121830Sjoerg#ifdef IPX 55221830Sjoerg case ETHERTYPE_IPX: 55321830Sjoerg schednetisr(NETISR_IPX); 55421830Sjoerg inq = &ipxintrq; 55521830Sjoerg break; 55621830Sjoerg#endif 5577055Sdg#ifdef NS 5587055Sdg case ETHERTYPE_NS: 5597055Sdg schednetisr(NETISR_NS); 5607055Sdg inq = &nsintrq; 5617055Sdg break; 5627055Sdg#endif 5637055Sdg#ifdef DECNET 56421830Sjoerg case ETHERTYPE_DECNET: 5657055Sdg schednetisr(NETISR_DECNET); 5667055Sdg inq = &decnetintrq; 5677055Sdg break; 5687055Sdg#endif 56921830Sjoerg#ifdef NETATALK 57021830Sjoerg case ETHERTYPE_AT: 57121830Sjoerg schednetisr(NETISR_ATALK); 57221830Sjoerg inq = &atintrq1; 57321830Sjoerg break; 57421830Sjoerg case ETHERTYPE_AARP: 57521830Sjoerg /* probably this should be done with a NETISR as well */ 57621830Sjoerg aarpinput((struct arpcom *)ifp, m); /* XXX */ 57721830Sjoerg return; 57821830Sjoerg#endif /* NETATALK */ 5797055Sdg default: 58021830Sjoerg /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 5817055Sdg ifp->if_noproto++; 5827055Sdg goto dropanyway; 5837055Sdg } 5847055Sdg break; 5857055Sdg } 5867055Sdg#endif /* INET || NS */ 5877055Sdg#ifdef ISO 58821830Sjoerg case LLC_ISO_LSAP: 5897055Sdg switch (l->llc_control) { 5907055Sdg case LLC_UI: 5917055Sdg /* LLC_UI_P forbidden in class 1 service */ 5927055Sdg if ((l->llc_dsap == LLC_ISO_LSAP) && 5937055Sdg (l->llc_ssap == LLC_ISO_LSAP)) { 5947055Sdg /* LSAP for ISO */ 5957055Sdg m->m_data += 3; /* XXX */ 5967055Sdg m->m_len -= 3; /* XXX */ 5977055Sdg m->m_pkthdr.len -= 3; /* XXX */ 5987055Sdg M_PREPEND(m, sizeof *fh, M_DONTWAIT); 5997055Sdg if (m == 0) 6007055Sdg return; 6017055Sdg *mtod(m, struct fddi_header *) = *fh; 6027055Sdg IFDEBUG(D_ETHER) 6037055Sdg printf("clnp packet"); 6047055Sdg ENDDEBUG 6057055Sdg schednetisr(NETISR_ISO); 6067055Sdg inq = &clnlintrq; 6077055Sdg break; 6087055Sdg } 6097055Sdg goto dropanyway; 61021830Sjoerg 6117055Sdg case LLC_XID: 6127055Sdg case LLC_XID_P: 6137055Sdg if(m->m_len < 6) 6147055Sdg goto dropanyway; 6157055Sdg l->llc_window = 0; 6167055Sdg l->llc_fid = 9; 6177055Sdg l->llc_class = 1; 6187055Sdg l->llc_dsap = l->llc_ssap = 0; 6197055Sdg /* Fall through to */ 6207055Sdg case LLC_TEST: 6217055Sdg case LLC_TEST_P: 6227055Sdg { 6237055Sdg struct sockaddr sa; 62421830Sjoerg register struct ether_header *eh; 62521830Sjoerg struct arpcom *ac = (struct arpcom *) ifp; 6267055Sdg int i; 6277055Sdg u_char c = l->llc_dsap; 6287055Sdg 6297055Sdg l->llc_dsap = l->llc_ssap; 6307055Sdg l->llc_ssap = c; 6317055Sdg if (m->m_flags & (M_BCAST | M_MCAST)) 6327055Sdg bcopy((caddr_t)ac->ac_enaddr, 6337055Sdg (caddr_t)eh->ether_dhost, 6); 6347055Sdg sa.sa_family = AF_UNSPEC; 6357055Sdg sa.sa_len = sizeof(sa); 63621830Sjoerg eh = (struct ether_header *)sa.sa_data; 6377055Sdg for (i = 0; i < 6; i++) { 63821830Sjoerg eh->ether_shost[i] = fh->fddi_dhost[i]; 63921830Sjoerg eh->ether_dhost[i] = fh->fddi_shost[i]; 6407055Sdg } 64121830Sjoerg eh->ether_type = 0; 6427055Sdg ifp->if_output(ifp, m, &sa, NULL); 6437055Sdg return; 6447055Sdg } 6457055Sdg default: 6467055Sdg m_freem(m); 6477055Sdg return; 6487055Sdg } 6497055Sdg break; 6507055Sdg#endif /* ISO */ 6517055Sdg#ifdef LLC 6527055Sdg case LLC_X25_LSAP: 6537055Sdg { 6547055Sdg M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT); 6557055Sdg if (m == 0) 6567055Sdg return; 6577055Sdg if ( !sdl_sethdrif(ifp, fh->fddi_shost, LLC_X25_LSAP, 65821830Sjoerg fh->fddi_dhost, LLC_X25_LSAP, 6, 6597055Sdg mtod(m, struct sdl_hdr *))) 6607055Sdg panic("ETHER cons addr failure"); 6617055Sdg mtod(m, struct sdl_hdr *)->sdlhdr_len = m->m_pkthdr.len - sizeof(struct sdl_hdr); 6627055Sdg#ifdef LLC_DEBUG 6637055Sdg printf("llc packet\n"); 6647055Sdg#endif /* LLC_DEBUG */ 6657055Sdg schednetisr(NETISR_CCITT); 6667055Sdg inq = &llcintrq; 6677055Sdg break; 6687055Sdg } 6697055Sdg#endif /* LLC */ 67021830Sjoerg 6717055Sdg default: 67221830Sjoerg /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 6737055Sdg ifp->if_noproto++; 6747055Sdg dropanyway: 6757055Sdg m_freem(m); 6767055Sdg return; 6777055Sdg } 6787055Sdg 6797055Sdg s = splimp(); 6807055Sdg if (IF_QFULL(inq)) { 6817055Sdg IF_DROP(inq); 6827055Sdg m_freem(m); 6837055Sdg } else 6847055Sdg IF_ENQUEUE(inq, m); 6857055Sdg splx(s); 6867055Sdg} 6877055Sdg/* 6887055Sdg * Perform common duties while attaching to interface list 6897055Sdg */ 69021830Sjoerg#ifdef __NetBSD__ 69121830Sjoerg#define ifa_next ifa_list.tqe_next 69221830Sjoerg#endif 69321830Sjoerg 6947055Sdgvoid 6957055Sdgfddi_ifattach(ifp) 6967055Sdg register struct ifnet *ifp; 6977055Sdg{ 6987055Sdg register struct ifaddr *ifa; 6997055Sdg register struct sockaddr_dl *sdl; 7007055Sdg 7017055Sdg ifp->if_type = IFT_FDDI; 7027055Sdg ifp->if_addrlen = 6; 7037055Sdg ifp->if_hdrlen = 21; 7047055Sdg ifp->if_mtu = FDDIMTU; 70516063Sgpalmer ifp->if_baudrate = 100000000; 70621830Sjoerg#ifdef IFF_NOTRAILERS 70721830Sjoerg ifp->if_flags |= IFF_NOTRAILERS; 70821830Sjoerg#endif 70921831Sjoerg#if defined(__FreeBSD__) 71021831Sjoerg ifa = ifnet_addrs[ifp->if_index - 1]; 71121831Sjoerg sdl = (struct sockaddr_dl *)ifa->ifa_addr; 71221831Sjoerg sdl->sdl_type = IFT_FDDI; 71321831Sjoerg sdl->sdl_alen = ifp->if_addrlen; 71421831Sjoerg bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 71521831Sjoerg#elif defined(__NetBSD__) 71621830Sjoerg LIST_INIT(&((struct arpcom *)ifp)->ac_multiaddrs); 71721830Sjoerg for (ifa = ifp->if_addrlist.tqh_first; ifa != NULL; ifa = ifa->ifa_list.tqe_next) 71821830Sjoerg#else 71921830Sjoerg for (ifa = ifp->if_addrlist; ifa != NULL; ifa = ifa->ifa_next) 72021830Sjoerg#endif 72121831Sjoerg#if !defined(__FreeBSD__) 72221830Sjoerg if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 72321830Sjoerg sdl->sdl_family == AF_LINK) { 72421830Sjoerg sdl->sdl_type = IFT_FDDI; 72521830Sjoerg sdl->sdl_alen = ifp->if_addrlen; 72621830Sjoerg bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, 72721830Sjoerg LLADDR(sdl), ifp->if_addrlen); 72821830Sjoerg break; 72921830Sjoerg } 73021831Sjoerg#endif 7317055Sdg} 732