if_atmsubr.c revision 32350
125603Skjc/*      $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $       */
225603Skjc
325603Skjc/*
425603Skjc *
525603Skjc * Copyright (c) 1996 Charles D. Cranor and Washington University.
625603Skjc * All rights reserved.
725603Skjc *
825603Skjc * Redistribution and use in source and binary forms, with or without
925603Skjc * modification, are permitted provided that the following conditions
1025603Skjc * are met:
1125603Skjc * 1. Redistributions of source code must retain the above copyright
1225603Skjc *    notice, this list of conditions and the following disclaimer.
1325603Skjc * 2. Redistributions in binary form must reproduce the above copyright
1425603Skjc *    notice, this list of conditions and the following disclaimer in the
1525603Skjc *    documentation and/or other materials provided with the distribution.
1625603Skjc * 3. All advertising materials mentioning features or use of this software
1725603Skjc *    must display the following acknowledgement:
1825603Skjc *      This product includes software developed by Charles D. Cranor and
1925603Skjc *	Washington University.
2025603Skjc * 4. The name of the author may not be used to endorse or promote products
2125603Skjc *    derived from this software without specific prior written permission.
2225603Skjc *
2325603Skjc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2425603Skjc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2525603Skjc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2625603Skjc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2725603Skjc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2825603Skjc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2925603Skjc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3025603Skjc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3125603Skjc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3225603Skjc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3325603Skjc */
3425603Skjc
3525603Skjc/*
3625603Skjc * if_atmsubr.c
3725603Skjc */
3825603Skjc
3932350Seivind#include "opt_inet.h"
4032350Seivind
4125603Skjc#include <sys/param.h>
4225603Skjc#include <sys/systm.h>
4325603Skjc#include <sys/mbuf.h>
4425603Skjc#include <sys/socket.h>
4525603Skjc
4625603Skjc#include <net/if.h>
4725603Skjc#include <net/netisr.h>
4825603Skjc#include <net/route.h>
4925603Skjc#include <net/if_dl.h>
5025603Skjc#include <net/if_types.h>
5125603Skjc#include <net/if_atm.h>
5225603Skjc
5325603Skjc#include <netinet/in.h>
5425603Skjc#include <netinet/if_atm.h>
5525603Skjc#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
5625603Skjc#ifdef INET
5725603Skjc#include <netinet/in_var.h>
5825603Skjc#endif
5925603Skjc#ifdef NATM
6025603Skjc#include <netnatm/natm.h>
6125603Skjc#endif
6225603Skjc
6325603Skjc#include "bpfilter.h"
6425603Skjc#if NBPFILTER > 0
6525603Skjc/*
6625603Skjc * bpf support.
6725603Skjc * the code is derived from if_loop.c.
6825603Skjc * bpf support should belong to the driver but it's easier to implement
6925603Skjc * it here since we can call bpf_mtap before atm_output adds a pseudo
7025603Skjc * header to the mbuf.
7125603Skjc *			--kjc
7225603Skjc */
7325603Skjc#include <net/bpf.h>
7425603Skjc#endif /* NBPFILTER > 0 */
7525603Skjc
7625603Skjc#define senderr(e) { error = (e); goto bad;}
7725603Skjc
7825603Skjc/*
7925603Skjc * atm_output: ATM output routine
8025603Skjc *   inputs:
8125603Skjc *     "ifp" = ATM interface to output to
8225603Skjc *     "m0" = the packet to output
8325603Skjc *     "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
8425603Skjc *     "rt0" = the route to use
8525603Skjc *   returns: error code   [0 == ok]
8625603Skjc *
8725603Skjc *   note: special semantic: if (dst == NULL) then we assume "m" already
8825603Skjc *		has an atm_pseudohdr on it and just send it directly.
8925603Skjc *		[for native mode ATM output]   if dst is null, then
9025603Skjc *		rt0 must also be NULL.
9125603Skjc */
9225603Skjc
9325603Skjcint
9425603Skjcatm_output(ifp, m0, dst, rt0)
9525603Skjc	register struct ifnet *ifp;
9625603Skjc	struct mbuf *m0;
9725603Skjc	struct sockaddr *dst;
9825603Skjc	struct rtentry *rt0;
9925603Skjc{
10025603Skjc	u_int16_t etype = 0;			/* if using LLC/SNAP */
10125603Skjc	int s, error = 0, sz;
10225603Skjc	struct atm_pseudohdr atmdst, *ad;
10325603Skjc	register struct mbuf *m = m0;
10425603Skjc	register struct rtentry *rt;
10525603Skjc	struct atmllc *atmllc;
10625603Skjc	u_int32_t atm_flags;
10725603Skjc
10825603Skjc	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
10925603Skjc		senderr(ENETDOWN);
11031264Sbde	gettime(&ifp->if_lastchange);
11125603Skjc
11225603Skjc	/*
11325603Skjc	 * check route
11425603Skjc	 */
11525603Skjc	if ((rt = rt0) != NULL) {
11625603Skjc
11725603Skjc		if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */
11825603Skjc			if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL)
11925603Skjc				rt->rt_refcnt--;
12025603Skjc			else
12125603Skjc				senderr(EHOSTUNREACH);
12225603Skjc		}
12325603Skjc
12425603Skjc		if (rt->rt_flags & RTF_GATEWAY) {
12525603Skjc			if (rt->rt_gwroute == 0)
12625603Skjc				goto lookup;
12725603Skjc			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
12825603Skjc				rtfree(rt); rt = rt0;
12925603Skjc			lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0);
13025603Skjc				if ((rt = rt->rt_gwroute) == 0)
13125603Skjc					senderr(EHOSTUNREACH);
13225603Skjc			}
13325603Skjc		}
13425603Skjc
13525603Skjc		/* XXX: put RTF_REJECT code here if doing ATMARP */
13625603Skjc
13725603Skjc	}
13825603Skjc
13925603Skjc	/*
14025603Skjc	 * check for non-native ATM traffic   (dst != NULL)
14125603Skjc	 */
14225603Skjc	if (dst) {
14325603Skjc		switch (dst->sa_family) {
14425603Skjc#ifdef INET
14525603Skjc		case AF_INET:
14625603Skjc			if (!atmresolve(rt, m, dst, &atmdst)) {
14725603Skjc				m = NULL;
14825603Skjc				/* XXX: atmresolve already free'd it */
14925603Skjc				senderr(EHOSTUNREACH);
15025603Skjc				/* XXX: put ATMARP stuff here */
15125603Skjc				/* XXX: watch who frees m on failure */
15225603Skjc			}
15325603Skjc			etype = htons(ETHERTYPE_IP);
15425603Skjc			break;
15525603Skjc#endif
15625603Skjc
15725603Skjc		default:
15825603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
15925603Skjc			printf("%s: can't handle af%d\n", ifp->if_xname,
16025603Skjc			    dst->sa_family);
16125603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
16225603Skjc			printf("%s%d: can't handle af%d\n", ifp->if_name,
16325603Skjc			    ifp->if_unit, dst->sa_family);
16425603Skjc#endif
16525603Skjc			senderr(EAFNOSUPPORT);
16625603Skjc		}
16725603Skjc
16825603Skjc#if NBPFILTER > 0
16925603Skjc		/* BPF write needs to be handled specially */
17025603Skjc		if (dst && dst->sa_family == AF_UNSPEC) {
17125603Skjc		    dst->sa_family = *(mtod(m, int *));
17225603Skjc		    m->m_len -= sizeof(int);
17325603Skjc		    m->m_pkthdr.len -= sizeof(int);
17425603Skjc		    m->m_data += sizeof(int);
17525603Skjc		}
17625603Skjc
17725603Skjc		if (ifp->if_bpf) {
17825603Skjc		    /*
17925603Skjc		     * We need to prepend the address family as
18025603Skjc		     * a four byte field.  Cons up a dummy header
18125603Skjc		     * to pacify bpf.  This is safe because bpf
18225603Skjc		     * will only read from the mbuf (i.e., it won't
18325603Skjc		     * try to free it or keep a pointer a to it).
18425603Skjc		     */
18525603Skjc		    struct mbuf m1;
18625603Skjc		    u_int af = dst->sa_family;
18725603Skjc
18825603Skjc		    m1.m_next = m;
18925603Skjc		    m1.m_len = 4;
19025603Skjc		    m1.m_data = (char *)&af;
19125603Skjc
19225603Skjc		    s = splimp();
19325603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
19425603Skjc		bpf_mtap(&ifp->if_bpf, &m0);
19525603Skjc#elif defined(__FreeBSD__)
19625603Skjc		    bpf_mtap(ifp, &m1);
19725603Skjc#endif
19825603Skjc		    splx(s);
19925603Skjc		}
20025603Skjc#endif /* NBPFILTER > 0 */
20125603Skjc
20225603Skjc		/*
20325603Skjc		 * must add atm_pseudohdr to data
20425603Skjc		 */
20525603Skjc		sz = sizeof(atmdst);
20625603Skjc		atm_flags = ATM_PH_FLAGS(&atmdst);
20725603Skjc		if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */
20825603Skjc		M_PREPEND(m, sz, M_DONTWAIT);
20925603Skjc		if (m == 0)
21025603Skjc			senderr(ENOBUFS);
21125603Skjc		ad = mtod(m, struct atm_pseudohdr *);
21225603Skjc		*ad = atmdst;
21325603Skjc		if (atm_flags & ATM_PH_LLCSNAP) {
21425603Skjc			atmllc = (struct atmllc *)(ad + 1);
21525603Skjc			bcopy(ATMLLC_HDR, atmllc->llchdr,
21625603Skjc						sizeof(atmllc->llchdr));
21725603Skjc			ATM_LLC_SETTYPE(atmllc, etype);
21825603Skjc					/* note: already in network order */
21925603Skjc		}
22025603Skjc	}
22125603Skjc
22225603Skjc	/*
22325603Skjc	 * Queue message on interface, and start output if interface
22425603Skjc	 * not yet active.
22525603Skjc	 */
22625603Skjc
22725603Skjc	s = splimp();
22825603Skjc	if (IF_QFULL(&ifp->if_snd)) {
22925603Skjc		IF_DROP(&ifp->if_snd);
23025603Skjc		splx(s);
23125603Skjc		senderr(ENOBUFS);
23225603Skjc	}
23325603Skjc	ifp->if_obytes += m->m_pkthdr.len;
23425603Skjc	IF_ENQUEUE(&ifp->if_snd, m);
23525603Skjc	if ((ifp->if_flags & IFF_OACTIVE) == 0)
23625603Skjc		(*ifp->if_start)(ifp);
23725603Skjc	splx(s);
23825603Skjc	return (error);
23925603Skjc
24025603Skjcbad:
24125603Skjc	if (m)
24225603Skjc		m_freem(m);
24325603Skjc	return (error);
24425603Skjc}
24525603Skjc
24625603Skjc/*
24725603Skjc * Process a received ATM packet;
24825603Skjc * the packet is in the mbuf chain m.
24925603Skjc */
25025603Skjcvoid
25125603Skjcatm_input(ifp, ah, m, rxhand)
25225603Skjc	struct ifnet *ifp;
25325603Skjc	register struct atm_pseudohdr *ah;
25425603Skjc	struct mbuf *m;
25525603Skjc	void *rxhand;
25625603Skjc{
25725603Skjc	register struct ifqueue *inq;
25825603Skjc	u_int16_t etype = ETHERTYPE_IP; /* default */
25925603Skjc	int s;
26025603Skjc
26125603Skjc	if ((ifp->if_flags & IFF_UP) == 0) {
26225603Skjc		m_freem(m);
26325603Skjc		return;
26425603Skjc	}
26531264Sbde	gettime(&ifp->if_lastchange);
26625603Skjc	ifp->if_ibytes += m->m_pkthdr.len;
26725603Skjc
26825603Skjc#if NBPFILTER > 0
26925603Skjc	if (ifp->if_bpf) {
27025603Skjc		/*
27125603Skjc		 * We need to prepend the address family as
27225603Skjc		 * a four byte field.  Cons up a dummy header
27325603Skjc		 * to pacify bpf.  This is safe because bpf
27425603Skjc		 * will only read from the mbuf (i.e., it won't
27525603Skjc		 * try to free it or keep a pointer to it).
27625603Skjc		 */
27725603Skjc		struct mbuf m0;
27825603Skjc		u_int af = AF_INET;
27925603Skjc
28025603Skjc		m0.m_next = m;
28125603Skjc		m0.m_len = 4;
28225603Skjc		m0.m_data = (char *)&af;
28325603Skjc
28425603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
28525603Skjc		bpf_mtap(&ifp->if_bpf, &m0);
28625603Skjc#elif defined(__FreeBSD__)
28725603Skjc		bpf_mtap(ifp, &m0);
28825603Skjc#endif
28925603Skjc	}
29025603Skjc#endif /* NBPFILTER > 0 */
29125603Skjc
29225603Skjc	if (rxhand) {
29325603Skjc#ifdef NATM
29425603Skjc	  struct natmpcb *npcb = rxhand;
29525603Skjc	  s = splimp();			/* in case 2 atm cards @ diff lvls */
29625603Skjc	  npcb->npcb_inq++;			/* count # in queue */
29725603Skjc	  splx(s);
29825603Skjc	  schednetisr(NETISR_NATM);
29925603Skjc	  inq = &natmintrq;
30025603Skjc	  m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
30125603Skjc#else
30225603Skjc	  printf("atm_input: NATM detected but not configured in kernel\n");
30325603Skjc	  m_freem(m);
30425603Skjc	  return;
30525603Skjc#endif
30625603Skjc	} else {
30725603Skjc	  /*
30825603Skjc	   * handle LLC/SNAP header, if present
30925603Skjc	   */
31025603Skjc	  if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
31125603Skjc	    struct atmllc *alc;
31225603Skjc	    if (m->m_len < sizeof(*alc) && (m = m_pullup(m, sizeof(*alc))) == 0)
31325603Skjc		  return; /* failed */
31425603Skjc	    alc = mtod(m, struct atmllc *);
31525603Skjc	    if (bcmp(alc, ATMLLC_HDR, 6)) {
31625603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
31725603Skjc	      printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
31825603Skjc		  ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
31925603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
32025603Skjc	      printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
32125603Skjc		  ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
32225603Skjc#endif
32325603Skjc	      m_freem(m);
32425603Skjc              return;
32525603Skjc	    }
32625603Skjc	    etype = ATM_LLC_TYPE(alc);
32725603Skjc	    m_adj(m, sizeof(*alc));
32825603Skjc	  }
32925603Skjc
33025603Skjc	  switch (etype) {
33125603Skjc#ifdef INET
33225603Skjc	  case ETHERTYPE_IP:
33325603Skjc		  schednetisr(NETISR_IP);
33425603Skjc		  inq = &ipintrq;
33525603Skjc		  break;
33625603Skjc#endif
33725603Skjc	  default:
33825603Skjc	      m_freem(m);
33925603Skjc	      return;
34025603Skjc	  }
34125603Skjc	}
34225603Skjc
34325603Skjc	s = splimp();
34425603Skjc	if (IF_QFULL(inq)) {
34525603Skjc		IF_DROP(inq);
34625603Skjc		m_freem(m);
34725603Skjc	} else
34825603Skjc		IF_ENQUEUE(inq, m);
34925603Skjc	splx(s);
35025603Skjc}
35125603Skjc
35225603Skjc/*
35325603Skjc * Perform common duties while attaching to interface list
35425603Skjc */
35525603Skjcvoid
35625603Skjcatm_ifattach(ifp)
35725603Skjc	register struct ifnet *ifp;
35825603Skjc{
35925603Skjc	register struct ifaddr *ifa;
36025603Skjc	register struct sockaddr_dl *sdl;
36125603Skjc
36225603Skjc	ifp->if_type = IFT_ATM;
36325603Skjc	ifp->if_addrlen = 0;
36425603Skjc	ifp->if_hdrlen = 0;
36525603Skjc	ifp->if_mtu = ATMMTU;
36625603Skjc	ifp->if_output = atm_output;
36725603Skjc
36825603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
36925603Skjc	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
37025603Skjc	    ifa = ifa->ifa_list.tqe_next)
37125603Skjc#elif defined(__FreeBSD__) && ((__FreeBSD__ > 2) || defined(_NET_IF_VAR_H_))
37225603Skjc/*
37325603Skjc * for FreeBSD-3.0.  3.0-SNAP-970124 still sets -D__FreeBSD__=2!
37425603Skjc * XXX -- for now, use newly-introduced "net/if_var.h" as an identifier.
37525603Skjc * need a better way to identify 3.0.  -- kjc
37625603Skjc */
37725603Skjc	for (ifa = ifp->if_addrhead.tqh_first; ifa;
37825603Skjc	    ifa = ifa->ifa_link.tqe_next)
37925603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
38025603Skjc	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
38125603Skjc#endif
38225603Skjc
38325603Skjc		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
38425603Skjc		    sdl->sdl_family == AF_LINK) {
38525603Skjc			sdl->sdl_type = IFT_ATM;
38625603Skjc			sdl->sdl_alen = ifp->if_addrlen;
38725603Skjc#ifdef notyet /* if using ATMARP, store hardware address using the next line */
38825603Skjc			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
38925603Skjc#endif
39025603Skjc			break;
39125603Skjc		}
39225603Skjc#if NBPFILTER > 0
39325603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
39425603Skjc	bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
39525603Skjc#elif defined(__FreeBSD__)
39625603Skjc	bpfattach(ifp, DLT_NULL, sizeof(u_int));
39725603Skjc#endif
39825603Skjc#endif /* NBPFILTER > 0 */
39925603Skjc}
400