if_fddisubr.c revision 31264
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 3631264Sbde * $Id: if_fddisubr.c,v 1.21 1997/10/29 07:59:27 julian Exp $ 377055Sdg */ 387055Sdg 397055Sdg#include <sys/param.h> 407055Sdg#include <sys/systm.h> 417055Sdg#include <sys/kernel.h> 427055Sdg#include <sys/mbuf.h> 437055Sdg#include <sys/socket.h> 447055Sdg 457055Sdg#include <net/if.h> 467055Sdg#include <net/netisr.h> 477055Sdg#include <net/route.h> 487055Sdg#include <net/if_llc.h> 497055Sdg#include <net/if_dl.h> 507055Sdg#include <net/if_types.h> 517055Sdg 527055Sdg#ifdef INET 537055Sdg#include <netinet/in.h> 547055Sdg#include <netinet/in_var.h> 557055Sdg#endif 567055Sdg#include <netinet/if_ether.h> 5721830Sjoerg#if defined(__FreeBSD__) 587055Sdg#include <netinet/if_fddi.h> 5921830Sjoerg#else 6021830Sjoerg#include <net/if_fddi.h> 6121830Sjoerg#endif 627055Sdg 6311819Sjulian#ifdef IPX 6421830Sjoerg#include <netipx/ipx.h> 6511819Sjulian#include <netipx/ipx_if.h> 6611819Sjulian#endif 6711819Sjulian 687055Sdg#ifdef NS 697055Sdg#include <netns/ns.h> 707055Sdg#include <netns/ns_if.h> 717055Sdg#endif 727055Sdg 737055Sdg#ifdef DECNET 747055Sdg#include <netdnet/dn.h> 757055Sdg#endif 767055Sdg 777055Sdg#ifdef ISO 787055Sdg#include <netiso/argo_debug.h> 797055Sdg#include <netiso/iso.h> 807055Sdg#include <netiso/iso_var.h> 817055Sdg#include <netiso/iso_snpac.h> 827055Sdg#endif 837055Sdg 847055Sdg#ifdef LLC 857055Sdg#include <netccitt/dll.h> 867055Sdg#include <netccitt/llc_var.h> 877055Sdg#endif 887055Sdg 8921830Sjoerg#ifdef NETATALK 9021830Sjoerg#include <netatalk/at.h> 9121830Sjoerg#include <netatalk/at_var.h> 9221830Sjoerg#include <netatalk/at_extern.h> 9321830Sjoerg 9421830Sjoerg#define llc_snap_org_code llc_un.type_snap.org_code 9521830Sjoerg#define llc_snap_ether_type llc_un.type_snap.ether_type 9621830Sjoerg 9721830Sjoergextern u_char at_org_code[ 3 ]; 9821830Sjoergextern u_char aarp_org_code[ 3 ]; 9921830Sjoerg#endif /* NETATALK */ 10021830Sjoerg 1017055Sdg#if defined(LLC) && defined(CCITT) 1027055Sdgextern struct ifqueue pkintrq; 1037055Sdg#endif 1047055Sdg 10521830Sjoerg#include "bpfilter.h" 10621830Sjoerg 1077055Sdg#define senderr(e) { error = (e); goto bad;} 1087055Sdg 1097055Sdg/* 1107055Sdg * This really should be defined in if_llc.h but in case it isn't. 1117055Sdg */ 1127055Sdg#ifndef llc_snap 1137055Sdg#define llc_snap llc_un.type_snap 1147055Sdg#endif 1157055Sdg 11621830Sjoerg#if defined(__bsdi__) || defined(__NetBSD__) 11721830Sjoerg#define RTALLOC1(a, b) rtalloc1(a, b) 1187055Sdg#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e) 11921830Sjoerg#elif defined(__FreeBSD__) 12021830Sjoerg#define RTALLOC1(a, b) rtalloc1(a, b, 0UL) 1217055Sdg#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e, f) 1227055Sdg#endif 1237055Sdg/* 1247055Sdg * FDDI output routine. 1257055Sdg * Encapsulate a packet of type family for the local net. 1267055Sdg * Use trailer local net encapsulation if enough data in first 1277055Sdg * packet leaves a multiple of 512 bytes of data in remainder. 1287055Sdg * Assumes that ifp is actually pointer to arpcom structure. 1297055Sdg */ 1307055Sdgint 1317055Sdgfddi_output(ifp, m0, dst, rt0) 1327055Sdg register struct ifnet *ifp; 1337055Sdg struct mbuf *m0; 1347055Sdg struct sockaddr *dst; 1357055Sdg struct rtentry *rt0; 1367055Sdg{ 13721830Sjoerg u_int16_t type; 1387055Sdg int s, error = 0; 1397055Sdg u_char edst[6]; 1407055Sdg register struct mbuf *m = m0; 1417055Sdg register struct rtentry *rt; 14221830Sjoerg register struct fddi_header *fh; 1437055Sdg struct mbuf *mcopy = (struct mbuf *)0; 1447055Sdg struct arpcom *ac = (struct arpcom *)ifp; 1457055Sdg 1467055Sdg if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 1477055Sdg senderr(ENETDOWN); 14831264Sbde gettime(&ifp->if_lastchange); 14921830Sjoerg#if !defined(__bsdi__) || _BSDI_VERSION >= 199401 1507055Sdg if (rt = rt0) { 1517055Sdg if ((rt->rt_flags & RTF_UP) == 0) { 1527055Sdg if (rt0 = rt = RTALLOC1(dst, 1)) 1537055Sdg rt->rt_refcnt--; 15421830Sjoerg else 1557055Sdg senderr(EHOSTUNREACH); 1567055Sdg } 1577055Sdg if (rt->rt_flags & RTF_GATEWAY) { 1587055Sdg if (rt->rt_gwroute == 0) 1597055Sdg goto lookup; 1607055Sdg if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 1617055Sdg rtfree(rt); rt = rt0; 1627055Sdg lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 1); 1637055Sdg if ((rt = rt->rt_gwroute) == 0) 1647055Sdg senderr(EHOSTUNREACH); 1657055Sdg } 1667055Sdg } 1677055Sdg if (rt->rt_flags & RTF_REJECT) 1687055Sdg if (rt->rt_rmx.rmx_expire == 0 || 1697055Sdg time.tv_sec < rt->rt_rmx.rmx_expire) 1707055Sdg senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 1717055Sdg } 17221830Sjoerg#endif 1737055Sdg switch (dst->sa_family) { 1747055Sdg 1757055Sdg#ifdef INET 17621830Sjoerg case AF_INET: { 17721830Sjoerg#if !defined(__bsdi__) || _BSDI_VERSION >= 199401 1787055Sdg if (!ARPRESOLVE(ac, rt, m, dst, edst, rt0)) 1797055Sdg return (0); /* if not yet resolved */ 18021830Sjoerg#else 18121830Sjoerg int usetrailers; 18221830Sjoerg if (!arpresolve(ac, m, &((struct sockaddr_in *)dst)->sin_addr, edst, &usetrailers)) 18321830Sjoerg return (0); /* if not yet resolved */ 18421830Sjoerg#endif 1857055Sdg /* If broadcasting on a simplex interface, loopback a copy */ 1867055Sdg if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 1877055Sdg mcopy = m_copy(m, 0, (int)M_COPYALL); 18821830Sjoerg type = htons(ETHERTYPE_IP); 1897055Sdg break; 19021830Sjoerg } 1917055Sdg#endif 19211819Sjulian#ifdef IPX 19311819Sjulian case AF_IPX: 19425653Sjhay { 19525653Sjhay struct ifaddr *ia; 19625653Sjhay 19721830Sjoerg type = htons(ETHERTYPE_IPX); 19811819Sjulian bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 19911819Sjulian (caddr_t)edst, sizeof (edst)); 20025653Sjhay 20125653Sjhay for(ia = ifp->if_addrhead.tqh_first; ia != 0; 20225653Sjhay ia = ia->ifa_link.tqe_next) { 20325653Sjhay if(ia->ifa_addr->sa_family == AF_IPX && 20425653Sjhay !bcmp((caddr_t)edst, 20525653Sjhay (caddr_t)&((struct ipx_ifaddr *)ia)->ia_addr.sipx_addr.x_host, 20625653Sjhay sizeof(edst)) ) 20725653Sjhay return (looutput(ifp, m, dst, rt)); 20825653Sjhay } 20925653Sjhay 21011819Sjulian /* If broadcasting on a simplex interface, loopback a copy */ 21111819Sjulian if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 21211819Sjulian mcopy = m_copy(m, 0, (int)M_COPYALL); 21311819Sjulian break; 21425653Sjhay } 21511819Sjulian#endif 21621830Sjoerg#ifdef NETATALK 21721830Sjoerg case AF_APPLETALK: { 21821830Sjoerg struct at_ifaddr *aa; 21921830Sjoerg if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) { 22021830Sjoerg#ifdef NETATALKDEBUG 22121830Sjoerg extern char *prsockaddr(struct sockaddr *); 22221830Sjoerg printf("aarpresolv: failed for %s\n", prsockaddr(dst)); 22321830Sjoerg#endif 22421830Sjoerg return (0); 22521830Sjoerg } 22621830Sjoerg /* 22721830Sjoerg * ifaddr is the first thing in at_ifaddr 22821830Sjoerg */ 22930834Sjulian if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0) 23021830Sjoerg goto bad; 23121830Sjoerg 23221830Sjoerg /* 23321830Sjoerg * In the phase 2 case, we need to prepend an mbuf for the llc header. 23421830Sjoerg * Since we must preserve the value of m, which is passed to us by 23521830Sjoerg * value, we m_copy() the first mbuf, and use it for our llc header. 23621830Sjoerg */ 23721830Sjoerg if (aa->aa_flags & AFA_PHASE2) { 23821830Sjoerg struct llc llc; 23921830Sjoerg 24021830Sjoerg M_PREPEND(m, sizeof(struct llc), M_WAIT); 24121830Sjoerg if (m == 0) 24221830Sjoerg senderr(ENOBUFS); 24321830Sjoerg llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 24421830Sjoerg llc.llc_control = LLC_UI; 24521830Sjoerg bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code)); 24621830Sjoerg llc.llc_snap_ether_type = htons(ETHERTYPE_AT); 24721830Sjoerg bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); 24821830Sjoerg type = 0; 24921830Sjoerg } else { 25021830Sjoerg type = htons(ETHERTYPE_AT); 25121830Sjoerg } 25221830Sjoerg break; 25321830Sjoerg } 25421830Sjoerg#endif /* NETATALK */ 2557055Sdg#ifdef NS 2567055Sdg case AF_NS: 25721830Sjoerg type = htons(ETHERTYPE_NS); 2587055Sdg bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 2597055Sdg (caddr_t)edst, sizeof (edst)); 2607055Sdg if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))) 2617055Sdg return (looutput(ifp, m, dst, rt)); 2627055Sdg /* If broadcasting on a simplex interface, loopback a copy */ 2637055Sdg if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 2647055Sdg mcopy = m_copy(m, 0, (int)M_COPYALL); 2657055Sdg break; 2667055Sdg#endif 2677055Sdg#ifdef ISO 2687055Sdg case AF_ISO: { 2697055Sdg int snpalen; 2707055Sdg struct llc *l; 2717055Sdg register struct sockaddr_dl *sdl; 2727055Sdg 2737055Sdg if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) && 2747055Sdg sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) { 2757055Sdg bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst)); 2767055Sdg } else if (error = 2777055Sdg iso_snparesolve(ifp, (struct sockaddr_iso *)dst, 2787055Sdg (char *)edst, &snpalen)) 2797055Sdg goto bad; /* Not Resolved */ 2807055Sdg /* If broadcasting on a simplex interface, loopback a copy */ 2817055Sdg if (*edst & 1) 2827055Sdg m->m_flags |= (M_BCAST|M_MCAST); 2837055Sdg if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && 2847055Sdg (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 2857055Sdg M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT); 2867055Sdg if (mcopy) { 2877055Sdg fh = mtod(mcopy, struct fddi_header *); 2887055Sdg bcopy((caddr_t)edst, 2897055Sdg (caddr_t)fh->fddi_dhost, sizeof (edst)); 2907055Sdg bcopy((caddr_t)ac->ac_enaddr, 2917055Sdg (caddr_t)fh->fddi_shost, sizeof (edst)); 2927055Sdg } 2937055Sdg } 2947055Sdg M_PREPEND(m, 3, M_DONTWAIT); 2957055Sdg if (m == NULL) 2967055Sdg return (0); 2977055Sdg type = 0; 2987055Sdg l = mtod(m, struct llc *); 2997055Sdg l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; 3007055Sdg l->llc_control = LLC_UI; 3017055Sdg IFDEBUG(D_ETHER) 3027055Sdg int i; 3037055Sdg printf("unoutput: sending pkt to: "); 3047055Sdg for (i=0; i<6; i++) 3057055Sdg printf("%x ", edst[i] & 0xff); 3067055Sdg printf("\n"); 3077055Sdg ENDDEBUG 3087055Sdg } break; 3097055Sdg#endif /* ISO */ 3107055Sdg#ifdef LLC 3117055Sdg/* case AF_NSAP: */ 3127055Sdg case AF_CCITT: { 31321830Sjoerg register struct sockaddr_dl *sdl = 3147055Sdg (struct sockaddr_dl *) rt -> rt_gateway; 3157055Sdg 31621830Sjoerg if (sdl && sdl->sdl_family != AF_LINK && sdl->sdl_alen <= 0) 31721830Sjoerg goto bad; /* Not a link interface ? Funny ... */ 31821830Sjoerg bcopy(LLADDR(sdl), (char *)edst, sizeof(edst)); 3197055Sdg if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) && 3207055Sdg (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 3217055Sdg M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT); 3227055Sdg if (mcopy) { 3237055Sdg fh = mtod(mcopy, struct fddi_header *); 3247055Sdg bcopy((caddr_t)edst, 3257055Sdg (caddr_t)fh->fddi_dhost, sizeof (edst)); 3267055Sdg bcopy((caddr_t)ac->ac_enaddr, 3277055Sdg (caddr_t)fh->fddi_shost, sizeof (edst)); 3287055Sdg fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 3297055Sdg } 3307055Sdg } 3317055Sdg type = 0; 3327055Sdg#ifdef LLC_DEBUG 3337055Sdg { 3347055Sdg int i; 3357055Sdg register struct llc *l = mtod(m, struct llc *); 3367055Sdg 3377055Sdg printf("fddi_output: sending LLC2 pkt to: "); 3387055Sdg for (i=0; i<6; i++) 3397055Sdg printf("%x ", edst[i] & 0xff); 34021830Sjoerg printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n", 3417055Sdg type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff, 3427055Sdg l->llc_control & 0xff); 3437055Sdg 3447055Sdg } 3457055Sdg#endif /* LLC_DEBUG */ 3467055Sdg } break; 34721830Sjoerg#endif /* LLC */ 3487055Sdg 3497055Sdg case AF_UNSPEC: 3507055Sdg { 3517055Sdg struct ether_header *eh; 3527055Sdg eh = (struct ether_header *)dst->sa_data; 3538384Sdg (void)memcpy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); 3547055Sdg if (*edst & 1) 3557055Sdg m->m_flags |= (M_BCAST|M_MCAST); 3567055Sdg type = eh->ether_type; 3577055Sdg break; 3587055Sdg } 3597055Sdg 3607055Sdg#if NBPFILTER > 0 3617055Sdg case AF_IMPLINK: 3627055Sdg { 3637055Sdg fh = mtod(m, struct fddi_header *); 3647055Sdg error = EPROTONOSUPPORT; 3657055Sdg switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 3667055Sdg case FDDIFC_LLC_ASYNC: { 3677055Sdg /* legal priorities are 0 through 7 */ 3687055Sdg if ((fh->fddi_fc & FDDIFC_Z) > 7) 3697055Sdg goto bad; 3707055Sdg break; 3717055Sdg } 3727055Sdg case FDDIFC_LLC_SYNC: { 3737055Sdg /* FDDIFC_Z bits reserved, must be zero */ 3747055Sdg if (fh->fddi_fc & FDDIFC_Z) 3757055Sdg goto bad; 3767055Sdg break; 3777055Sdg } 3787055Sdg case FDDIFC_SMT: { 3797055Sdg /* FDDIFC_Z bits must be non zero */ 3807055Sdg if ((fh->fddi_fc & FDDIFC_Z) == 0) 3817055Sdg goto bad; 3827055Sdg break; 3837055Sdg } 3847055Sdg default: { 3857055Sdg /* anything else is too dangerous */ 3867055Sdg goto bad; 3877055Sdg } 3887055Sdg } 3897055Sdg error = 0; 3907055Sdg if (fh->fddi_dhost[0] & 1) 3917055Sdg m->m_flags |= (M_BCAST|M_MCAST); 3927055Sdg goto queue_it; 3937055Sdg } 3947055Sdg#endif 3957055Sdg default: 3967055Sdg printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 3977055Sdg dst->sa_family); 3987055Sdg senderr(EAFNOSUPPORT); 3997055Sdg } 4007055Sdg 4017055Sdg 4027055Sdg if (mcopy) 4037055Sdg (void) looutput(ifp, mcopy, dst, rt); 4047055Sdg if (type != 0) { 4057055Sdg register struct llc *l; 4067055Sdg M_PREPEND(m, sizeof (struct llc), M_DONTWAIT); 4077055Sdg if (m == 0) 4087055Sdg senderr(ENOBUFS); 4097055Sdg l = mtod(m, struct llc *); 4107055Sdg l->llc_control = LLC_UI; 4117055Sdg l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 4127055Sdg l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0; 4138384Sdg (void)memcpy((caddr_t) &l->llc_snap.ether_type, (caddr_t) &type, 41421830Sjoerg sizeof(u_int16_t)); 4157055Sdg } 4167055Sdg /* 4177055Sdg * Add local net header. If no space in first mbuf, 4187055Sdg * allocate another. 4197055Sdg */ 4207055Sdg M_PREPEND(m, sizeof (struct fddi_header), M_DONTWAIT); 4217055Sdg if (m == 0) 4227055Sdg senderr(ENOBUFS); 4237055Sdg fh = mtod(m, struct fddi_header *); 4247055Sdg fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 4258384Sdg (void)memcpy((caddr_t)fh->fddi_dhost, (caddr_t)edst, sizeof (edst)); 4267055Sdg queue_it: 4278384Sdg (void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)ac->ac_enaddr, 4287055Sdg sizeof(fh->fddi_shost)); 4297055Sdg s = splimp(); 4307055Sdg /* 4317055Sdg * Queue message on interface, and start output if interface 4327055Sdg * not yet active. 4337055Sdg */ 4347055Sdg if (IF_QFULL(&ifp->if_snd)) { 4357055Sdg IF_DROP(&ifp->if_snd); 4367055Sdg splx(s); 4377055Sdg senderr(ENOBUFS); 4387055Sdg } 4397055Sdg ifp->if_obytes += m->m_pkthdr.len; 4407055Sdg IF_ENQUEUE(&ifp->if_snd, m); 4417055Sdg if ((ifp->if_flags & IFF_OACTIVE) == 0) 4427055Sdg (*ifp->if_start)(ifp); 4437055Sdg splx(s); 4447055Sdg if (m->m_flags & M_MCAST) 4457055Sdg ifp->if_omcasts++; 4467055Sdg return (error); 4477055Sdg 4487055Sdgbad: 4497055Sdg if (m) 4507055Sdg m_freem(m); 4517055Sdg return (error); 4527055Sdg} 4537055Sdg 4547055Sdg/* 4557055Sdg * Process a received FDDI packet; 4567055Sdg * the packet is in the mbuf chain m without 4577055Sdg * the fddi header, which is provided separately. 4587055Sdg */ 4597055Sdgvoid 4607055Sdgfddi_input(ifp, fh, m) 4617055Sdg struct ifnet *ifp; 4627055Sdg register struct fddi_header *fh; 4637055Sdg struct mbuf *m; 4647055Sdg{ 4657055Sdg register struct ifqueue *inq; 4667055Sdg register struct llc *l; 4677055Sdg int s; 4687055Sdg 4697055Sdg if ((ifp->if_flags & IFF_UP) == 0) { 4707055Sdg m_freem(m); 4717055Sdg return; 4727055Sdg } 47331264Sbde gettime(&ifp->if_lastchange); 4747055Sdg ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh); 47521830Sjoerg if (fh->fddi_dhost[0] & 1) { 47621830Sjoerg if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost, 47721830Sjoerg sizeof(fddibroadcastaddr)) == 0) 47821830Sjoerg m->m_flags |= M_BCAST; 47921830Sjoerg else 48021830Sjoerg m->m_flags |= M_MCAST; 4817055Sdg ifp->if_imcasts++; 48223910Sjoerg } else if ((ifp->if_flags & IFF_PROMISC) 48323910Sjoerg && bcmp(((struct arpcom *)ifp)->ac_enaddr, (caddr_t)fh->fddi_dhost, 48423910Sjoerg sizeof(fh->fddi_dhost)) != 0) { 48523910Sjoerg m_freem(m); 48623910Sjoerg return; 48721830Sjoerg } 4887055Sdg 48921830Sjoerg#ifdef M_LINK0 49021830Sjoerg /* 49121830Sjoerg * If this has a LLC priority of 0, then mark it so upper 49221830Sjoerg * layers have a hint that it really came via a FDDI/Ethernet 49321830Sjoerg * bridge. 49421830Sjoerg */ 49521830Sjoerg if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 49621830Sjoerg m->m_flags |= M_LINK0; 49721830Sjoerg#endif 49821830Sjoerg 4997055Sdg l = mtod(m, struct llc *); 5007055Sdg switch (l->llc_dsap) { 50121830Sjoerg#if defined(INET) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK) 5027055Sdg case LLC_SNAP_LSAP: 5037055Sdg { 50421830Sjoerg u_int16_t type; 5057055Sdg if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP) 5067055Sdg goto dropanyway; 50721830Sjoerg#ifdef NETATALK 50821830Sjoerg if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code, 50921830Sjoerg sizeof(at_org_code)) == 0 && 51021830Sjoerg ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { 51121830Sjoerg inq = &atintrq2; 51221830Sjoerg m_adj( m, sizeof( struct llc )); 51321830Sjoerg schednetisr(NETISR_ATALK); 51421830Sjoerg break; 51521830Sjoerg } 51621830Sjoerg 51721830Sjoerg if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, 51821830Sjoerg sizeof(aarp_org_code)) == 0 && 51921830Sjoerg ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { 52021830Sjoerg m_adj( m, sizeof( struct llc )); 52121830Sjoerg aarpinput((struct arpcom *)ifp, m); /* XXX */ 52221830Sjoerg return; 52321830Sjoerg } 52421830Sjoerg#endif /* NETATALK */ 5257055Sdg if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0) 5267055Sdg goto dropanyway; 52721830Sjoerg type = ntohs(l->llc_snap.ether_type); 5287055Sdg m_adj(m, 8); 52921830Sjoerg switch (type) { 5307055Sdg#ifdef INET 5317055Sdg case ETHERTYPE_IP: 5327055Sdg schednetisr(NETISR_IP); 5337055Sdg inq = &ipintrq; 5347055Sdg break; 5357055Sdg 5367055Sdg case ETHERTYPE_ARP: 53721830Sjoerg#if !defined(__bsdi__) || _BSDI_VERSION >= 199401 5387055Sdg schednetisr(NETISR_ARP); 5397055Sdg inq = &arpintrq; 5407055Sdg break; 54121830Sjoerg#else 54221830Sjoerg arpinput((struct arpcom *)ifp, m); 54321830Sjoerg return; 5447055Sdg#endif 54521830Sjoerg#endif 54621830Sjoerg#ifdef IPX 54721830Sjoerg case ETHERTYPE_IPX: 54821830Sjoerg schednetisr(NETISR_IPX); 54921830Sjoerg inq = &ipxintrq; 55021830Sjoerg break; 55121830Sjoerg#endif 5527055Sdg#ifdef NS 5537055Sdg case ETHERTYPE_NS: 5547055Sdg schednetisr(NETISR_NS); 5557055Sdg inq = &nsintrq; 5567055Sdg break; 5577055Sdg#endif 5587055Sdg#ifdef DECNET 55921830Sjoerg case ETHERTYPE_DECNET: 5607055Sdg schednetisr(NETISR_DECNET); 5617055Sdg inq = &decnetintrq; 5627055Sdg break; 5637055Sdg#endif 56421830Sjoerg#ifdef NETATALK 56521830Sjoerg case ETHERTYPE_AT: 56621830Sjoerg schednetisr(NETISR_ATALK); 56721830Sjoerg inq = &atintrq1; 56821830Sjoerg break; 56921830Sjoerg case ETHERTYPE_AARP: 57021830Sjoerg /* probably this should be done with a NETISR as well */ 57121830Sjoerg aarpinput((struct arpcom *)ifp, m); /* XXX */ 57221830Sjoerg return; 57321830Sjoerg#endif /* NETATALK */ 5747055Sdg default: 57521830Sjoerg /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 5767055Sdg ifp->if_noproto++; 5777055Sdg goto dropanyway; 5787055Sdg } 5797055Sdg break; 5807055Sdg } 5817055Sdg#endif /* INET || NS */ 5827055Sdg#ifdef ISO 58321830Sjoerg case LLC_ISO_LSAP: 5847055Sdg switch (l->llc_control) { 5857055Sdg case LLC_UI: 5867055Sdg /* LLC_UI_P forbidden in class 1 service */ 5877055Sdg if ((l->llc_dsap == LLC_ISO_LSAP) && 5887055Sdg (l->llc_ssap == LLC_ISO_LSAP)) { 5897055Sdg /* LSAP for ISO */ 5907055Sdg m->m_data += 3; /* XXX */ 5917055Sdg m->m_len -= 3; /* XXX */ 5927055Sdg m->m_pkthdr.len -= 3; /* XXX */ 5937055Sdg M_PREPEND(m, sizeof *fh, M_DONTWAIT); 5947055Sdg if (m == 0) 5957055Sdg return; 5967055Sdg *mtod(m, struct fddi_header *) = *fh; 5977055Sdg IFDEBUG(D_ETHER) 5987055Sdg printf("clnp packet"); 5997055Sdg ENDDEBUG 6007055Sdg schednetisr(NETISR_ISO); 6017055Sdg inq = &clnlintrq; 6027055Sdg break; 6037055Sdg } 6047055Sdg goto dropanyway; 60521830Sjoerg 6067055Sdg case LLC_XID: 6077055Sdg case LLC_XID_P: 6087055Sdg if(m->m_len < 6) 6097055Sdg goto dropanyway; 6107055Sdg l->llc_window = 0; 6117055Sdg l->llc_fid = 9; 6127055Sdg l->llc_class = 1; 6137055Sdg l->llc_dsap = l->llc_ssap = 0; 6147055Sdg /* Fall through to */ 6157055Sdg case LLC_TEST: 6167055Sdg case LLC_TEST_P: 6177055Sdg { 6187055Sdg struct sockaddr sa; 61921830Sjoerg register struct ether_header *eh; 62021830Sjoerg struct arpcom *ac = (struct arpcom *) ifp; 6217055Sdg int i; 6227055Sdg u_char c = l->llc_dsap; 6237055Sdg 6247055Sdg l->llc_dsap = l->llc_ssap; 6257055Sdg l->llc_ssap = c; 6267055Sdg if (m->m_flags & (M_BCAST | M_MCAST)) 6277055Sdg bcopy((caddr_t)ac->ac_enaddr, 6287055Sdg (caddr_t)eh->ether_dhost, 6); 6297055Sdg sa.sa_family = AF_UNSPEC; 6307055Sdg sa.sa_len = sizeof(sa); 63121830Sjoerg eh = (struct ether_header *)sa.sa_data; 6327055Sdg for (i = 0; i < 6; i++) { 63321830Sjoerg eh->ether_shost[i] = fh->fddi_dhost[i]; 63421830Sjoerg eh->ether_dhost[i] = fh->fddi_shost[i]; 6357055Sdg } 63621830Sjoerg eh->ether_type = 0; 6377055Sdg ifp->if_output(ifp, m, &sa, NULL); 6387055Sdg return; 6397055Sdg } 6407055Sdg default: 6417055Sdg m_freem(m); 6427055Sdg return; 6437055Sdg } 6447055Sdg break; 6457055Sdg#endif /* ISO */ 6467055Sdg#ifdef LLC 6477055Sdg case LLC_X25_LSAP: 6487055Sdg { 6497055Sdg M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT); 6507055Sdg if (m == 0) 6517055Sdg return; 6527055Sdg if ( !sdl_sethdrif(ifp, fh->fddi_shost, LLC_X25_LSAP, 65321830Sjoerg fh->fddi_dhost, LLC_X25_LSAP, 6, 6547055Sdg mtod(m, struct sdl_hdr *))) 6557055Sdg panic("ETHER cons addr failure"); 6567055Sdg mtod(m, struct sdl_hdr *)->sdlhdr_len = m->m_pkthdr.len - sizeof(struct sdl_hdr); 6577055Sdg#ifdef LLC_DEBUG 6587055Sdg printf("llc packet\n"); 6597055Sdg#endif /* LLC_DEBUG */ 6607055Sdg schednetisr(NETISR_CCITT); 6617055Sdg inq = &llcintrq; 6627055Sdg break; 6637055Sdg } 6647055Sdg#endif /* LLC */ 66521830Sjoerg 6667055Sdg default: 66721830Sjoerg /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 6687055Sdg ifp->if_noproto++; 6697055Sdg dropanyway: 6707055Sdg m_freem(m); 6717055Sdg return; 6727055Sdg } 6737055Sdg 6747055Sdg s = splimp(); 6757055Sdg if (IF_QFULL(inq)) { 6767055Sdg IF_DROP(inq); 6777055Sdg m_freem(m); 6787055Sdg } else 6797055Sdg IF_ENQUEUE(inq, m); 6807055Sdg splx(s); 6817055Sdg} 6827055Sdg/* 6837055Sdg * Perform common duties while attaching to interface list 6847055Sdg */ 68521830Sjoerg#ifdef __NetBSD__ 68621830Sjoerg#define ifa_next ifa_list.tqe_next 68721830Sjoerg#endif 68821830Sjoerg 6897055Sdgvoid 6907055Sdgfddi_ifattach(ifp) 6917055Sdg register struct ifnet *ifp; 6927055Sdg{ 6937055Sdg register struct ifaddr *ifa; 6947055Sdg register struct sockaddr_dl *sdl; 6957055Sdg 6967055Sdg ifp->if_type = IFT_FDDI; 6977055Sdg ifp->if_addrlen = 6; 6987055Sdg ifp->if_hdrlen = 21; 6997055Sdg ifp->if_mtu = FDDIMTU; 70016063Sgpalmer ifp->if_baudrate = 100000000; 70121830Sjoerg#ifdef IFF_NOTRAILERS 70221830Sjoerg ifp->if_flags |= IFF_NOTRAILERS; 70321830Sjoerg#endif 70421831Sjoerg#if defined(__FreeBSD__) 70521831Sjoerg ifa = ifnet_addrs[ifp->if_index - 1]; 70621831Sjoerg sdl = (struct sockaddr_dl *)ifa->ifa_addr; 70721831Sjoerg sdl->sdl_type = IFT_FDDI; 70821831Sjoerg sdl->sdl_alen = ifp->if_addrlen; 70921831Sjoerg bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 71021831Sjoerg#elif defined(__NetBSD__) 71121830Sjoerg LIST_INIT(&((struct arpcom *)ifp)->ac_multiaddrs); 71221830Sjoerg for (ifa = ifp->if_addrlist.tqh_first; ifa != NULL; ifa = ifa->ifa_list.tqe_next) 71321830Sjoerg#else 71421830Sjoerg for (ifa = ifp->if_addrlist; ifa != NULL; ifa = ifa->ifa_next) 71521830Sjoerg#endif 71621831Sjoerg#if !defined(__FreeBSD__) 71721830Sjoerg if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 71821830Sjoerg sdl->sdl_family == AF_LINK) { 71921830Sjoerg sdl->sdl_type = IFT_FDDI; 72021830Sjoerg sdl->sdl_alen = ifp->if_addrlen; 72121830Sjoerg bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, 72221830Sjoerg LLADDR(sdl), ifp->if_addrlen); 72321830Sjoerg break; 72421830Sjoerg } 72521831Sjoerg#endif 7267055Sdg} 727