if_iso88025subr.c revision 50477
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 * 3350477Speter * $FreeBSD: head/sys/net/if_iso88025subr.c 50477 1999-08-28 01:08:13Z peter $ 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 7148645Sdes#if NBPF > 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 iso88025_header *th; 17344627Sjulian struct iso88025_header gen_th; 17444627Sjulian register struct iso88025_sockaddr_data *sd = (struct iso88025_sockaddr_data *)dst->sa_data; 17544165Sjulian register struct llc *l; 17644627Sjulian register struct sockaddr_dl *sdl = NULL; 17744627Sjulian int s, error = 0, rif_len = 0; 17844165Sjulian u_char edst[6]; 17944165Sjulian register struct mbuf *m = m0; 18044165Sjulian register struct rtentry *rt; 18144627Sjulian int 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 } 21144627Sjulian 21244627Sjulian /* Calculate routing info length based on arp table entry */ 21344627Sjulian if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway)) 21444627Sjulian if (sdl->sdl_rcf != NULL) 21544627Sjulian rif_len = (ntohs(sdl->sdl_rcf) & 0x1f00) >> 8; 21644627Sjulian 21744627Sjulian /* Generate a generic 802.5 header for the packet */ 21844627Sjulian gen_th.ac = 0x10; 21944627Sjulian gen_th.fc = 0x40; 22044627Sjulian memcpy(gen_th.iso88025_shost, ac->ac_enaddr, sizeof(ac->ac_enaddr)); 22144627Sjulian if (rif_len) { 22244627Sjulian gen_th.iso88025_shost[0] |= 0x80; 22344627Sjulian if (rif_len > 2) { 22444627Sjulian gen_th.rcf = sdl->sdl_rcf; 22544627Sjulian memcpy(gen_th.rseg, sdl->sdl_route, rif_len - 2); 22644627Sjulian } 22744627Sjulian } 22844627Sjulian 22944627Sjulian 23044165Sjulian switch (dst->sa_family) { 23144165Sjulian#ifdef INET 23244165Sjulian case AF_INET: 23344165Sjulian if (!arpresolve(ac, rt, m, dst, edst, rt0)) 23444165Sjulian return (0); /* if not yet resolved */ 23544627Sjulian /* Add LLC and SNAP headers */ 23644627Sjulian M_PREPEND(m, 8, M_DONTWAIT) 23744627Sjulian if (m == 0) 23844627Sjulian senderr(ENOBUFS); 23944627Sjulian l = mtod(m, struct llc *); 24044627Sjulian l->llc_un.type_snap.ether_type = htons(ETHERTYPE_IP); 24144627Sjulian l->llc_dsap = 0xaa; 24244627Sjulian l->llc_ssap = 0xaa; 24344627Sjulian l->llc_un.type_snap.control = 0x3; 24444627Sjulian l->llc_un.type_snap.org_code[0] = 0x0; 24544627Sjulian l->llc_un.type_snap.org_code[1] = 0x0; 24644627Sjulian l->llc_un.type_snap.org_code[2] = 0x0; 24744627Sjulian memcpy(gen_th.iso88025_dhost, edst, sizeof(edst)); 24844165Sjulian break; 24944165Sjulian#endif 25044165Sjulian 25144165Sjulian case AF_UNSPEC: 25244627Sjulian /* 25344627Sjulian * For AF_UNSPEC sockaddr.sa_data must contain all of the 25444627Sjulian * mac information needed to send the packet. This allows 25544627Sjulian * full mac, llc, and source routing function to be controlled. 25644627Sjulian * llc and source routing information must already be in the 25744627Sjulian * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data 25844627Sjulian * should be a iso88025_sockaddr_data structure see iso88025.h 25944627Sjulian */ 26044165Sjulian loop_copy = -1; 26144627Sjulian sd = (struct iso88025_sockaddr_data *)dst->sa_data; 26244627Sjulian gen_th.ac = sd->ac; 26344627Sjulian gen_th.fc = sd->fc; 26444627Sjulian memcpy(gen_th.iso88025_dhost, sd->ether_dhost, sizeof(sd->ether_dhost)); 26544627Sjulian memcpy(gen_th.iso88025_shost, sd->ether_shost, sizeof(sd->ether_shost)); 26644627Sjulian rif_len = 0; 26744165Sjulian break; 26844165Sjulian 26944165Sjulian default: 27044165Sjulian printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 27144165Sjulian dst->sa_family); 27244165Sjulian senderr(EAFNOSUPPORT); 27344165Sjulian } 27444165Sjulian 27544165Sjulian /* 27644165Sjulian * Add local net header. If no space in first mbuf, 27744165Sjulian * allocate another. 27844165Sjulian */ 27944627Sjulian 28044627Sjulian M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_DONTWAIT); 28144165Sjulian if (m == 0) 28244165Sjulian senderr(ENOBUFS); 28344627Sjulian 28444627Sjulian /* Copy as much of the generic header as is needed into the mbuf */ 28544165Sjulian th = mtod(m, struct iso88025_header *); 28644627Sjulian memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len); 28744627Sjulian 28844165Sjulian /* 28944165Sjulian * If a simplex interface, and the packet is being sent to our 29044165Sjulian * Ethernet address or a broadcast address, loopback a copy. 29144165Sjulian * XXX To make a simplex device behave exactly like a duplex 29244165Sjulian * device, we should copy in the case of sending to our own 29344165Sjulian * ethernet address (thus letting the original actually appear 29444165Sjulian * on the wire). However, we don't do that here for security 29544165Sjulian * reasons and compatibility with the original behavior. 29644165Sjulian */ 29744165Sjulian if ((ifp->if_flags & IFF_SIMPLEX) && 29844165Sjulian (loop_copy != -1)) { 29944165Sjulian if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 30044165Sjulian struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 30144165Sjulian /*printf("iso88025_output: if_simloop broadcast.\n");*/ 30244165Sjulian (void) if_simloop(ifp, n, dst, ISO88025_HDR_LEN); 30344165Sjulian } else if (bcmp(th->iso88025_dhost, 30444165Sjulian th->iso88025_shost, ETHER_ADDR_LEN) == 0) { 30544165Sjulian /*printf("iso88025_output: if_simloop to ourselves.\n");*/ 30644165Sjulian (void) if_simloop(ifp, m, dst, ISO88025_HDR_LEN); 30744165Sjulian return(0); /* XXX */ 30844165Sjulian } 30944165Sjulian } 31044165Sjulian 31144165Sjulian s = splimp(); 31244165Sjulian /* 31344165Sjulian * Queue message on interface, and start output if interface 31444165Sjulian * not yet active. 31544165Sjulian */ 31644165Sjulian if (IF_QFULL(&ifp->if_snd)) { 31744165Sjulian printf("iso88025_output: packet dropped QFULL.\n"); 31844165Sjulian IF_DROP(&ifp->if_snd); 31944165Sjulian splx(s); 32044165Sjulian senderr(ENOBUFS); 32144165Sjulian } 32244165Sjulian IF_ENQUEUE(&ifp->if_snd, m); 32344165Sjulian /*printf("iso88025_output: packet queued.\n");*/ 32444165Sjulian if ((ifp->if_flags & IFF_OACTIVE) == 0) 32544165Sjulian (*ifp->if_start)(ifp); 32644165Sjulian splx(s); 32744165Sjulian ifp->if_obytes += len + ISO88025_HDR_LEN + 8; 32844165Sjulian if (m->m_flags & M_MCAST) 32944165Sjulian ifp->if_omcasts++; 33044165Sjulian return (error); 33144165Sjulian 33244165Sjulianbad: 33344165Sjulian if (m) 33444165Sjulian m_freem(m); 33544627Sjulian /*printf("iso88025_output: something went wrong, bailing to bad.\n");*/ 33644165Sjulian return (error); 33744165Sjulian} 33844165Sjulian 33944165Sjulian/* 34044165Sjulian * ISO 88025 de-encapsulation 34144165Sjulian */ 34244165Sjulianvoid 34344165Sjulianiso88025_input(ifp, th, m) 34444165Sjulian struct ifnet *ifp; 34544165Sjulian register struct iso88025_header *th; 34644165Sjulian struct mbuf *m; 34744165Sjulian{ 34844165Sjulian register struct ifqueue *inq; 34944165Sjulian u_short ether_type; 35044165Sjulian int s; 35144165Sjulian register struct llc *l = mtod(m, struct llc *); 35244165Sjulian 35344165Sjulian /*printf("iso88025_input: entered.\n");*/ 35444165Sjulian 35544165Sjulian /*m->m_pkthdr.len = m->m_len = m->m_len - 8;*/ /* Length of LLC header in our case */ 35644165Sjulian m->m_pkthdr.len -= 8; 35744165Sjulian m->m_len -= 8; 35844165Sjulian m->m_data += 8; /* Length of LLC header in our case */ 35944165Sjulian 36044165Sjulian if ((ifp->if_flags & IFF_UP) == 0) { 36144165Sjulian m_freem(m); 36244165Sjulian return; 36344165Sjulian } 36444165Sjulian ifp->if_ibytes += m->m_pkthdr.len + sizeof (*th); 36544165Sjulian if (th->iso88025_dhost[0] & 1) { 36644165Sjulian if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)th->iso88025_dhost, 36744165Sjulian sizeof(etherbroadcastaddr)) == 0) 36844165Sjulian m->m_flags |= M_BCAST; 36944165Sjulian else 37044165Sjulian m->m_flags |= M_MCAST; 37144165Sjulian } 37244165Sjulian if (m->m_flags & (M_BCAST|M_MCAST)) 37344165Sjulian ifp->if_imcasts++; 37444165Sjulian 37544165Sjulian ether_type = ntohs(l->llc_un.type_snap.ether_type); 37644165Sjulian 37744165Sjulian /*printf("iso88025_input: source %6D dest %6D ethertype %x\n", th->iso88025_shost, ":", th->iso88025_dhost, ":", ether_type);*/ 37844165Sjulian 37944165Sjulian switch (ether_type) { 38044165Sjulian#ifdef INET 38144165Sjulian case ETHERTYPE_IP: 38244165Sjulian /*printf("iso88025_input: IP Packet\n");*/ 38344627Sjulian th->iso88025_shost[0] &= ~(0x80); /* Turn off source route bit XXX */ 38444165Sjulian if (ipflow_fastforward(m)) 38544165Sjulian return; 38644165Sjulian schednetisr(NETISR_IP); 38744165Sjulian inq = &ipintrq; 38844165Sjulian break; 38944165Sjulian 39044165Sjulian case ETHERTYPE_ARP: 39144165Sjulian /*printf("iso88025_input: ARP Packet\n");*/ 39244165Sjulian schednetisr(NETISR_ARP); 39344165Sjulian inq = &arpintrq; 39444165Sjulian break; 39544165Sjulian#endif 39644165Sjulian default: 39744165Sjulian m_freem(m); 39844165Sjulian return; 39944165Sjulian } 40044165Sjulian 40144165Sjulian s = splimp(); 40244165Sjulian if (IF_QFULL(inq)) { 40344165Sjulian IF_DROP(inq); 40444165Sjulian m_freem(m); 40544165Sjulian printf("iso88025_input: Packet dropped (Queue full).\n"); 40644165Sjulian } else 40744165Sjulian IF_ENQUEUE(inq, m); 40844165Sjulian /*printf("iso88025_input: Packet queued.\n");*/ 40944165Sjulian splx(s); 41044165Sjulian} 411