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