if_atmsubr.c revision 112193
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.
3354263Sshin *
3454263Sshin * $FreeBSD: head/sys/net/if_atmsubr.c 112193 2003-03-13 12:44:06Z harti $
3525603Skjc */
3625603Skjc
3725603Skjc/*
3825603Skjc * if_atmsubr.c
3925603Skjc */
4025603Skjc
4132350Seivind#include "opt_inet.h"
4254263Sshin#include "opt_inet6.h"
43105576Srwatson#include "opt_mac.h"
4432925Seivind#include "opt_natm.h"
4532350Seivind
4625603Skjc#include <sys/param.h>
4725603Skjc#include <sys/systm.h>
48105576Srwatson#include <sys/mac.h>
4925603Skjc#include <sys/mbuf.h>
5025603Skjc#include <sys/socket.h>
5137939Skjc#include <sys/sockio.h>
5237939Skjc#include <sys/errno.h>
5325603Skjc
5425603Skjc#include <net/if.h>
5525603Skjc#include <net/netisr.h>
5625603Skjc#include <net/route.h>
5725603Skjc#include <net/if_dl.h>
5825603Skjc#include <net/if_types.h>
5925603Skjc#include <net/if_atm.h>
6025603Skjc
6125603Skjc#include <netinet/in.h>
6225603Skjc#include <netinet/if_atm.h>
6325603Skjc#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
6437939Skjc#if defined(INET) || defined(INET6)
6525603Skjc#include <netinet/in_var.h>
6625603Skjc#endif
6725603Skjc#ifdef NATM
6825603Skjc#include <netnatm/natm.h>
6925603Skjc#endif
7025603Skjc
7137939Skjc#ifndef ETHERTYPE_IPV6
7237939Skjc#define ETHERTYPE_IPV6	0x86dd
7337939Skjc#endif
7425603Skjc
7525603Skjc#define senderr(e) { error = (e); goto bad;}
7625603Skjc
7725603Skjc/*
7825603Skjc * atm_output: ATM output routine
7925603Skjc *   inputs:
8025603Skjc *     "ifp" = ATM interface to output to
8125603Skjc *     "m0" = the packet to output
8225603Skjc *     "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
8325603Skjc *     "rt0" = the route to use
8425603Skjc *   returns: error code   [0 == ok]
8525603Skjc *
8625603Skjc *   note: special semantic: if (dst == NULL) then we assume "m" already
8725603Skjc *		has an atm_pseudohdr on it and just send it directly.
8825603Skjc *		[for native mode ATM output]   if dst is null, then
8925603Skjc *		rt0 must also be NULL.
9025603Skjc */
9125603Skjc
9225603Skjcint
9325603Skjcatm_output(ifp, m0, dst, rt0)
94111774Smdodd	struct ifnet *ifp;
9525603Skjc	struct mbuf *m0;
9625603Skjc	struct sockaddr *dst;
9725603Skjc	struct rtentry *rt0;
9825603Skjc{
9925603Skjc	u_int16_t etype = 0;			/* if using LLC/SNAP */
10078249Speter	int error = 0, sz;
10125603Skjc	struct atm_pseudohdr atmdst, *ad;
10259633Skjc	struct mbuf *m = m0;
10359633Skjc	struct rtentry *rt;
10425603Skjc	struct atmllc *atmllc;
10537939Skjc	struct atmllc *llc_hdr = NULL;
10625603Skjc	u_int32_t atm_flags;
10725603Skjc
108105576Srwatson#ifdef MAC
109105576Srwatson	error = mac_check_ifnet_transmit(ifp, m);
110105576Srwatson	if (error)
111105576Srwatson		senderr(error);
112105576Srwatson#endif
113105576Srwatson
11425603Skjc	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
11525603Skjc		senderr(ENETDOWN);
11625603Skjc
11725603Skjc	/*
11825603Skjc	 * check route
11925603Skjc	 */
120111767Smdodd	error = rt_check(&rt, &rt0, dst);
121111767Smdodd	if (error)
122111767Smdodd		goto bad;
12325603Skjc
12425603Skjc	/*
12525603Skjc	 * check for non-native ATM traffic   (dst != NULL)
12625603Skjc	 */
12725603Skjc	if (dst) {
12825603Skjc		switch (dst->sa_family) {
12937939Skjc#if defined(INET) || defined(INET6)
13025603Skjc		case AF_INET:
13137939Skjc		case AF_INET6:
13246695Skjc			if (dst->sa_family == AF_INET6)
133112193Sharti			        etype = ETHERTYPE_IPV6;
13446695Skjc			else
135112193Sharti			        etype = ETHERTYPE_IP;
13625603Skjc			if (!atmresolve(rt, m, dst, &atmdst)) {
13725603Skjc				m = NULL;
13825603Skjc				/* XXX: atmresolve already free'd it */
13925603Skjc				senderr(EHOSTUNREACH);
14025603Skjc				/* XXX: put ATMARP stuff here */
14125603Skjc				/* XXX: watch who frees m on failure */
14225603Skjc			}
14325603Skjc			break;
14437939Skjc#endif /* INET || INET6 */
14525603Skjc
14637939Skjc		case AF_UNSPEC:
14737939Skjc			/*
14846695Skjc			 * XXX: bpfwrite. assuming dst contains 12 bytes
14946695Skjc			 * (atm pseudo header (4) + LLC/SNAP (8))
15037939Skjc			 */
15137939Skjc			bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
15237939Skjc			llc_hdr = (struct atmllc *)(dst->sa_data + sizeof(atmdst));
15337939Skjc			break;
15437939Skjc
15525603Skjc		default:
15625603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
15725603Skjc			printf("%s: can't handle af%d\n", ifp->if_xname,
15825603Skjc			    dst->sa_family);
15925603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
16025603Skjc			printf("%s%d: can't handle af%d\n", ifp->if_name,
16125603Skjc			    ifp->if_unit, dst->sa_family);
16225603Skjc#endif
16325603Skjc			senderr(EAFNOSUPPORT);
16425603Skjc		}
16525603Skjc
16625603Skjc		/*
16725603Skjc		 * must add atm_pseudohdr to data
16825603Skjc		 */
16925603Skjc		sz = sizeof(atmdst);
17025603Skjc		atm_flags = ATM_PH_FLAGS(&atmdst);
17125603Skjc		if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */
172111119Simp		M_PREPEND(m, sz, M_DONTWAIT);
17325603Skjc		if (m == 0)
17425603Skjc			senderr(ENOBUFS);
17525603Skjc		ad = mtod(m, struct atm_pseudohdr *);
17625603Skjc		*ad = atmdst;
17725603Skjc		if (atm_flags & ATM_PH_LLCSNAP) {
17825603Skjc			atmllc = (struct atmllc *)(ad + 1);
17937939Skjc			if (llc_hdr == NULL) {
18037939Skjc			        bcopy(ATMLLC_HDR, atmllc->llchdr,
18137939Skjc				      sizeof(atmllc->llchdr));
18237939Skjc				ATM_LLC_SETTYPE(atmllc, etype);
183112193Sharti					/* note: in host order */
18437939Skjc			}
18537939Skjc			else
18637939Skjc			        bcopy(llc_hdr, atmllc, sizeof(struct atmllc));
18725603Skjc		}
18825603Skjc	}
18925603Skjc
19025603Skjc	/*
19125603Skjc	 * Queue message on interface, and start output if interface
19225603Skjc	 * not yet active.
19325603Skjc	 */
19469152Sjlemon	if (! IF_HANDOFF(&ifp->if_snd, m, ifp))
19569152Sjlemon		return (ENOBUFS);
19625603Skjc	return (error);
19725603Skjc
19825603Skjcbad:
19925603Skjc	if (m)
20025603Skjc		m_freem(m);
20125603Skjc	return (error);
20225603Skjc}
20325603Skjc
20425603Skjc/*
20525603Skjc * Process a received ATM packet;
20625603Skjc * the packet is in the mbuf chain m.
20725603Skjc */
20825603Skjcvoid
20925603Skjcatm_input(ifp, ah, m, rxhand)
21025603Skjc	struct ifnet *ifp;
211111774Smdodd	struct atm_pseudohdr *ah;
21225603Skjc	struct mbuf *m;
21325603Skjc	void *rxhand;
21425603Skjc{
215111888Sjlemon	int isr;
21625603Skjc	u_int16_t etype = ETHERTYPE_IP; /* default */
21725603Skjc	int s;
21825603Skjc
21925603Skjc	if ((ifp->if_flags & IFF_UP) == 0) {
22025603Skjc		m_freem(m);
22125603Skjc		return;
22225603Skjc	}
223105576Srwatson#ifdef MAC
224105576Srwatson	mac_create_mbuf_from_ifnet(ifp, m);
225105576Srwatson#endif
22625603Skjc	ifp->if_ibytes += m->m_pkthdr.len;
22725603Skjc
22825603Skjc	if (rxhand) {
22925603Skjc#ifdef NATM
23037939Skjc		struct natmpcb *npcb = rxhand;
23137939Skjc		s = splimp();		/* in case 2 atm cards @ diff lvls */
23237939Skjc		npcb->npcb_inq++;	/* count # in queue */
23337939Skjc		splx(s);
234111888Sjlemon		isr = NETISR_NATM;
23537939Skjc		m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
23625603Skjc#else
23737939Skjc		printf("atm_input: NATM detected but not configured in kernel\n");
23837939Skjc		m_freem(m);
23937939Skjc		return;
24025603Skjc#endif
24125603Skjc	} else {
24237939Skjc		/*
24337939Skjc		 * handle LLC/SNAP header, if present
24437939Skjc		 */
24537939Skjc		if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
24637939Skjc			struct atmllc *alc;
24737939Skjc			if (m->m_len < sizeof(*alc) &&
24837939Skjc			    (m = m_pullup(m, sizeof(*alc))) == 0)
24937939Skjc				return; /* failed */
25037939Skjc			alc = mtod(m, struct atmllc *);
25137939Skjc			if (bcmp(alc, ATMLLC_HDR, 6)) {
25225603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
25337939Skjc				printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
25437939Skjc				       ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
25525603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
25637939Skjc				printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
25737939Skjc				       ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
25825603Skjc#endif
25937939Skjc				m_freem(m);
26037939Skjc				return;
26137939Skjc			}
26237939Skjc			etype = ATM_LLC_TYPE(alc);
26337939Skjc			m_adj(m, sizeof(*alc));
26437939Skjc		}
26525603Skjc
26637939Skjc		switch (etype) {
26725603Skjc#ifdef INET
26837939Skjc		case ETHERTYPE_IP:
269111888Sjlemon			isr = NETISR_IP;
27037939Skjc			break;
27125603Skjc#endif
27237939Skjc#ifdef INET6
27337939Skjc		case ETHERTYPE_IPV6:
274111888Sjlemon			isr = NETISR_IPV6;
27537939Skjc			break;
27637939Skjc#endif
27737939Skjc		default:
27837939Skjc			m_freem(m);
27937939Skjc			return;
28037939Skjc		}
28125603Skjc	}
282111888Sjlemon	netisr_dispatch(isr, m);
28325603Skjc}
28425603Skjc
28525603Skjc/*
28625603Skjc * Perform common duties while attaching to interface list
28725603Skjc */
28825603Skjcvoid
28925603Skjcatm_ifattach(ifp)
290111774Smdodd	struct ifnet *ifp;
29125603Skjc{
292111774Smdodd	struct ifaddr *ifa;
293111774Smdodd	struct sockaddr_dl *sdl;
29425603Skjc
29525603Skjc	ifp->if_type = IFT_ATM;
29625603Skjc	ifp->if_addrlen = 0;
29725603Skjc	ifp->if_hdrlen = 0;
29825603Skjc	ifp->if_mtu = ATMMTU;
29925603Skjc	ifp->if_output = atm_output;
300106939Ssam#if 0
301106939Ssam	ifp->if_input = atm_input;
302106939Ssam#endif
30346695Skjc	ifp->if_snd.ifq_maxlen = 50;	/* dummy */
30425603Skjc
30525603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
30672012Sphk	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
30737939Skjc#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
30871959Sphk	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
30971959Sphk	    ifa = TAILQ_NEXT(ifa, ifa_link))
31025603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
31125603Skjc	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
31225603Skjc#endif
31325603Skjc		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
31425603Skjc		    sdl->sdl_family == AF_LINK) {
31525603Skjc			sdl->sdl_type = IFT_ATM;
31625603Skjc			sdl->sdl_alen = ifp->if_addrlen;
31725603Skjc#ifdef notyet /* if using ATMARP, store hardware address using the next line */
31825603Skjc			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
31925603Skjc#endif
32025603Skjc			break;
32125603Skjc		}
32237939Skjc
32337939Skjc}
324