]>
git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_atmsubr.c
eb7bdb7f5b0d04356fb92e8e5b6f99c55d287adb
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $ */
26 * Copyright (c) 1996 Charles D. Cranor and Washington University.
27 * All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by Charles D. Cranor and
40 * Washington University.
41 * 4. The name of the author may not be used to endorse or promote products
42 * derived from this software without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
45 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
47 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
48 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
49 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
53 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 #include <sys/param.h>
64 #include <sys/systm.h>
66 #include <sys/socket.h>
67 #include <sys/sockio.h>
68 #include <sys/malloc.h>
69 #include <sys/errno.h>
73 #include <net/netisr.h>
74 #include <net/route.h>
75 #include <net/if_dl.h>
76 #include <net/if_types.h>
77 #include <net/if_atm.h>
79 #include <netinet/in.h>
80 #include <netinet/if_atm.h>
81 #include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
82 #if defined(INET) || defined(INET6)
83 #include <netinet/in_var.h>
86 #include <netnatm/natm.h>
89 #ifndef ETHERTYPE_IPV6
90 #define ETHERTYPE_IPV6 0x86dd
93 #define senderr(e) { error = (e); goto bad;}
96 * atm_output: ATM output routine
98 * "ifp" = ATM interface to output to
99 * "m0" = the packet to output
100 * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
101 * "rt0" = the route to use
102 * returns: error code [0 == ok]
104 * note: special semantic: if (dst == NULL) then we assume "m" already
105 * has an atm_pseudohdr on it and just send it directly.
106 * [for native mode ATM output] if dst is null, then
107 * rt0 must also be NULL.
111 atm_output(ifp
, m0
, dst
, rt0
)
112 register struct ifnet
*ifp
;
114 struct sockaddr
*dst
;
117 u_int16_t etype
= 0; /* if using LLC/SNAP */
118 int s
, error
= 0, sz
;
119 struct atm_pseudohdr atmdst
, *ad
;
120 register struct mbuf
*m
= m0
;
121 register struct rtentry
*rt
;
122 struct atmllc
*atmllc
;
123 struct atmllc
*llc_hdr
= NULL
;
126 if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
))
132 if ((rt
= rt0
) != NULL
) {
134 if ((rt
->rt_flags
& RTF_UP
) == 0) { /* route went down! */
135 if ((rt0
= rt
= RTALLOC1(dst
, 0)) != NULL
)
138 senderr(EHOSTUNREACH
);
141 if (rt
->rt_flags
& RTF_GATEWAY
) {
142 if (rt
->rt_gwroute
== 0)
144 if (((rt
= rt
->rt_gwroute
)->rt_flags
& RTF_UP
) == 0) {
145 rtfree(rt
); rt
= rt0
;
146 lookup
: rt
->rt_gwroute
= RTALLOC1(rt
->rt_gateway
, 0);
147 if ((rt
= rt
->rt_gwroute
) == 0)
148 senderr(EHOSTUNREACH
);
152 /* XXX: put RTF_REJECT code here if doing ATMARP */
157 * check for non-native ATM traffic (dst != NULL)
160 switch (dst
->sa_family
) {
161 #if defined(INET) || defined(INET6)
164 if (!atmresolve(rt
, m
, dst
, &atmdst
)) {
166 /* XXX: atmresolve already free'd it */
167 senderr(EHOSTUNREACH
);
168 /* XXX: put ATMARP stuff here */
169 /* XXX: watch who frees m on failure */
171 if (dst
->sa_family
== AF_INET6
)
172 etype
= htons(ETHERTYPE_IPV6
);
174 etype
= htons(ETHERTYPE_IP
);
176 #endif /* INET || INET6 */
180 * XXX: bpfwrite or output from a pvc shadow if.
181 * assuming dst contains 12 bytes (atm pseudo
182 * header (4) + LLC/SNAP (8))
184 bcopy(dst
->sa_data
, &atmdst
, sizeof(atmdst
));
185 llc_hdr
= (struct atmllc
*)(dst
->sa_data
+ sizeof(atmdst
));
189 #if defined(__NetBSD__) || defined(__OpenBSD__)
190 printf("%s: can't handle af%d\n", ifp
->if_xname
,
192 #elif defined(__FreeBSD__) || defined(__bsdi__)
193 printf("%s%d: can't handle af%d\n", ifp
->if_name
,
194 ifp
->if_unit
, dst
->sa_family
);
196 senderr(EAFNOSUPPORT
);
200 * must add atm_pseudohdr to data
203 atm_flags
= ATM_PH_FLAGS(&atmdst
);
204 if (atm_flags
& ATM_PH_LLCSNAP
) sz
+= 8; /* sizeof snap == 8 */
205 M_PREPEND(m
, sz
, M_DONTWAIT
);
208 ad
= mtod(m
, struct atm_pseudohdr
*);
210 if (atm_flags
& ATM_PH_LLCSNAP
) {
211 atmllc
= (struct atmllc
*)(ad
+ 1);
212 if (llc_hdr
== NULL
) {
213 bcopy(ATMLLC_HDR
, atmllc
->llchdr
,
214 sizeof(atmllc
->llchdr
));
215 ATM_LLC_SETTYPE(atmllc
, etype
);
216 /* note: already in network order */
219 bcopy(llc_hdr
, atmllc
, sizeof(struct atmllc
));
224 * Queue message on interface, and start output if interface
228 if (IF_QFULL(&ifp
->if_snd
)) {
229 IF_DROP(&ifp
->if_snd
);
233 ifp
->if_obytes
+= m
->m_pkthdr
.len
;
234 IF_ENQUEUE(&ifp
->if_snd
, m
);
235 if ((ifp
->if_flags
& IFF_OACTIVE
) == 0)
236 (*ifp
->if_start
)(ifp
);
247 * Process a received ATM packet;
248 * the packet is in the mbuf chain m.
251 atm_input(ifp
, ah
, m
, rxhand
)
253 register struct atm_pseudohdr
*ah
;
257 register struct ifqueue
*inq
;
258 u_int16_t etype
= ETHERTYPE_IP
; /* default */
261 if ((ifp
->if_flags
& IFF_UP
) == 0) {
265 ifp
->if_ibytes
+= m
->m_pkthdr
.len
;
268 if (ATM_PH_FLAGS(ah
) & ATM_PH_PVCSIF
) {
270 * when PVC shadow interface is used, pointer to
271 * the shadow interface is passed as rxhand.
272 * override the receive interface of the packet.
274 m
->m_pkthdr
.rcvif
= (struct ifnet
*)rxhand
;
277 #endif /* ATM_PVCEXT */
281 struct natmpcb
*npcb
= rxhand
;
282 s
= splimp(); /* in case 2 atm cards @ diff lvls */
283 npcb
->npcb_inq
++; /* count # in queue */
285 schednetisr(NETISR_NATM
);
287 m
->m_pkthdr
.rcvif
= rxhand
; /* XXX: overload */
289 printf("atm_input: NATM detected but not configured in kernel\n");
295 * handle LLC/SNAP header, if present
297 if (ATM_PH_FLAGS(ah
) & ATM_PH_LLCSNAP
) {
299 if (m
->m_len
< sizeof(*alc
) &&
300 (m
= m_pullup(m
, sizeof(*alc
))) == 0)
302 alc
= mtod(m
, struct atmllc
*);
303 if (bcmp(alc
, ATMLLC_HDR
, 6)) {
304 #if defined(__NetBSD__) || defined(__OpenBSD__)
305 printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
306 ifp
->if_xname
, ATM_PH_VPI(ah
), ATM_PH_VCI(ah
));
307 #elif defined(__FreeBSD__) || defined(__bsdi__)
308 printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
309 ifp
->if_name
, ifp
->if_unit
, ATM_PH_VPI(ah
), ATM_PH_VCI(ah
));
314 etype
= ATM_LLC_TYPE(alc
);
315 m_adj(m
, sizeof(*alc
));
321 schednetisr(NETISR_IP
);
327 schednetisr(NETISR_IPV6
);
347 * Perform common duties while attaching to interface list
351 register struct ifnet
*ifp
;
353 register struct ifaddr
*ifa
;
354 register struct sockaddr_dl
*sdl
;
356 ifp
->if_type
= IFT_ATM
;
359 ifp
->if_mtu
= ATMMTU
;
360 ifp
->if_output
= atm_output
;
362 #if defined(__NetBSD__) || defined(__OpenBSD__)
363 for (ifa
= ifp
->if_addrlist
.tqh_first
; ifa
!= 0;
364 ifa
= ifa
->ifa_list
.tqe_next
)
365 #elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
366 for (ifa
= ifp
->if_addrhead
.tqh_first
; ifa
;
367 ifa
= ifa
->ifa_link
.tqe_next
)
368 #elif defined(__FreeBSD__) || defined(__bsdi__)
369 for (ifa
= ifp
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
371 if ((sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
) &&
372 sdl
->sdl_family
== AF_LINK
) {
373 sdl
->sdl_type
= IFT_ATM
;
374 sdl
->sdl_alen
= ifp
->if_addrlen
;
375 #ifdef notyet /* if using ATMARP, store hardware address using the next line */
376 bcopy(ifp
->hw_addr
, LLADDR(sdl
), ifp
->if_addrlen
);
385 * ATM PVC shadow interface: a trick to assign a shadow interface
387 * with shadow interface, each PVC looks like an individual
388 * Point-to-Point interface.
389 * as oposed to the NBMA model, a shadow interface is inherently
390 * multicast capable (no LANE/MARS required).
393 struct ifnet sif_shadow
; /* shadow ifnet structure per pvc */
394 struct atm_pseudohdr sif_aph
; /* flags + vpi:vci */
395 struct ifnet
*sif_ifp
; /* pointer to the genuine interface */
398 static int pvc_output
__P((struct ifnet
*, struct mbuf
*,
399 struct sockaddr
*, struct rtentry
*));
400 static int pvc_ioctl
__P((struct ifnet
*, u_long
, caddr_t
));
403 * create and attach per pvc shadow interface
404 * (currently detach is not supported)
406 static int pvc_number
= 0;
412 struct pvcsif
*pvcsif
;
413 struct ifnet
*shadow
;
415 struct sockaddr_dl
*sdl
;
418 MALLOC(pvcsif
, struct pvcsif
*, sizeof(struct pvcsif
),
420 bzero(pvcsif
, sizeof(struct pvcsif
));
422 pvcsif
->sif_ifp
= ifp
;
423 shadow
= &pvcsif
->sif_shadow
;
425 shadow
->if_name
= "pvc";
426 shadow
->if_family
= APPLE_IF_FAM_PVC
;
427 shadow
->if_unit
= pvc_number
++;
428 shadow
->if_flags
= ifp
->if_flags
| (IFF_POINTOPOINT
| IFF_MULTICAST
);
429 shadow
->if_ioctl
= pvc_ioctl
;
430 shadow
->if_output
= pvc_output
;
431 shadow
->if_start
= NULL
;
432 shadow
->if_mtu
= ifp
->if_mtu
;
433 shadow
->if_type
= ifp
->if_type
;
434 shadow
->if_addrlen
= ifp
->if_addrlen
;
435 shadow
->if_hdrlen
= ifp
->if_hdrlen
;
436 shadow
->if_softc
= pvcsif
;
437 shadow
->if_snd
.ifq_maxlen
= 50; /* dummy */
442 #if defined(__NetBSD__) || defined(__OpenBSD__)
443 for (ifa
= shadow
->if_addrlist
.tqh_first
; ifa
!= 0;
444 ifa
= ifa
->ifa_list
.tqe_next
)
445 #elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
446 for (ifa
= shadow
->if_addrhead
.tqh_first
; ifa
;
447 ifa
= ifa
->ifa_link
.tqe_next
)
448 #elif defined(__FreeBSD__) || defined(__bsdi__)
449 for (ifa
= shadow
->if_addrlist
; ifa
; ifa
= ifa
->ifa_next
)
451 if ((sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
) &&
452 sdl
->sdl_family
== AF_LINK
) {
453 sdl
->sdl_type
= IFT_ATM
;
454 sdl
->sdl_alen
= shadow
->if_addrlen
;
463 * pvc_output relays the packet to atm_output along with vpi:vci info.
466 pvc_output(shadow
, m
, dst
, rt
)
467 struct ifnet
*shadow
;
469 struct sockaddr
*dst
;
472 struct pvcsif
*pvcsif
;
473 struct sockaddr dst_addr
;
474 struct atmllc
*atmllc
;
478 if ((shadow
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
))
481 pvcsif
= shadow
->if_softc
;
482 if (ATM_PH_VCI(&pvcsif
->sif_aph
) == 0)
486 * create a dummy sockaddr: (using bpfwrite interface)
487 * put atm pseudo header and llc/snap into sa_data (12 bytes)
488 * and mark it as AF_UNSPEC.
491 switch (dst
->sa_family
) {
492 #if defined(INET) || defined(INET6)
495 if (dst
->sa_family
== AF_INET6
)
496 etype
= htons(ETHERTYPE_IPV6
);
498 etype
= htons(ETHERTYPE_IP
);
503 printf("%s%d: can't handle af%d\n", shadow
->if_name
,
504 shadow
->if_unit
, dst
->sa_family
);
505 senderr(EAFNOSUPPORT
);
509 dst_addr
.sa_family
= AF_UNSPEC
;
510 bcopy(&pvcsif
->sif_aph
, dst_addr
.sa_data
,
511 sizeof(struct atm_pseudohdr
));
512 atmllc
= (struct atmllc
*)
513 (dst_addr
.sa_data
+ sizeof(struct atm_pseudohdr
));
514 bcopy(ATMLLC_HDR
, atmllc
->llchdr
, sizeof(atmllc
->llchdr
));
515 ATM_LLC_SETTYPE(atmllc
, etype
); /* note: already in network order */
517 return atm_output(pvcsif
->sif_ifp
, m
, &dst_addr
, rt
);
526 pvc_ioctl(shadow
, cmd
, data
)
527 struct ifnet
*shadow
;
532 struct pvcsif
*pvcsif
;
533 struct ifreq
*ifr
= (struct ifreq
*) data
;
534 void (*ifa_rtrequest
)(int, struct rtentry
*, struct sockaddr
*) = NULL
;
537 pvcsif
= (struct pvcsif
*)shadow
->if_softc
;
538 ifp
= pvcsif
->sif_ifp
;
539 if (ifp
== 0 || ifp
->if_ioctl
== 0)
547 snprintf(ifr
->ifr_name
, sizeof(ifr
->ifr_name
),
548 "%s%d", ifp
->if_name
, ifp
->if_unit
);
553 struct pvctxreq
*pvcreq
= (struct pvctxreq
*)data
;
555 snprintf(pvcreq
->pvc_ifname
,
556 sizeof(pvcreq
->pvc_ifname
), "%s%d",
557 ifp
->if_name
, ifp
->if_unit
);
558 pvcreq
->pvc_aph
= pvcsif
->sif_aph
;
565 return (EAFNOSUPPORT
); /* XXX */
566 switch (ifr
->ifr_addr
.sa_family
) {
576 return (EAFNOSUPPORT
);
580 if (ifp
->if_flags
& IFF_UP
) {
581 /* real if is already up */
582 shadow
->if_flags
= ifp
->if_flags
|
583 (IFF_POINTOPOINT
|IFF_MULTICAST
);
587 * XXX: save the rtrequest field since the atm driver
588 * overwrites this field.
590 ifa_rtrequest
= ((struct ifaddr
*)data
)->ifa_rtrequest
;
594 if ((shadow
->if_flags
& IFF_UP
) == 0) {
596 * interface down. don't pass this to
597 * the real interface.
601 if (shadow
->if_flags
& IFF_UP
) {
603 * interface up. if the real if is already up,
606 if (ifp
->if_flags
& IFF_UP
) {
607 shadow
->if_flags
= ifp
->if_flags
|
608 (IFF_POINTOPOINT
|IFF_MULTICAST
);
616 * pass the ioctl to the genuine interface
618 error
= (*ifp
->if_ioctl
)(ifp
, cmd
, data
);
625 shadow
->if_mtu
= ifp
->if_mtu
;
628 /* restore rtrequest */
629 ((struct ifaddr
*)data
)->ifa_rtrequest
= ifa_rtrequest
;
632 /* update if_flags */
633 shadow
->if_flags
= ifp
->if_flags
634 | (IFF_POINTOPOINT
|IFF_MULTICAST
);
641 int pvc_setaph(shadow
, aph
)
642 struct ifnet
*shadow
;
643 struct atm_pseudohdr
*aph
;
645 struct pvcsif
*pvcsif
;
647 pvcsif
= shadow
->if_softc
;
648 bcopy(aph
, &pvcsif
->sif_aph
, sizeof(struct atm_pseudohdr
));
652 #endif /* ATM_PVCEXT */