if_atmsubr.c revision 37939
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"
4032925Seivind#include "opt_natm.h"
4132350Seivind
4225603Skjc#include <sys/param.h>
4325603Skjc#include <sys/systm.h>
4425603Skjc#include <sys/mbuf.h>
4525603Skjc#include <sys/socket.h>
4637939Skjc#include <sys/sockio.h>
4737939Skjc#include <sys/malloc.h>
4837939Skjc#include <sys/errno.h>
4925603Skjc
5025603Skjc#include <net/if.h>
5125603Skjc#include <net/netisr.h>
5225603Skjc#include <net/route.h>
5325603Skjc#include <net/if_dl.h>
5425603Skjc#include <net/if_types.h>
5525603Skjc#include <net/if_atm.h>
5625603Skjc
5725603Skjc#include <netinet/in.h>
5825603Skjc#include <netinet/if_atm.h>
5925603Skjc#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
6037939Skjc#if defined(INET) || defined(INET6)
6125603Skjc#include <netinet/in_var.h>
6225603Skjc#endif
6325603Skjc#ifdef NATM
6425603Skjc#include <netnatm/natm.h>
6525603Skjc#endif
6625603Skjc
6737939Skjc#ifndef ETHERTYPE_IPV6
6837939Skjc#define ETHERTYPE_IPV6	0x86dd
6937939Skjc#endif
7025603Skjc
7125603Skjc#define senderr(e) { error = (e); goto bad;}
7225603Skjc
7325603Skjc/*
7425603Skjc * atm_output: ATM output routine
7525603Skjc *   inputs:
7625603Skjc *     "ifp" = ATM interface to output to
7725603Skjc *     "m0" = the packet to output
7825603Skjc *     "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
7925603Skjc *     "rt0" = the route to use
8025603Skjc *   returns: error code   [0 == ok]
8125603Skjc *
8225603Skjc *   note: special semantic: if (dst == NULL) then we assume "m" already
8325603Skjc *		has an atm_pseudohdr on it and just send it directly.
8425603Skjc *		[for native mode ATM output]   if dst is null, then
8525603Skjc *		rt0 must also be NULL.
8625603Skjc */
8725603Skjc
8825603Skjcint
8925603Skjcatm_output(ifp, m0, dst, rt0)
9025603Skjc	register struct ifnet *ifp;
9125603Skjc	struct mbuf *m0;
9225603Skjc	struct sockaddr *dst;
9325603Skjc	struct rtentry *rt0;
9425603Skjc{
9525603Skjc	u_int16_t etype = 0;			/* if using LLC/SNAP */
9625603Skjc	int s, error = 0, sz;
9725603Skjc	struct atm_pseudohdr atmdst, *ad;
9825603Skjc	register struct mbuf *m = m0;
9925603Skjc	register struct rtentry *rt;
10025603Skjc	struct atmllc *atmllc;
10137939Skjc	struct atmllc *llc_hdr = NULL;
10225603Skjc	u_int32_t atm_flags;
10325603Skjc
10425603Skjc	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
10525603Skjc		senderr(ENETDOWN);
10625603Skjc
10725603Skjc	/*
10825603Skjc	 * check route
10925603Skjc	 */
11025603Skjc	if ((rt = rt0) != NULL) {
11125603Skjc
11225603Skjc		if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */
11325603Skjc			if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL)
11425603Skjc				rt->rt_refcnt--;
11525603Skjc			else
11625603Skjc				senderr(EHOSTUNREACH);
11725603Skjc		}
11825603Skjc
11925603Skjc		if (rt->rt_flags & RTF_GATEWAY) {
12025603Skjc			if (rt->rt_gwroute == 0)
12125603Skjc				goto lookup;
12225603Skjc			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
12325603Skjc				rtfree(rt); rt = rt0;
12425603Skjc			lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0);
12525603Skjc				if ((rt = rt->rt_gwroute) == 0)
12625603Skjc					senderr(EHOSTUNREACH);
12725603Skjc			}
12825603Skjc		}
12925603Skjc
13025603Skjc		/* XXX: put RTF_REJECT code here if doing ATMARP */
13125603Skjc
13225603Skjc	}
13325603Skjc
13425603Skjc	/*
13525603Skjc	 * check for non-native ATM traffic   (dst != NULL)
13625603Skjc	 */
13725603Skjc	if (dst) {
13825603Skjc		switch (dst->sa_family) {
13937939Skjc#if defined(INET) || defined(INET6)
14025603Skjc		case AF_INET:
14137939Skjc		case AF_INET6:
14225603Skjc			if (!atmresolve(rt, m, dst, &atmdst)) {
14325603Skjc				m = NULL;
14425603Skjc				/* XXX: atmresolve already free'd it */
14525603Skjc				senderr(EHOSTUNREACH);
14625603Skjc				/* XXX: put ATMARP stuff here */
14725603Skjc				/* XXX: watch who frees m on failure */
14825603Skjc			}
14937939Skjc			if (dst->sa_family == AF_INET6)
15037939Skjc			        etype = htons(ETHERTYPE_IPV6);
15137939Skjc			else
15237939Skjc			        etype = htons(ETHERTYPE_IP);
15325603Skjc			break;
15437939Skjc#endif /* INET || INET6 */
15525603Skjc
15637939Skjc		case AF_UNSPEC:
15737939Skjc			/*
15837939Skjc			 * XXX: bpfwrite or output from a pvc shadow if.
15937939Skjc			 * assuming dst contains 12 bytes (atm pseudo
16037939Skjc			 * header (4) + LLC/SNAP (8))
16137939Skjc			 */
16237939Skjc			bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
16337939Skjc			llc_hdr = (struct atmllc *)(dst->sa_data + sizeof(atmdst));
16437939Skjc			break;
16537939Skjc
16625603Skjc		default:
16725603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
16825603Skjc			printf("%s: can't handle af%d\n", ifp->if_xname,
16925603Skjc			    dst->sa_family);
17025603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
17125603Skjc			printf("%s%d: can't handle af%d\n", ifp->if_name,
17225603Skjc			    ifp->if_unit, dst->sa_family);
17325603Skjc#endif
17425603Skjc			senderr(EAFNOSUPPORT);
17525603Skjc		}
17625603Skjc
17725603Skjc		/*
17825603Skjc		 * must add atm_pseudohdr to data
17925603Skjc		 */
18025603Skjc		sz = sizeof(atmdst);
18125603Skjc		atm_flags = ATM_PH_FLAGS(&atmdst);
18225603Skjc		if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */
18325603Skjc		M_PREPEND(m, sz, M_DONTWAIT);
18425603Skjc		if (m == 0)
18525603Skjc			senderr(ENOBUFS);
18625603Skjc		ad = mtod(m, struct atm_pseudohdr *);
18725603Skjc		*ad = atmdst;
18825603Skjc		if (atm_flags & ATM_PH_LLCSNAP) {
18925603Skjc			atmllc = (struct atmllc *)(ad + 1);
19037939Skjc			if (llc_hdr == NULL) {
19137939Skjc			        bcopy(ATMLLC_HDR, atmllc->llchdr,
19237939Skjc				      sizeof(atmllc->llchdr));
19337939Skjc				ATM_LLC_SETTYPE(atmllc, etype);
19425603Skjc					/* note: already in network order */
19537939Skjc			}
19637939Skjc			else
19737939Skjc			        bcopy(llc_hdr, atmllc, sizeof(struct atmllc));
19825603Skjc		}
19925603Skjc	}
20025603Skjc
20125603Skjc	/*
20225603Skjc	 * Queue message on interface, and start output if interface
20325603Skjc	 * not yet active.
20425603Skjc	 */
20525603Skjc	s = splimp();
20625603Skjc	if (IF_QFULL(&ifp->if_snd)) {
20725603Skjc		IF_DROP(&ifp->if_snd);
20825603Skjc		splx(s);
20925603Skjc		senderr(ENOBUFS);
21025603Skjc	}
21125603Skjc	ifp->if_obytes += m->m_pkthdr.len;
21225603Skjc	IF_ENQUEUE(&ifp->if_snd, m);
21325603Skjc	if ((ifp->if_flags & IFF_OACTIVE) == 0)
21425603Skjc		(*ifp->if_start)(ifp);
21525603Skjc	splx(s);
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	}
24325603Skjc	ifp->if_ibytes += m->m_pkthdr.len;
24425603Skjc
24537939Skjc#ifdef ATM_PVCEXT
24637939Skjc	if (ATM_PH_FLAGS(ah) & ATM_PH_PVCSIF) {
24725603Skjc		/*
24837939Skjc		 * when PVC shadow interface is used, pointer to
24937939Skjc		 * the shadow interface is passed as rxhand.
25037939Skjc		 * override the receive interface of the packet.
25125603Skjc		 */
25237939Skjc		m->m_pkthdr.rcvif = (struct ifnet *)rxhand;
25337939Skjc		rxhand = NULL;
25425603Skjc	}
25537939Skjc#endif /*  ATM_PVCEXT */
25625603Skjc
25725603Skjc	if (rxhand) {
25825603Skjc#ifdef NATM
25937939Skjc		struct natmpcb *npcb = rxhand;
26037939Skjc		s = splimp();		/* in case 2 atm cards @ diff lvls */
26137939Skjc		npcb->npcb_inq++;	/* count # in queue */
26237939Skjc		splx(s);
26337939Skjc		schednetisr(NETISR_NATM);
26437939Skjc		inq = &natmintrq;
26537939Skjc		m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
26625603Skjc#else
26737939Skjc		printf("atm_input: NATM detected but not configured in kernel\n");
26837939Skjc		m_freem(m);
26937939Skjc		return;
27025603Skjc#endif
27125603Skjc	} else {
27237939Skjc		/*
27337939Skjc		 * handle LLC/SNAP header, if present
27437939Skjc		 */
27537939Skjc		if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
27637939Skjc			struct atmllc *alc;
27737939Skjc			if (m->m_len < sizeof(*alc) &&
27837939Skjc			    (m = m_pullup(m, sizeof(*alc))) == 0)
27937939Skjc				return; /* failed */
28037939Skjc			alc = mtod(m, struct atmllc *);
28137939Skjc			if (bcmp(alc, ATMLLC_HDR, 6)) {
28225603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
28337939Skjc				printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
28437939Skjc				       ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
28525603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
28637939Skjc				printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
28737939Skjc				       ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
28825603Skjc#endif
28937939Skjc				m_freem(m);
29037939Skjc				return;
29137939Skjc			}
29237939Skjc			etype = ATM_LLC_TYPE(alc);
29337939Skjc			m_adj(m, sizeof(*alc));
29437939Skjc		}
29525603Skjc
29637939Skjc		switch (etype) {
29725603Skjc#ifdef INET
29837939Skjc		case ETHERTYPE_IP:
29937939Skjc			schednetisr(NETISR_IP);
30037939Skjc			inq = &ipintrq;
30137939Skjc			break;
30225603Skjc#endif
30337939Skjc#ifdef INET6
30437939Skjc		case ETHERTYPE_IPV6:
30537939Skjc			schednetisr(NETISR_IPV6);
30637939Skjc			inq = &ip6intrq;
30737939Skjc			break;
30837939Skjc#endif
30937939Skjc		default:
31037939Skjc			m_freem(m);
31137939Skjc			return;
31237939Skjc		}
31325603Skjc	}
31425603Skjc
31525603Skjc	s = splimp();
31625603Skjc	if (IF_QFULL(inq)) {
31725603Skjc		IF_DROP(inq);
31825603Skjc		m_freem(m);
31925603Skjc	} else
32025603Skjc		IF_ENQUEUE(inq, m);
32125603Skjc	splx(s);
32225603Skjc}
32325603Skjc
32425603Skjc/*
32525603Skjc * Perform common duties while attaching to interface list
32625603Skjc */
32725603Skjcvoid
32825603Skjcatm_ifattach(ifp)
32925603Skjc	register struct ifnet *ifp;
33025603Skjc{
33125603Skjc	register struct ifaddr *ifa;
33225603Skjc	register struct sockaddr_dl *sdl;
33325603Skjc
33425603Skjc	ifp->if_type = IFT_ATM;
33525603Skjc	ifp->if_addrlen = 0;
33625603Skjc	ifp->if_hdrlen = 0;
33725603Skjc	ifp->if_mtu = ATMMTU;
33825603Skjc	ifp->if_output = atm_output;
33925603Skjc
34025603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
34125603Skjc	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
34225603Skjc	    ifa = ifa->ifa_list.tqe_next)
34337939Skjc#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
34425603Skjc	for (ifa = ifp->if_addrhead.tqh_first; ifa;
34525603Skjc	    ifa = ifa->ifa_link.tqe_next)
34625603Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
34725603Skjc	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
34825603Skjc#endif
34925603Skjc		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
35025603Skjc		    sdl->sdl_family == AF_LINK) {
35125603Skjc			sdl->sdl_type = IFT_ATM;
35225603Skjc			sdl->sdl_alen = ifp->if_addrlen;
35325603Skjc#ifdef notyet /* if using ATMARP, store hardware address using the next line */
35425603Skjc			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
35525603Skjc#endif
35625603Skjc			break;
35725603Skjc		}
35837939Skjc
35937939Skjc}
36037939Skjc
36137939Skjc#ifdef ATM_PVCEXT
36237939Skjc/*
36337939Skjc * ATM PVC shadow interface: a trick to assign a shadow interface
36437939Skjc * to a PVC.
36537939Skjc * with shadow interface, each PVC looks like an individual
36637939Skjc * Point-to-Point interface.
36737939Skjc * as oposed to the NBMA model, a shadow interface is inherently
36837939Skjc * multicast capable (no LANE/MARS required).
36937939Skjc */
37037939Skjcstruct pvcsif {
37137939Skjc	struct ifnet sif_shadow;	/* shadow ifnet structure per pvc */
37237939Skjc	struct atm_pseudohdr sif_aph;	/* flags + vpi:vci */
37337939Skjc	struct ifnet *sif_ifp;		/* pointer to the genuine interface */
37437939Skjc};
37537939Skjc
37637939Skjcstatic int pvc_output __P((struct ifnet *, struct mbuf *,
37737939Skjc			   struct sockaddr *, struct rtentry *));
37837939Skjcstatic int pvc_ioctl __P((struct ifnet *, u_long, caddr_t));
37937939Skjc
38037939Skjc/*
38137939Skjc * create and attach per pvc shadow interface
38237939Skjc * (currently detach is not supported)
38337939Skjc */
38437939Skjcstatic int pvc_number = 0;
38537939Skjc
38637939Skjcstruct ifnet *
38737939Skjcpvc_attach(ifp)
38837939Skjc	struct ifnet *ifp;
38937939Skjc{
39037939Skjc	struct pvcsif *pvcsif;
39137939Skjc	struct ifnet *shadow;
39237939Skjc	struct ifaddr *ifa;
39337939Skjc	struct sockaddr_dl *sdl;
39437939Skjc	int s;
39537939Skjc
39637939Skjc	MALLOC(pvcsif, struct pvcsif *, sizeof(struct pvcsif),
39737939Skjc	       M_DEVBUF, M_WAITOK);
39837939Skjc	bzero(pvcsif, sizeof(struct pvcsif));
39937939Skjc
40037939Skjc	pvcsif->sif_ifp = ifp;
40137939Skjc	shadow = &pvcsif->sif_shadow;
40237939Skjc
40337939Skjc	shadow->if_name = "pvc";
40437939Skjc	shadow->if_unit = pvc_number++;
40537939Skjc	shadow->if_flags = ifp->if_flags | (IFF_POINTOPOINT | IFF_MULTICAST);
40637939Skjc	shadow->if_ioctl = pvc_ioctl;
40737939Skjc	shadow->if_output = pvc_output;
40837939Skjc	shadow->if_start = NULL;
40937939Skjc	shadow->if_mtu = ifp->if_mtu;
41037939Skjc	shadow->if_type = ifp->if_type;
41137939Skjc	shadow->if_addrlen = ifp->if_addrlen;
41237939Skjc	shadow->if_hdrlen = ifp->if_hdrlen;
41337939Skjc	shadow->if_softc = pvcsif;
41437939Skjc	shadow->if_snd.ifq_maxlen = 50;	/* dummy */
41537939Skjc
41637939Skjc	s = splimp();
41737939Skjc	if_attach(shadow);
41837939Skjc
41925603Skjc#if defined(__NetBSD__) || defined(__OpenBSD__)
42037939Skjc	for (ifa = shadow->if_addrlist.tqh_first; ifa != 0;
42137939Skjc	     ifa = ifa->ifa_list.tqe_next)
42237939Skjc#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
42337939Skjc	for (ifa = shadow->if_addrhead.tqh_first; ifa;
42437939Skjc	     ifa = ifa->ifa_link.tqe_next)
42537939Skjc#elif defined(__FreeBSD__) || defined(__bsdi__)
42637939Skjc	for (ifa = shadow->if_addrlist; ifa; ifa = ifa->ifa_next)
42725603Skjc#endif
42837939Skjc		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
42937939Skjc		    sdl->sdl_family == AF_LINK) {
43037939Skjc			sdl->sdl_type = IFT_ATM;
43137939Skjc			sdl->sdl_alen = shadow->if_addrlen;
43237939Skjc			break;
43337939Skjc		}
43437939Skjc	splx(s);
43537939Skjc
43637939Skjc	return (shadow);
43725603Skjc}
43837939Skjc
43937939Skjc/*
44037939Skjc * pvc_output relays the packet to atm_output along with vpi:vci info.
44137939Skjc */
44237939Skjcstatic int
44337939Skjcpvc_output(shadow, m, dst, rt)
44437939Skjc	struct ifnet *shadow;
44537939Skjc	struct mbuf *m;
44637939Skjc	struct sockaddr *dst;
44737939Skjc	struct rtentry *rt;
44837939Skjc{
44937939Skjc	struct pvcsif *pvcsif;
45037939Skjc	struct sockaddr dst_addr;
45137939Skjc	struct atmllc *atmllc;
45237939Skjc	u_int16_t etype = 0;
45337939Skjc	int error = 0;
45437939Skjc
45537939Skjc	if ((shadow->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
45637939Skjc		senderr(ENETDOWN);
45737939Skjc
45837939Skjc	pvcsif = shadow->if_softc;
45937939Skjc	if (ATM_PH_VCI(&pvcsif->sif_aph) == 0)
46037939Skjc		senderr(ENETDOWN);
46137939Skjc
46237939Skjc	/*
46337939Skjc	 * create a dummy sockaddr: (using bpfwrite interface)
46437939Skjc	 * put atm pseudo header and llc/snap into sa_data (12 bytes)
46537939Skjc	 * and mark it as AF_UNSPEC.
46637939Skjc	 */
46737939Skjc	if (dst) {
46837939Skjc		switch (dst->sa_family) {
46937939Skjc#if defined(INET) || defined(INET6)
47037939Skjc		case AF_INET:
47137939Skjc		case AF_INET6:
47237939Skjc			if (dst->sa_family == AF_INET6)
47337939Skjc				etype = htons(ETHERTYPE_IPV6);
47437939Skjc			else
47537939Skjc				etype = htons(ETHERTYPE_IP);
47637939Skjc			break;
47737939Skjc#endif
47837939Skjc
47937939Skjc		default:
48037939Skjc			printf("%s%d: can't handle af%d\n", shadow->if_name,
48137939Skjc			       shadow->if_unit, dst->sa_family);
48237939Skjc			senderr(EAFNOSUPPORT);
48337939Skjc		}
48437939Skjc	}
48537939Skjc
48637939Skjc	dst_addr.sa_family = AF_UNSPEC;
48737939Skjc	bcopy(&pvcsif->sif_aph, dst_addr.sa_data,
48837939Skjc	      sizeof(struct atm_pseudohdr));
48937939Skjc	atmllc = (struct atmllc *)
49037939Skjc		(dst_addr.sa_data + sizeof(struct atm_pseudohdr));
49137939Skjc	bcopy(ATMLLC_HDR, atmllc->llchdr,  sizeof(atmllc->llchdr));
49237939Skjc	ATM_LLC_SETTYPE(atmllc, etype);  /* note: already in network order */
49337939Skjc
49437939Skjc	return atm_output(pvcsif->sif_ifp, m, &dst_addr, rt);
49537939Skjc
49637939Skjcbad:
49737939Skjc	if (m)
49837939Skjc		m_freem(m);
49937939Skjc	return (error);
50037939Skjc}
50137939Skjc
50237939Skjcstatic int
50337939Skjcpvc_ioctl(shadow, cmd, data)
50437939Skjc	struct ifnet *shadow;
50537939Skjc	u_long cmd;
50637939Skjc	caddr_t data;
50737939Skjc{
50837939Skjc	struct ifnet *ifp;
50937939Skjc	struct pvcsif *pvcsif;
51037939Skjc	struct ifreq *ifr = (struct ifreq *) data;
51137939Skjc	void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *) = NULL;
51237939Skjc	int error = 0;
51337939Skjc
51437939Skjc	pvcsif = (struct pvcsif *)shadow->if_softc;
51537939Skjc	ifp = pvcsif->sif_ifp;
51637939Skjc	if (ifp == 0 || ifp->if_ioctl == 0)
51737939Skjc		return (EOPNOTSUPP);
51837939Skjc
51937939Skjc	/*
52037939Skjc	 * pre process
52137939Skjc	 */
52237939Skjc	switch (cmd) {
52337939Skjc	case SIOCGPVCSIF:
52437939Skjc		sprintf(ifr->ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
52537939Skjc		return (0);
52637939Skjc
52737939Skjc	case SIOCGPVCTX:
52837939Skjc		do {
52937939Skjc			struct pvctxreq *pvcreq = (struct pvctxreq *)data;
53037939Skjc
53137939Skjc			sprintf(pvcreq->pvc_ifname, "%s%d",
53237939Skjc				ifp->if_name, ifp->if_unit);
53337939Skjc			pvcreq->pvc_aph = pvcsif->sif_aph;
53437939Skjc		} while (0);
53537939Skjc		break;
53637939Skjc
53737939Skjc	case SIOCADDMULTI:
53837939Skjc	case SIOCDELMULTI:
53937939Skjc		if (ifr == 0)
54037939Skjc			return (EAFNOSUPPORT);	/* XXX */
54137939Skjc		switch (ifr->ifr_addr.sa_family) {
54237939Skjc#ifdef INET
54337939Skjc		case AF_INET:
54437939Skjc			return (0);
54537939Skjc#endif
54637939Skjc#ifdef INET6
54737939Skjc		case AF_INET6:
54837939Skjc			return (0);
54937939Skjc#endif
55037939Skjc		default:
55137939Skjc			return (EAFNOSUPPORT);
55237939Skjc		}
55337939Skjc		break;
55437939Skjc	case SIOCSIFADDR:
55537939Skjc		if (ifp->if_flags & IFF_UP) {
55637939Skjc			/* real if is already up */
55737939Skjc			shadow->if_flags = ifp->if_flags |
55837939Skjc				(IFF_POINTOPOINT|IFF_MULTICAST);
55937939Skjc			return (0);
56037939Skjc		}
56137939Skjc		/*
56237939Skjc		 * XXX: save the rtrequest field since the atm driver
56337939Skjc		 * overwrites this field.
56437939Skjc		 */
56537939Skjc		ifa_rtrequest = ((struct ifaddr *)data)->ifa_rtrequest;
56637939Skjc		break;
56737939Skjc
56837939Skjc	case SIOCSIFFLAGS:
56937939Skjc		if ((shadow->if_flags & IFF_UP) == 0) {
57037939Skjc			/*
57137939Skjc			 * interface down. don't pass this to
57237939Skjc			 * the real interface.
57337939Skjc			 */
57437939Skjc			return (0);
57537939Skjc		}
57637939Skjc		if (shadow->if_flags & IFF_UP) {
57737939Skjc			/*
57837939Skjc			 * interface up. if the real if is already up,
57937939Skjc			 * nothing to do.
58037939Skjc			 */
58137939Skjc			if (ifp->if_flags & IFF_UP) {
58237939Skjc				shadow->if_flags = ifp->if_flags |
58337939Skjc					(IFF_POINTOPOINT|IFF_MULTICAST);
58437939Skjc				return (0);
58537939Skjc			}
58637939Skjc		}
58737939Skjc		break;
58837939Skjc	}
58937939Skjc
59037939Skjc	/*
59137939Skjc	 * pass the ioctl to the genuine interface
59237939Skjc	 */
59337939Skjc	error = (*ifp->if_ioctl)(ifp, cmd, data);
59437939Skjc
59537939Skjc	/*
59637939Skjc	 * post process
59737939Skjc	 */
59837939Skjc	switch (cmd) {
59937939Skjc	case SIOCSIFMTU:
60037939Skjc		shadow->if_mtu = ifp->if_mtu;
60137939Skjc		break;
60237939Skjc	case SIOCSIFADDR:
60337939Skjc		/* restore rtrequest */
60437939Skjc		((struct ifaddr *)data)->ifa_rtrequest = ifa_rtrequest;
60537939Skjc		/* fall into... */
60637939Skjc	case SIOCSIFFLAGS:
60737939Skjc		/* update if_flags */
60837939Skjc		shadow->if_flags = ifp->if_flags
60937939Skjc			| (IFF_POINTOPOINT|IFF_MULTICAST);
61037939Skjc		break;
61137939Skjc	}
61237939Skjc
61337939Skjc	return (error);
61437939Skjc}
61537939Skjc
61637939Skjcint pvc_setaph(shadow, aph)
61737939Skjc	struct ifnet *shadow;
61837939Skjc	struct atm_pseudohdr *aph;
61937939Skjc{
62037939Skjc	struct pvcsif *pvcsif;
62137939Skjc
62237939Skjc	pvcsif = shadow->if_softc;
62337939Skjc	bcopy(aph, &pvcsif->sif_aph, sizeof(struct atm_pseudohdr));
62437939Skjc	return (0);
62537939Skjc}
62637939Skjc
62737939Skjc#endif /* ATM_PVCEXT */
628