if_iso88025subr.c revision 44165
144165Sjulian/* 244165Sjulian * Copyright (c) 1998, Larry Lile 344165Sjulian * All rights reserved. 444165Sjulian * 544165Sjulian * For latest sources and information on this driver, please 644165Sjulian * go to http://anarchy.stdio.com. 744165Sjulian * 844165Sjulian * Questions, comments or suggestions should be directed to 944165Sjulian * Larry Lile <lile@stdio.com>. 1044165Sjulian * 1144165Sjulian * Redistribution and use in source and binary forms, with or without 1244165Sjulian * modification, are permitted provided that the following conditions 1344165Sjulian * are met: 1444165Sjulian * 1. Redistributions of source code must retain the above copyright 1544165Sjulian * notice unmodified, this list of conditions, and the following 1644165Sjulian * disclaimer. 1744165Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1844165Sjulian * notice, this list of conditions and the following disclaimer in the 1944165Sjulian * documentation and/or other materials provided with the distribution. 2044165Sjulian * 2144165Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2244165Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2344165Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2444165Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2544165Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2644165Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2744165Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2844165Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2944165Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3044165Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3144165Sjulian * SUCH DAMAGE. 3244165Sjulian * 3344165Sjulian * $Id: if_iso88025subr.c,v 1.5 1999/01/09 22:45:58 lile Exp $ 3444165Sjulian * 3544165Sjulian */ 3644165Sjulian 3744165Sjulian/* 3844165Sjulian * 3944165Sjulian * General ISO 802.5 (Token Ring) support routines 4044165Sjulian * 4144165Sjulian */ 4244165Sjulian 4344165Sjulian#include "opt_inet.h" 4444165Sjulian 4544165Sjulian#include <sys/param.h> 4644165Sjulian#include <sys/systm.h> 4744165Sjulian#include <sys/kernel.h> 4844165Sjulian#include <sys/malloc.h> 4944165Sjulian#include <sys/mbuf.h> 5044165Sjulian#include <sys/socket.h> 5144165Sjulian#include <sys/sockio.h> 5244165Sjulian#include <sys/sysctl.h> 5344165Sjulian 5444165Sjulian#include <net/if.h> 5544165Sjulian#include <net/netisr.h> 5644165Sjulian#include <net/route.h> 5744165Sjulian#include <net/if_llc.h> 5844165Sjulian#include <net/if_dl.h> 5944165Sjulian#include <net/if_types.h> 6044165Sjulian 6144165Sjulian#include <net/if_arp.h> 6244165Sjulian 6344165Sjulian#include <net/iso88025.h> 6444165Sjulian 6544165Sjulian#ifdef INET 6644165Sjulian#include <netinet/in.h> 6744165Sjulian#include <netinet/in_var.h> 6844165Sjulian#include <netinet/if_ether.h> 6944165Sjulian#endif 7044165Sjulian 7144165Sjulian#if NBPFILTER > 0 7244165Sjulian#include <net/bpf.h> 7344165Sjulian#include <net/bpfdesc.h> 7444165Sjulian#endif 7544165Sjulian 7644165Sjulian#include <machine/clock.h> 7744165Sjulian#include <machine/md_var.h> 7844165Sjulian 7944165Sjulian#include <i386/isa/isa_device.h> 8044165Sjulian 8144165Sjulian#include <vm/vm.h> 8244165Sjulian#include <vm/vm_param.h> 8344165Sjulian#include <vm/pmap.h> 8444165Sjulian 8544165Sjulian#include <sys/kernel.h> 8644165Sjulian#include <net/iso88025.h> 8744165Sjulian 8844165Sjulianvoid 8944165Sjulianiso88025_ifattach(ifp) 9044165Sjulian register struct ifnet *ifp; 9144165Sjulian{ 9244165Sjulian register struct ifaddr *ifa = NULL; 9344165Sjulian register struct sockaddr_dl *sdl; 9444165Sjulian 9544165Sjulian ifp->if_type = IFT_ISO88025; 9644165Sjulian ifp->if_addrlen = 6; 9744165Sjulian ifp->if_hdrlen=18; 9844165Sjulian if (ifp->if_baudrate == 0) 9944165Sjulian ifp->if_baudrate = 16000000; /* 1, 4, or 16Mbit default? */ 10044165Sjulian if (ifp->if_mtu == 0) 10144165Sjulian ifp->if_mtu = ISO88025_DEFAULT_MTU; 10244165Sjulian 10344165Sjulian ifa = ifnet_addrs[ifp->if_index - 1]; 10444165Sjulian if (ifa == 0) { 10544165Sjulian printf("iso88025_ifattach: no lladdr!\n"); 10644165Sjulian return; 10744165Sjulian } 10844165Sjulian sdl = (struct sockaddr_dl *)ifa->ifa_addr; 10944165Sjulian sdl->sdl_type = IFT_ISO88025; 11044165Sjulian sdl->sdl_alen = ifp->if_addrlen; 11144165Sjulian bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 11244165Sjulian} 11344165Sjulian 11444165Sjulianint 11544165Sjulianiso88025_ioctl(struct ifnet *ifp, int command, caddr_t data) 11644165Sjulian{ 11744165Sjulian struct ifaddr *ifa = (struct ifaddr *) data; 11844165Sjulian struct ifreq *ifr = (struct ifreq *) data; 11944165Sjulian int error = 0; 12044165Sjulian 12144165Sjulian switch (command) { 12244165Sjulian case SIOCSIFADDR: 12344165Sjulian ifp->if_flags |= IFF_UP; 12444165Sjulian 12544165Sjulian switch (ifa->ifa_addr->sa_family) { 12644165Sjulian#ifdef INET 12744165Sjulian case AF_INET: 12844165Sjulian ifp->if_init(ifp->if_softc); /* before arpwhohas */ 12944165Sjulian arp_ifinit((struct arpcom *)ifp, ifa); 13044165Sjulian break; 13144165Sjulian#endif 13244165Sjulian default: 13344165Sjulian ifp->if_init(ifp->if_softc); 13444165Sjulian break; 13544165Sjulian } 13644165Sjulian break; 13744165Sjulian 13844165Sjulian case SIOCGIFADDR: 13944165Sjulian { 14044165Sjulian struct sockaddr *sa; 14144165Sjulian 14244165Sjulian sa = (struct sockaddr *) & ifr->ifr_data; 14344165Sjulian bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr, 14444165Sjulian (caddr_t) sa->sa_data, ISO88025_ADDR_LEN); 14544165Sjulian } 14644165Sjulian break; 14744165Sjulian 14844165Sjulian case SIOCSIFMTU: 14944165Sjulian /* 15044165Sjulian * Set the interface MTU. 15144165Sjulian */ 15244165Sjulian if (ifr->ifr_mtu > ISO88025MTU) { 15344165Sjulian error = EINVAL; 15444165Sjulian } else { 15544165Sjulian ifp->if_mtu = ifr->ifr_mtu; 15644165Sjulian } 15744165Sjulian break; 15844165Sjulian } 15944165Sjulian return (error); 16044165Sjulian} 16144165Sjulian 16244165Sjulian/* 16344165Sjulian * ISO88025 encapsulation 16444165Sjulian */ 16544165Sjulianint 16644165Sjulianiso88025_output(ifp, m0, dst, rt0) 16744165Sjulian register struct ifnet *ifp; 16844165Sjulian struct mbuf *m0; 16944165Sjulian struct sockaddr *dst; 17044165Sjulian struct rtentry *rt0; 17144165Sjulian{ 17244165Sjulian register struct ether_header *eh; /* Needed for AF_UNSPEC XXX */ 17344165Sjulian register struct iso88025_header *th; 17444165Sjulian register struct llc *l; 17544165Sjulian short type; 17644165Sjulian int s, error = 0; 17744165Sjulian u_char edst[6]; 17844165Sjulian register struct mbuf *m = m0; 17944165Sjulian register struct rtentry *rt; 18044165Sjulian struct mbuf *mcopy = (struct mbuf *)0; 18144165Sjulian int off, len = m->m_pkthdr.len, loop_copy = 0; 18244165Sjulian struct arpcom *ac = (struct arpcom *)ifp; 18344165Sjulian 18444165Sjulian if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 18544165Sjulian senderr(ENETDOWN); 18644165Sjulian rt = rt0; 18744165Sjulian if (rt) { 18844165Sjulian if ((rt->rt_flags & RTF_UP) == 0) { 18944165Sjulian rt0 = rt = rtalloc1(dst, 1, 0UL); 19044165Sjulian if (rt0) 19144165Sjulian rt->rt_refcnt--; 19244165Sjulian else 19344165Sjulian senderr(EHOSTUNREACH); 19444165Sjulian } 19544165Sjulian if (rt->rt_flags & RTF_GATEWAY) { 19644165Sjulian if (rt->rt_gwroute == 0) 19744165Sjulian goto lookup; 19844165Sjulian if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 19944165Sjulian rtfree(rt); rt = rt0; 20044165Sjulian lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 20144165Sjulian 0UL); 20244165Sjulian if ((rt = rt->rt_gwroute) == 0) 20344165Sjulian senderr(EHOSTUNREACH); 20444165Sjulian } 20544165Sjulian } 20644165Sjulian if (rt->rt_flags & RTF_REJECT) 20744165Sjulian if (rt->rt_rmx.rmx_expire == 0 || 20844165Sjulian time_second < rt->rt_rmx.rmx_expire) 20944165Sjulian senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 21044165Sjulian } 21144165Sjulian switch (dst->sa_family) { 21244165Sjulian 21344165Sjulian#ifdef INET 21444165Sjulian case AF_INET: 21544165Sjulian /*printf("%s%d: iso88025_output (AF_INET).\n", ifp->if_name, ifp->if_unit);*/ 21644165Sjulian if (!arpresolve(ac, rt, m, dst, edst, rt0)) 21744165Sjulian return (0); /* if not yet resolved */ 21844165Sjulian off = m->m_pkthdr.len - m->m_len; 21944165Sjulian type = htons(ETHERTYPE_IP); 22044165Sjulian break; 22144165Sjulian#endif 22244165Sjulian 22344165Sjulian case AF_UNSPEC: 22444165Sjulian /*printf("%s%d: iso88025_output (AF_UNSPEC).\n", ifp->if_name, ifp->if_unit);*/ 22544165Sjulian loop_copy = -1; 22644165Sjulian eh = (struct ether_header *)dst->sa_data; 22744165Sjulian (void)memcpy(edst, eh->ether_dhost, sizeof (edst)); 22844165Sjulian type = eh->ether_type; 22944165Sjulian break; 23044165Sjulian 23144165Sjulian default: 23244165Sjulian printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 23344165Sjulian dst->sa_family); 23444165Sjulian senderr(EAFNOSUPPORT); 23544165Sjulian } 23644165Sjulian 23744165Sjulian /* 23844165Sjulian * Add local net header. If no space in first mbuf, 23944165Sjulian * allocate another. 24044165Sjulian */ 24144165Sjulian M_PREPEND(m, ISO88025_HDR_LEN + 8, M_DONTWAIT); 24244165Sjulian if (m == 0) 24344165Sjulian senderr(ENOBUFS); 24444165Sjulian th = mtod(m, struct iso88025_header *); 24544165Sjulian th->ac = 0x10; 24644165Sjulian th->fc = 0x40; 24744165Sjulian m->m_data += ISO88025_HDR_LEN; 24844165Sjulian l = mtod(m , struct llc *); 24944165Sjulian m->m_data -= ISO88025_HDR_LEN; 25044165Sjulian (void)memcpy(&l->llc_un.type_snap.ether_type, &type, 25144165Sjulian sizeof(l->llc_un.type_snap.ether_type)); 25244165Sjulian (void)memcpy(th->iso88025_dhost, edst, sizeof (edst)); 25344165Sjulian (void)memcpy(th->iso88025_shost, ac->ac_enaddr, 25444165Sjulian sizeof(th->iso88025_shost)); 25544165Sjulian l->llc_dsap = 0xaa; 25644165Sjulian l->llc_ssap = 0xaa; 25744165Sjulian l->llc_un.type_snap.control = 0x3; 25844165Sjulian l->llc_un.type_snap.org_code[0] = 0x0; 25944165Sjulian l->llc_un.type_snap.org_code[1] = 0x0; 26044165Sjulian l->llc_un.type_snap.org_code[2] = 0x0; 26144165Sjulian /* 26244165Sjulian * If a simplex interface, and the packet is being sent to our 26344165Sjulian * Ethernet address or a broadcast address, loopback a copy. 26444165Sjulian * XXX To make a simplex device behave exactly like a duplex 26544165Sjulian * device, we should copy in the case of sending to our own 26644165Sjulian * ethernet address (thus letting the original actually appear 26744165Sjulian * on the wire). However, we don't do that here for security 26844165Sjulian * reasons and compatibility with the original behavior. 26944165Sjulian */ 27044165Sjulian if ((ifp->if_flags & IFF_SIMPLEX) && 27144165Sjulian (loop_copy != -1)) { 27244165Sjulian if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 27344165Sjulian struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 27444165Sjulian /*printf("iso88025_output: if_simloop broadcast.\n");*/ 27544165Sjulian (void) if_simloop(ifp, n, dst, ISO88025_HDR_LEN); 27644165Sjulian } else if (bcmp(th->iso88025_dhost, 27744165Sjulian th->iso88025_shost, ETHER_ADDR_LEN) == 0) { 27844165Sjulian /*printf("iso88025_output: if_simloop to ourselves.\n");*/ 27944165Sjulian (void) if_simloop(ifp, m, dst, ISO88025_HDR_LEN); 28044165Sjulian return(0); /* XXX */ 28144165Sjulian } 28244165Sjulian } 28344165Sjulian 28444165Sjulian s = splimp(); 28544165Sjulian /* 28644165Sjulian * Queue message on interface, and start output if interface 28744165Sjulian * not yet active. 28844165Sjulian */ 28944165Sjulian if (IF_QFULL(&ifp->if_snd)) { 29044165Sjulian printf("iso88025_output: packet dropped QFULL.\n"); 29144165Sjulian IF_DROP(&ifp->if_snd); 29244165Sjulian splx(s); 29344165Sjulian senderr(ENOBUFS); 29444165Sjulian } 29544165Sjulian IF_ENQUEUE(&ifp->if_snd, m); 29644165Sjulian /*printf("iso88025_output: packet queued.\n");*/ 29744165Sjulian if ((ifp->if_flags & IFF_OACTIVE) == 0) 29844165Sjulian (*ifp->if_start)(ifp); 29944165Sjulian splx(s); 30044165Sjulian ifp->if_obytes += len + ISO88025_HDR_LEN + 8; 30144165Sjulian if (m->m_flags & M_MCAST) 30244165Sjulian ifp->if_omcasts++; 30344165Sjulian return (error); 30444165Sjulian 30544165Sjulianbad: 30644165Sjulian if (m) 30744165Sjulian m_freem(m); 30844165Sjulian printf("iso88025_output: something went wrong, bailing to bad.\n"); 30944165Sjulian return (error); 31044165Sjulian} 31144165Sjulian 31244165Sjulian/* 31344165Sjulian * ISO 88025 de-encapsulation 31444165Sjulian */ 31544165Sjulianvoid 31644165Sjulianiso88025_input(ifp, th, m) 31744165Sjulian struct ifnet *ifp; 31844165Sjulian register struct iso88025_header *th; 31944165Sjulian struct mbuf *m; 32044165Sjulian{ 32144165Sjulian register struct ifqueue *inq; 32244165Sjulian u_short ether_type; 32344165Sjulian int s; 32444165Sjulian register struct llc *l = mtod(m, struct llc *); 32544165Sjulian 32644165Sjulian /*printf("iso88025_input: entered.\n");*/ 32744165Sjulian 32844165Sjulian /*m->m_pkthdr.len = m->m_len = m->m_len - 8;*/ /* Length of LLC header in our case */ 32944165Sjulian m->m_pkthdr.len -= 8; 33044165Sjulian m->m_len -= 8; 33144165Sjulian m->m_data += 8; /* Length of LLC header in our case */ 33244165Sjulian 33344165Sjulian if ((ifp->if_flags & IFF_UP) == 0) { 33444165Sjulian m_freem(m); 33544165Sjulian return; 33644165Sjulian } 33744165Sjulian ifp->if_ibytes += m->m_pkthdr.len + sizeof (*th); 33844165Sjulian if (th->iso88025_dhost[0] & 1) { 33944165Sjulian if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)th->iso88025_dhost, 34044165Sjulian sizeof(etherbroadcastaddr)) == 0) 34144165Sjulian m->m_flags |= M_BCAST; 34244165Sjulian else 34344165Sjulian m->m_flags |= M_MCAST; 34444165Sjulian } 34544165Sjulian if (m->m_flags & (M_BCAST|M_MCAST)) 34644165Sjulian ifp->if_imcasts++; 34744165Sjulian 34844165Sjulian ether_type = ntohs(l->llc_un.type_snap.ether_type); 34944165Sjulian 35044165Sjulian /*printf("iso88025_input: source %6D dest %6D ethertype %x\n", th->iso88025_shost, ":", th->iso88025_dhost, ":", ether_type);*/ 35144165Sjulian 35244165Sjulian th->iso88025_shost[0] &= ~(0x80); /* Turn off source route bit */ 35344165Sjulian 35444165Sjulian switch (ether_type) { 35544165Sjulian#ifdef INET 35644165Sjulian case ETHERTYPE_IP: 35744165Sjulian /*printf("iso88025_input: IP Packet\n");*/ 35844165Sjulian if (ipflow_fastforward(m)) 35944165Sjulian return; 36044165Sjulian schednetisr(NETISR_IP); 36144165Sjulian inq = &ipintrq; 36244165Sjulian break; 36344165Sjulian 36444165Sjulian case ETHERTYPE_ARP: 36544165Sjulian /*printf("iso88025_input: ARP Packet\n");*/ 36644165Sjulian schednetisr(NETISR_ARP); 36744165Sjulian inq = &arpintrq; 36844165Sjulian break; 36944165Sjulian#endif 37044165Sjulian default: 37144165Sjulian m_freem(m); 37244165Sjulian return; 37344165Sjulian } 37444165Sjulian 37544165Sjulian s = splimp(); 37644165Sjulian if (IF_QFULL(inq)) { 37744165Sjulian IF_DROP(inq); 37844165Sjulian m_freem(m); 37944165Sjulian printf("iso88025_input: Packet dropped (Queue full).\n"); 38044165Sjulian } else 38144165Sjulian IF_ENQUEUE(inq, m); 38244165Sjulian /*printf("iso88025_input: Packet queued.\n");*/ 38344165Sjulian splx(s); 38444165Sjulian} 385