if_atmsubr.c revision 105576
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 105576 2002-10-20 22:20:48Z rwatson $
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)
9425603Skjc	register 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	 */
12025603Skjc	if ((rt = rt0) != NULL) {
12125603Skjc
12225603Skjc		if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */
12325603Skjc			if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL)
12425603Skjc				rt->rt_refcnt--;
12525603Skjc			else
12625603Skjc				senderr(EHOSTUNREACH);
12725603Skjc		}
12825603Skjc
12925603Skjc		if (rt->rt_flags & RTF_GATEWAY) {
13025603Skjc			if (rt->rt_gwroute == 0)
13125603Skjc				goto lookup;
13225603Skjc			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
13325603Skjc				rtfree(rt); rt = rt0;
13425603Skjc			lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0);
13525603Skjc				if ((rt = rt->rt_gwroute) == 0)
13625603Skjc					senderr(EHOSTUNREACH);
13725603Skjc			}
13825603Skjc		}
13925603Skjc
14025603Skjc		/* XXX: put RTF_REJECT code here if doing ATMARP */
14125603Skjc
14225603Skjc	}
14325603Skjc
14425603Skjc	/*
14525603Skjc	 * check for non-native ATM traffic   (dst != NULL)
14625603Skjc	 */
14725603Skjc	if (dst) {
14825603Skjc		switch (dst->sa_family) {
14937939Skjc#if defined(INET) || defined(INET6)
15025603Skjc		case AF_INET:
15137939Skjc		case AF_INET6:
15246695Skjc			if (dst->sa_family == AF_INET6)
15346695Skjc			        etype = htons(ETHERTYPE_IPV6);
15446695Skjc			else
15546695Skjc			        etype = htons(ETHERTYPE_IP);
15625603Skjc			if (!atmresolve(rt, m, dst, &atmdst)) {
15725603Skjc				m = NULL;
15825603Skjc				/* XXX: atmresolve already free'd it */
15925603Skjc				senderr(EHOSTUNREACH);
16025603Skjc				/* XXX: put ATMARP stuff here */
16125603Skjc				/* XXX: watch who frees m on failure */
16225603Skjc			}
16325603Skjc			break;
16437939Skjc#endif /* INET || INET6 */
16525603Skjc
16637939Skjc		case AF_UNSPEC:
16737939Skjc			/*
16846695Skjc			 * XXX: bpfwrite. assuming dst contains 12 bytes
16946695Skjc			 * (atm pseudo header (4) + LLC/SNAP (8))
17037939Skjc			 */
17137939Skjc			bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
17237939Skjc			llc_hdr = (struct atmllc *)(dst->sa_data + sizeof(atmdst));
17337939Skjc			break;
17437939Skjc
17525603Skjc		default:
17625603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
17725603Skjc			printf("%s: can't handle af%d\n", ifp->if_xname,
17825603Skjc			    dst->sa_family);
17925603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
18025603Skjc			printf("%s%d: can't handle af%d\n", ifp->if_name,
18125603Skjc			    ifp->if_unit, dst->sa_family);
18225603Skjc#endif
18325603Skjc			senderr(EAFNOSUPPORT);
18425603Skjc		}
18525603Skjc
18625603Skjc		/*
18725603Skjc		 * must add atm_pseudohdr to data
18825603Skjc		 */
18925603Skjc		sz = sizeof(atmdst);
19025603Skjc		atm_flags = ATM_PH_FLAGS(&atmdst);
19125603Skjc		if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */
19225603Skjc		M_PREPEND(m, sz, M_DONTWAIT);
19325603Skjc		if (m == 0)
19425603Skjc			senderr(ENOBUFS);
19525603Skjc		ad = mtod(m, struct atm_pseudohdr *);
19625603Skjc		*ad = atmdst;
19725603Skjc		if (atm_flags & ATM_PH_LLCSNAP) {
19825603Skjc			atmllc = (struct atmllc *)(ad + 1);
19937939Skjc			if (llc_hdr == NULL) {
20037939Skjc			        bcopy(ATMLLC_HDR, atmllc->llchdr,
20137939Skjc				      sizeof(atmllc->llchdr));
20237939Skjc				ATM_LLC_SETTYPE(atmllc, etype);
20325603Skjc					/* note: already in network order */
20437939Skjc			}
20537939Skjc			else
20637939Skjc			        bcopy(llc_hdr, atmllc, sizeof(struct atmllc));
20725603Skjc		}
20825603Skjc	}
20925603Skjc
21025603Skjc	/*
21125603Skjc	 * Queue message on interface, and start output if interface
21225603Skjc	 * not yet active.
21325603Skjc	 */
21469152Sjlemon	if (! IF_HANDOFF(&ifp->if_snd, m, ifp))
21569152Sjlemon		return (ENOBUFS);
21625603Skjc	return (error);
21725603Skjc
21825603Skjcbad:
21925603Skjc	if (m)
22025603Skjc		m_freem(m);
22125603Skjc	return (error);
22225603Skjc}
22325603Skjc
22425603Skjc/*
22525603Skjc * Process a received ATM packet;
22625603Skjc * the packet is in the mbuf chain m.
22725603Skjc */
22825603Skjcvoid
22925603Skjcatm_input(ifp, ah, m, rxhand)
23025603Skjc	struct ifnet *ifp;
23125603Skjc	register struct atm_pseudohdr *ah;
23225603Skjc	struct mbuf *m;
23325603Skjc	void *rxhand;
23425603Skjc{
23525603Skjc	register struct ifqueue *inq;
23625603Skjc	u_int16_t etype = ETHERTYPE_IP; /* default */
23725603Skjc	int s;
23825603Skjc
23925603Skjc	if ((ifp->if_flags & IFF_UP) == 0) {
24025603Skjc		m_freem(m);
24125603Skjc		return;
24225603Skjc	}
243105576Srwatson#ifdef MAC
244105576Srwatson	mac_create_mbuf_from_ifnet(ifp, m);
245105576Srwatson#endif
24625603Skjc	ifp->if_ibytes += m->m_pkthdr.len;
24725603Skjc
24825603Skjc	if (rxhand) {
24925603Skjc#ifdef NATM
25037939Skjc		struct natmpcb *npcb = rxhand;
25137939Skjc		s = splimp();		/* in case 2 atm cards @ diff lvls */
25237939Skjc		npcb->npcb_inq++;	/* count # in queue */
25337939Skjc		splx(s);
25437939Skjc		schednetisr(NETISR_NATM);
25537939Skjc		inq = &natmintrq;
25637939Skjc		m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
25725603Skjc#else
25837939Skjc		printf("atm_input: NATM detected but not configured in kernel\n");
25937939Skjc		m_freem(m);
26037939Skjc		return;
26125603Skjc#endif
26225603Skjc	} else {
26337939Skjc		/*
26437939Skjc		 * handle LLC/SNAP header, if present
26537939Skjc		 */
26637939Skjc		if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
26737939Skjc			struct atmllc *alc;
26837939Skjc			if (m->m_len < sizeof(*alc) &&
26937939Skjc			    (m = m_pullup(m, sizeof(*alc))) == 0)
27037939Skjc				return; /* failed */
27137939Skjc			alc = mtod(m, struct atmllc *);
27237939Skjc			if (bcmp(alc, ATMLLC_HDR, 6)) {
27325603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
27437939Skjc				printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
27537939Skjc				       ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
27625603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
27737939Skjc				printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
27837939Skjc				       ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
27925603Skjc#endif
28037939Skjc				m_freem(m);
28137939Skjc				return;
28237939Skjc			}
28337939Skjc			etype = ATM_LLC_TYPE(alc);
28437939Skjc			m_adj(m, sizeof(*alc));
28537939Skjc		}
28625603Skjc
28737939Skjc		switch (etype) {
28825603Skjc#ifdef INET
28937939Skjc		case ETHERTYPE_IP:
29037939Skjc			schednetisr(NETISR_IP);
29137939Skjc			inq = &ipintrq;
29237939Skjc			break;
29325603Skjc#endif
29437939Skjc#ifdef INET6
29537939Skjc		case ETHERTYPE_IPV6:
29637939Skjc			schednetisr(NETISR_IPV6);
29737939Skjc			inq = &ip6intrq;
29837939Skjc			break;
29937939Skjc#endif
30037939Skjc		default:
30137939Skjc			m_freem(m);
30237939Skjc			return;
30337939Skjc		}
30425603Skjc	}
30525603Skjc
30669152Sjlemon	(void) IF_HANDOFF(inq, m, NULL);
30725603Skjc}
30825603Skjc
30925603Skjc/*
31025603Skjc * Perform common duties while attaching to interface list
31125603Skjc */
31225603Skjcvoid
31325603Skjcatm_ifattach(ifp)
31425603Skjc	register struct ifnet *ifp;
31525603Skjc{
31625603Skjc	register struct ifaddr *ifa;
31725603Skjc	register struct sockaddr_dl *sdl;
31825603Skjc
31925603Skjc	ifp->if_type = IFT_ATM;
32025603Skjc	ifp->if_addrlen = 0;
32125603Skjc	ifp->if_hdrlen = 0;
32225603Skjc	ifp->if_mtu = ATMMTU;
32325603Skjc	ifp->if_output = atm_output;
32446695Skjc	ifp->if_snd.ifq_maxlen = 50;	/* dummy */
32525603Skjc
32625603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
32772012Sphk	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
32837939Skjc#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
32971959Sphk	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
33071959Sphk	    ifa = TAILQ_NEXT(ifa, ifa_link))
33125603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
33225603Skjc	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
33325603Skjc#endif
33425603Skjc		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
33525603Skjc		    sdl->sdl_family == AF_LINK) {
33625603Skjc			sdl->sdl_type = IFT_ATM;
33725603Skjc			sdl->sdl_alen = ifp->if_addrlen;
33825603Skjc#ifdef notyet /* if using ATMARP, store hardware address using the next line */
33925603Skjc			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
34025603Skjc#endif
34125603Skjc			break;
34225603Skjc		}
34337939Skjc
34437939Skjc}
345