]>
git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_fddisubr.c
990823ecdf87b7da99252077ea0ce7466618669b
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 * Copyright (c) 1995, 1996
32 * Matt Thomas <matt@3am-software.com>. All rights reserved.
33 * Copyright (c) 1982, 1989, 1993
34 * The Regents of the University of California. All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp
67 #include "opt_atalk.h"
71 #include <sys/param.h>
72 #include <sys/systm.h>
74 #include <sys/socket.h>
77 #include <net/netisr.h>
78 #include <net/route.h>
79 #include <net/if_llc.h>
80 #include <net/if_dl.h>
81 #include <net/if_types.h>
84 #include <netinet/in.h>
85 #include <netinet/in_var.h>
86 #include <netinet/if_ether.h>
88 #if defined(__FreeBSD__)
89 #include <netinet/if_fddi.h>
91 #include <net/if_fddi.h>
95 #include <netipx/ipx.h>
96 #include <netipx/ipx_if.h>
100 #include <netdnet/dn.h>
103 #include "bpfilter.h"
105 #define senderr(e) { error = (e); goto bad;}
108 * This really should be defined in if_llc.h but in case it isn't.
111 #define llc_snap llc_un.type_snap
114 #if defined(__bsdi__) || defined(__NetBSD__)
115 #define RTALLOC1(a, b) rtalloc1(a, b)
116 #define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e)
117 #elif defined(__FreeBSD__)
118 #define RTALLOC1(a, b) rtalloc1(a, b, 0UL)
119 #define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e, f)
122 * FDDI output routine.
123 * Encapsulate a packet of type family for the local net.
124 * Use trailer local net encapsulation if enough data in first
125 * packet leaves a multiple of 512 bytes of data in remainder.
126 * Assumes that ifp is actually pointer to arpcom structure.
129 fddi_output(ifp
, m0
, dst
, rt0
)
130 register struct ifnet
*ifp
;
132 struct sockaddr
*dst
;
136 int s
, loop_copy
= 0, error
= 0;
138 register struct mbuf
*m
= m0
;
139 register struct rtentry
*rt
;
140 register struct fddi_header
*fh
;
141 struct arpcom
*ac
= (struct arpcom
*)ifp
;
143 if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
))
145 getmicrotime(&ifp
->if_lastchange
);
146 #if !defined(__bsdi__) || _BSDI_VERSION >= 199401
148 if ((rt
->rt_flags
& RTF_UP
) == 0) {
149 if (rt0
= rt
= RTALLOC1(dst
, 1))
152 senderr(EHOSTUNREACH
);
154 if (rt
->rt_flags
& RTF_GATEWAY
) {
155 if (rt
->rt_gwroute
== 0)
157 if (((rt
= rt
->rt_gwroute
)->rt_flags
& RTF_UP
) == 0) {
158 rtfree(rt
); rt
= rt0
;
159 lookup
: rt
->rt_gwroute
= RTALLOC1(rt
->rt_gateway
, 1);
160 if ((rt
= rt
->rt_gwroute
) == 0)
161 senderr(EHOSTUNREACH
);
164 if (rt
->rt_flags
& RTF_REJECT
)
165 if (rt
->rt_rmx
.rmx_expire
== 0 ||
166 time_second
< rt
->rt_rmx
.rmx_expire
)
167 senderr(rt
== rt0
? EHOSTDOWN
: EHOSTUNREACH
);
170 switch (dst
->sa_family
) {
174 #if !defined(__bsdi__) || _BSDI_VERSION >= 199401
175 if (!ARPRESOLVE(ac
, rt
, m
, dst
, edst
, rt0
))
176 return (0); /* if not yet resolved */
179 if (!arpresolve(ac
, m
, &((struct sockaddr_in
*)dst
)->sin_addr
, edst
, &usetrailers
))
180 return (0); /* if not yet resolved */
182 type
= htons(ETHERTYPE_IP
);
188 type
= htons(ETHERTYPE_IPX
);
189 bcopy((caddr_t
)&(((struct sockaddr_ipx
*)dst
)->sipx_addr
.x_host
),
190 (caddr_t
)edst
, sizeof (edst
));
196 type
= htons(ETHERTYPE_NS
);
197 bcopy((caddr_t
)&(((struct sockaddr_ns
*)dst
)->sns_addr
.x_host
),
198 (caddr_t
)edst
, sizeof (edst
));
205 register struct sockaddr_dl
*sdl
;
207 if (rt
&& (sdl
= (struct sockaddr_dl
*)rt
->rt_gateway
) &&
208 sdl
->sdl_family
== AF_LINK
&& sdl
->sdl_alen
> 0) {
209 bcopy(LLADDR(sdl
), (caddr_t
)edst
, sizeof(edst
));
211 iso_snparesolve(ifp
, (struct sockaddr_iso
*)dst
,
212 (char *)edst
, &snpalen
))
213 goto bad
; /* Not Resolved */
214 /* If broadcasting on a simplex interface, loopback a copy */
216 m
->m_flags
|= (M_BCAST
|M_MCAST
);
217 M_PREPEND(m
, 3, M_DONTWAIT
);
221 l
= mtod(m
, struct llc
*);
222 l
->llc_dsap
= l
->llc_ssap
= LLC_ISO_LSAP
;
223 l
->llc_control
= LLC_UI
;
226 printf("unoutput: sending pkt to: ");
228 printf("%x ", edst
[i
] & 0xff);
236 register struct sockaddr_dl
*sdl
=
237 (struct sockaddr_dl
*) rt
-> rt_gateway
;
239 if (sdl
&& sdl
->sdl_family
!= AF_LINK
&& sdl
->sdl_alen
<= 0)
240 goto bad
; /* Not a link interface ? Funny ... */
241 bcopy(LLADDR(sdl
), (char *)edst
, sizeof(edst
));
248 register struct llc
*l
= mtod(m
, struct llc
*);
250 printf("fddi_output: sending LLC2 pkt to: ");
252 printf("%x ", edst
[i
] & 0xff);
253 printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n",
254 type
& 0xff, l
->llc_dsap
& 0xff, l
->llc_ssap
&0xff,
255 l
->llc_control
& 0xff);
258 #endif /* LLC_DEBUG */
264 struct ether_header
*eh
;
266 eh
= (struct ether_header
*)dst
->sa_data
;
267 (void)memcpy((caddr_t
)edst
, (caddr_t
)eh
->ether_dhost
, sizeof (edst
));
269 m
->m_flags
|= (M_BCAST
|M_MCAST
);
270 type
= eh
->ether_type
;
277 fh
= mtod(m
, struct fddi_header
*);
278 error
= EPROTONOSUPPORT
;
279 switch (fh
->fddi_fc
& (FDDIFC_C
|FDDIFC_L
|FDDIFC_F
)) {
280 case FDDIFC_LLC_ASYNC
: {
281 /* legal priorities are 0 through 7 */
282 if ((fh
->fddi_fc
& FDDIFC_Z
) > 7)
286 case FDDIFC_LLC_SYNC
: {
287 /* FDDIFC_Z bits reserved, must be zero */
288 if (fh
->fddi_fc
& FDDIFC_Z
)
293 /* FDDIFC_Z bits must be non zero */
294 if ((fh
->fddi_fc
& FDDIFC_Z
) == 0)
299 /* anything else is too dangerous */
304 if (fh
->fddi_dhost
[0] & 1)
305 m
->m_flags
|= (M_BCAST
|M_MCAST
);
310 printf("%s%d: can't handle af%d\n", ifp
->if_name
, ifp
->if_unit
,
312 senderr(EAFNOSUPPORT
);
316 register struct llc
*l
;
317 M_PREPEND(m
, sizeof (struct llc
), M_DONTWAIT
);
320 l
= mtod(m
, struct llc
*);
321 l
->llc_control
= LLC_UI
;
322 l
->llc_dsap
= l
->llc_ssap
= LLC_SNAP_LSAP
;
323 l
->llc_snap
.org_code
[0] = l
->llc_snap
.org_code
[1] = l
->llc_snap
.org_code
[2] = 0;
324 (void)memcpy((caddr_t
) &l
->llc_snap
.ether_type
, (caddr_t
) &type
,
329 * Add local net header. If no space in first mbuf,
332 M_PREPEND(m
, sizeof (struct fddi_header
), M_DONTWAIT
);
335 fh
= mtod(m
, struct fddi_header
*);
336 fh
->fddi_fc
= FDDIFC_LLC_ASYNC
|FDDIFC_LLC_PRIO4
;
337 (void)memcpy((caddr_t
)fh
->fddi_dhost
, (caddr_t
)edst
, sizeof (edst
));
339 (void)memcpy((caddr_t
)fh
->fddi_shost
, (caddr_t
)ac
->ac_enaddr
,
340 sizeof(fh
->fddi_shost
));
343 * If a simplex interface, and the packet is being sent to our
344 * Ethernet address or a broadcast address, loopback a copy.
345 * XXX To make a simplex device behave exactly like a duplex
346 * device, we should copy in the case of sending to our own
347 * ethernet address (thus letting the original actually appear
348 * on the wire). However, we don't do that here for security
349 * reasons and compatibility with the original behavior.
351 if ((ifp
->if_flags
& IFF_SIMPLEX
) &&
353 if ((m
->m_flags
& M_BCAST
) || loop_copy
) {
354 struct mbuf
*n
= m_copy(m
, 0, (int)M_COPYALL
);
356 (void) if_simloop(ifp
,
357 n
, dst
, sizeof(struct fddi_header
));
358 } else if (bcmp(fh
->fddi_dhost
,
359 fh
->fddi_shost
, sizeof(fh
->fddi_shost
)) == 0) {
360 (void) if_simloop(ifp
,
361 m
, dst
, sizeof(struct fddi_header
));
368 * Queue message on interface, and start output if interface
371 if (IF_QFULL(&ifp
->if_snd
)) {
372 IF_DROP(&ifp
->if_snd
);
376 ifp
->if_obytes
+= m
->m_pkthdr
.len
;
377 IF_ENQUEUE(&ifp
->if_snd
, m
);
378 if ((ifp
->if_flags
& IFF_OACTIVE
) == 0)
379 (*ifp
->if_start
)(ifp
);
381 if (m
->m_flags
& M_MCAST
)
392 * Process a received FDDI packet;
393 * the packet is in the mbuf chain m without
394 * the fddi header, which is provided separately.
397 fddi_input(ifp
, fh
, m
)
399 register struct fddi_header
*fh
;
402 register struct ifqueue
*inq
;
403 register struct llc
*l
;
406 if ((ifp
->if_flags
& IFF_UP
) == 0) {
410 getmicrotime(&ifp
->if_lastchange
);
411 ifp
->if_ibytes
+= m
->m_pkthdr
.len
+ sizeof (*fh
);
412 if (fh
->fddi_dhost
[0] & 1) {
413 if (bcmp((caddr_t
)fddibroadcastaddr
, (caddr_t
)fh
->fddi_dhost
,
414 sizeof(fddibroadcastaddr
)) == 0)
415 m
->m_flags
|= M_BCAST
;
417 m
->m_flags
|= M_MCAST
;
419 } else if ((ifp
->if_flags
& IFF_PROMISC
)
420 && bcmp(((struct arpcom
*)ifp
)->ac_enaddr
, (caddr_t
)fh
->fddi_dhost
,
421 sizeof(fh
->fddi_dhost
)) != 0) {
428 * If this has a LLC priority of 0, then mark it so upper
429 * layers have a hint that it really came via a FDDI/Ethernet
432 if ((fh
->fddi_fc
& FDDIFC_LLC_PRIO7
) == FDDIFC_LLC_PRIO0
)
433 m
->m_flags
|= M_LINK0
;
436 l
= mtod(m
, struct llc
*);
437 switch (l
->llc_dsap
) {
438 #if defined(INET) || NS || IPX || defined(NETATALK)
442 if (l
->llc_control
!= LLC_UI
|| l
->llc_ssap
!= LLC_SNAP_LSAP
)
445 if (l
->llc_snap
.org_code
[0] != 0 || l
->llc_snap
.org_code
[1] != 0|| l
->llc_snap
.org_code
[2] != 0)
447 type
= ntohs(l
->llc_snap
.ether_type
);
452 if (ipflow_fastforward(m
))
454 schednetisr(NETISR_IP
);
459 #if !defined(__bsdi__) || _BSDI_VERSION >= 199401
460 schednetisr(NETISR_ARP
);
464 arpinput((struct arpcom
*)ifp
, m
);
470 schednetisr(NETISR_IPX
);
476 schednetisr(NETISR_NS
);
481 case ETHERTYPE_DECNET
:
482 schednetisr(NETISR_DECNET
);
488 /* printf("fddi_input: unknown protocol 0x%x\n", type); */
494 #endif /* INET || NS */
497 switch (l
->llc_control
) {
499 /* LLC_UI_P forbidden in class 1 service */
500 if ((l
->llc_dsap
== LLC_ISO_LSAP
) &&
501 (l
->llc_ssap
== LLC_ISO_LSAP
)) {
503 m
->m_data
+= 3; /* XXX */
504 m
->m_len
-= 3; /* XXX */
505 m
->m_pkthdr
.len
-= 3; /* XXX */
506 M_PREPEND(m
, sizeof *fh
, M_DONTWAIT
);
509 *mtod(m
, struct fddi_header
*) = *fh
;
511 printf("clnp packet");
513 schednetisr(NETISR_ISO
);
526 l
->llc_dsap
= l
->llc_ssap
= 0;
527 /* Fall through to */
532 register struct ether_header
*eh
;
533 struct arpcom
*ac
= (struct arpcom
*) ifp
;
535 u_char c
= l
->llc_dsap
;
537 l
->llc_dsap
= l
->llc_ssap
;
539 if (m
->m_flags
& (M_BCAST
| M_MCAST
))
540 bcopy((caddr_t
)ac
->ac_enaddr
,
541 (caddr_t
)eh
->ether_dhost
, 6);
542 sa
.sa_family
= AF_UNSPEC
;
543 sa
.sa_len
= sizeof(sa
);
544 eh
= (struct ether_header
*)sa
.sa_data
;
545 for (i
= 0; i
< 6; i
++) {
546 eh
->ether_shost
[i
] = fh
->fddi_dhost
[i
];
547 eh
->ether_dhost
[i
] = fh
->fddi_shost
[i
];
550 ifp
->if_output(ifp
, m
, &sa
, NULL
);
562 M_PREPEND(m
, sizeof(struct sdl_hdr
) , M_DONTWAIT
);
565 if ( !sdl_sethdrif(ifp
, fh
->fddi_shost
, LLC_X25_LSAP
,
566 fh
->fddi_dhost
, LLC_X25_LSAP
, 6,
567 mtod(m
, struct sdl_hdr
*)))
568 panic("ETHER cons addr failure");
569 mtod(m
, struct sdl_hdr
*)->sdlhdr_len
= m
->m_pkthdr
.len
- sizeof(struct sdl_hdr
);
571 printf("llc packet\n");
572 #endif /* LLC_DEBUG */
573 schednetisr(NETISR_CCITT
);
580 /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */
596 * Perform common duties while attaching to interface list
599 #define ifa_next ifa_list.tqe_next
604 register struct ifnet
*ifp
;
606 register struct ifaddr
*ifa
;
607 register struct sockaddr_dl
*sdl
;
609 ifp
->if_type
= IFT_FDDI
;
612 ifp
->if_mtu
= FDDIMTU
;
613 ifp
->if_baudrate
= 100000000;
615 ifp
->if_flags
|= IFF_NOTRAILERS
;
617 #if defined(__FreeBSD__)
618 ifa
= ifnet_addrs
[ifp
->if_index
- 1];
619 sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
620 sdl
->sdl_type
= IFT_FDDI
;
621 sdl
->sdl_alen
= ifp
->if_addrlen
;
622 bcopy(((struct arpcom
*)ifp
)->ac_enaddr
, LLADDR(sdl
), ifp
->if_addrlen
);
623 #elif defined(__NetBSD__)
624 LIST_INIT(&((struct arpcom
*)ifp
)->ac_multiaddrs
);
625 for (ifa
= ifp
->if_addrlist
.tqh_first
; ifa
!= NULL
; ifa
= ifa
->ifa_list
.tqe_next
)
627 for (ifa
= ifp
->if_addrlist
; ifa
!= NULL
; ifa
= ifa
->ifa_next
)
629 #if !defined(__FreeBSD__)
630 if ((sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
) &&
631 sdl
->sdl_family
== AF_LINK
) {
632 sdl
->sdl_type
= IFT_FDDI
;
633 sdl
->sdl_alen
= ifp
->if_addrlen
;
634 bcopy((caddr_t
)((struct arpcom
*)ifp
)->ac_enaddr
,
635 LLADDR(sdl
), ifp
->if_addrlen
);