2 * Copyright (c) 1998, Larry Lile
5 * For latest sources and information on this driver, please
6 * go to http://anarchy.stdio.com.
8 * Questions, comments or suggestions should be directed to
9 * Larry Lile <lile@stdio.com>.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice unmodified, this list of conditions, and the following
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * $FreeBSD: src/sys/net/if_iso88025subr.c,v 1.7.2.7 2002/06/18 00:15:31 kbyanc Exp $
34 * $DragonFly: src/sys/net/Attic/if_iso88025subr.c,v 1.16 2006/12/22 23:44:54 swildner Exp $
40 * General ISO 802.5 (Token Ring) support routines
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <sys/sysctl.h>
54 #include <sys/serialize.h>
57 #include <net/netisr.h>
58 #include <net/route.h>
59 #include <net/if_llc.h>
60 #include <net/if_dl.h>
61 #include <net/if_types.h>
63 #include <net/if_arp.h>
65 #include <net/iso88025.h>
68 #include <netinet/in.h>
69 #include <netinet/in_var.h>
70 #include <netinet/if_ether.h>
75 #include <machine/clock.h>
76 #include <machine/md_var.h>
78 #include <bus/isa/i386/isa_device.h>
81 #include <vm/vm_param.h>
84 #include <sys/kernel.h>
85 #include <net/iso88025.h>
87 static int iso88025_output(struct ifnet
*, struct mbuf
*,
88 struct sockaddr
*, struct rtentry
*);
89 static void iso88025_input(struct ifnet
*, struct mbuf
*);
92 iso88025_ifattach(struct ifnet
*ifp
, lwkt_serialize_t serializer
)
94 struct sockaddr_dl
*sdl
;
96 ifp
->if_input
= iso88025_input
;
97 ifp
->if_output
= iso88025_output
;
98 if_attach(ifp
, serializer
);
99 ifp
->if_type
= IFT_ISO88025
;
100 ifp
->if_addrlen
= ISO88025_ADDR_LEN
;
101 ifp
->if_hdrlen
= ISO88025_HDR_LEN
;
102 if (ifp
->if_baudrate
== 0)
103 ifp
->if_baudrate
= TR_16MBPS
; /* 16Mbit should be a safe default */
104 if (ifp
->if_mtu
== 0)
105 ifp
->if_mtu
= ISO88025_DEFAULT_MTU
;
107 sdl
= IF_LLSOCKADDR(ifp
);
108 sdl
->sdl_type
= IFT_ISO88025
;
109 sdl
->sdl_alen
= ifp
->if_addrlen
;
110 bcopy(((struct arpcom
*)ifp
)->ac_enaddr
, LLADDR(sdl
), ifp
->if_addrlen
);
111 bpfattach(ifp
, DLT_IEEE802
, sizeof(struct iso88025_header
));
115 iso88025_ioctl(struct ifnet
*ifp
, int command
, caddr_t data
)
117 struct ifaddr
*ifa
= (struct ifaddr
*) data
;
118 struct ifreq
*ifr
= (struct ifreq
*) data
;
123 ifp
->if_flags
|= IFF_UP
;
125 switch (ifa
->ifa_addr
->sa_family
) {
128 lwkt_serialize_enter(ifp
->if_serializer
);
129 ifp
->if_init(ifp
->if_softc
); /* before arpwhohas */
130 lwkt_serialize_exit(ifp
->if_serializer
);
131 arp_ifinit(ifp
, ifa
);
135 lwkt_serialize_enter(ifp
->if_serializer
);
136 ifp
->if_init(ifp
->if_softc
);
137 lwkt_serialize_exit(ifp
->if_serializer
);
143 bcopy(((struct arpcom
*)ifp
->if_softc
)->ac_enaddr
,
144 ((struct sockaddr
*)ifr
->ifr_data
)->sa_data
,
150 * Set the interface MTU.
152 if (ifr
->ifr_mtu
> ISO88025_MAX_MTU
) {
155 ifp
->if_mtu
= ifr
->ifr_mtu
;
163 * ISO88025 encapsulation
166 iso88025_output(struct ifnet
*ifp
, struct mbuf
*m
, struct sockaddr
*dst
,
169 struct iso88025_header
*th
;
170 struct iso88025_header gen_th
;
171 struct iso88025_sockaddr_data
*sd
= (struct iso88025_sockaddr_data
*)dst
->sa_data
;
173 struct sockaddr_dl
*sdl
= NULL
;
174 int error
= 0, rif_len
= 0;
177 int len
= m
->m_pkthdr
.len
, loop_copy
= 0;
178 struct arpcom
*ac
= (struct arpcom
*)ifp
;
180 if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
))
184 senderr(EHOSTUNREACH
);
185 error
= rt_llroute(dst
, rt0
, &rt
);
189 /* Calculate routing info length based on arp table entry. */
190 if (rt
&& (sdl
= (struct sockaddr_dl
*)rt
->rt_gateway
))
191 if (SDL_ISO88025(sdl
)->trld_rcf
!= NULL
)
192 rif_len
= TR_RCF_RIFLEN(SDL_ISO88025(sdl
)->trld_rcf
);
194 /* Generate a generic 802.5 header for the packet. */
196 gen_th
.fc
= TR_LLC_FRAME
;
197 memcpy(gen_th
.iso88025_shost
, ac
->ac_enaddr
, sizeof ac
->ac_enaddr
);
199 gen_th
.iso88025_shost
[0] |= TR_RII
;
201 gen_th
.rcf
= sdl
->sdl_rcf
;
202 memcpy(gen_th
.rd
, sdl
->sdl_route
, rif_len
- 2);
207 switch (dst
->sa_family
) {
210 if (!arpresolve(ifp
, rt0
, m
, dst
, edst
))
211 return (0); /* if not yet resolved */
212 /* Add LLC and SNAP headers */
213 M_PREPEND(m
, 8, MB_DONTWAIT
);
216 l
= mtod(m
, struct llc
*);
217 l
->llc_un
.type_snap
.ether_type
= htons(ETHERTYPE_IP
);
218 l
->llc_dsap
= l
->llc_ssap
= LLC_SNAP_LSAP
;
219 l
->llc_un
.type_snap
.control
= LLC_UI
;
220 l
->llc_un
.type_snap
.org_code
[0] = 0x0;
221 l
->llc_un
.type_snap
.org_code
[1] = 0x0;
222 l
->llc_un
.type_snap
.org_code
[2] = 0x0;
223 memcpy(gen_th
.iso88025_dhost
, edst
, sizeof(edst
));
229 * For AF_UNSPEC sockaddr.sa_data must contain all of the
230 * mac information needed to send the packet. This allows
231 * full mac, llc, and source routing function to be controlled.
232 * llc and source routing information must already be in the
233 * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data
234 * should be a iso88025_sockaddr_data structure see iso88025.h
237 sd
= (struct iso88025_sockaddr_data
*)dst
->sa_data
;
240 memcpy(gen_th
.iso88025_dhost
, sd
->ether_dhost
, sizeof(sd
->ether_dhost
));
241 memcpy(gen_th
.iso88025_shost
, sd
->ether_shost
, sizeof(sd
->ether_shost
));
246 kprintf("%s: can't handle af%d\n", ifp
->if_xname
,
248 senderr(EAFNOSUPPORT
);
252 * Add local net header. If no space in first mbuf,
256 M_PREPEND(m
, ISO88025_HDR_LEN
+ rif_len
, MB_DONTWAIT
);
260 /* Copy as much of the generic header as is needed into the mbuf */
261 th
= mtod(m
, struct iso88025_header
*);
262 memcpy(th
, &gen_th
, ISO88025_HDR_LEN
+ rif_len
);
265 * If a simplex interface, and the packet is being sent to our
266 * Ethernet address or a broadcast address, loopback a copy.
267 * XXX To make a simplex device behave exactly like a duplex
268 * device, we should copy in the case of sending to our own
269 * ethernet address (thus letting the original actually appear
270 * on the wire). However, we don't do that here for security
271 * reasons and compatibility with the original behavior.
273 if ((ifp
->if_flags
& IFF_SIMPLEX
) &&
275 if ((m
->m_flags
& M_BCAST
) || (loop_copy
> 0)) {
276 struct mbuf
*n
= m_copypacket(m
, MB_DONTWAIT
);
278 if_simloop(ifp
, n
, dst
->sa_family
, ISO88025_HDR_LEN
);
279 } else if (bcmp(th
->iso88025_dhost
,
280 th
->iso88025_shost
, ETHER_ADDR_LEN
) == 0) {
281 if_simloop(ifp
, m
, dst
->sa_family
, ISO88025_HDR_LEN
);
282 return (0); /* XXX */
288 * Queue message on interface, and start output if interface
291 if (IF_QFULL(&ifp
->if_snd
)) {
292 kprintf("iso88025_output: packet dropped QFULL.\n");
293 IF_DROP(&ifp
->if_snd
);
297 if (m
->m_flags
& M_MCAST
)
299 IF_ENQUEUE(&ifp
->if_snd
, m
);
300 if (!(ifp
->if_flags
& IFF_OACTIVE
))
301 (*ifp
->if_start
)(ifp
);
303 ifp
->if_obytes
+= len
+ ISO88025_HDR_LEN
+ 8;
312 * ISO 88025 de-encapsulation
315 iso88025_input(struct ifnet
*ifp
, struct mbuf
*m
)
318 struct iso88025_header
*th
= mtod(m
, struct iso88025_header
*);
322 ASSERT_SERIALIZED(ifp
->if_serializer
);
324 if (!(ifp
->if_flags
& IFF_UP
)) {
329 hdr_len
= ISO88025_HDR_LEN
;
330 if (th
->iso88025_shost
[0] & 0x80)
331 hdr_len
+= (ntohs(th
->rcf
) & 0x1f00) >> 8;
333 if (m
->m_len
< hdr_len
) {
337 m
->m_pkthdr
.len
-= hdr_len
;
339 m
->m_data
+= hdr_len
;
341 l
= mtod(m
, struct llc
*);
343 switch (l
->llc_control
) {
350 struct arpcom
*ac
= (struct arpcom
*)ifp
;
351 struct iso88025_sockaddr_data
*th2
;
353 u_char c
= l
->llc_dsap
;
355 if (th
->iso88025_shost
[0] & TR_RII
) { /* XXX */
356 kprintf("iso88025_input: dropping source routed LLC_TEST\n");
360 l
->llc_dsap
= l
->llc_ssap
;
362 if (m
->m_flags
& (M_BCAST
| M_MCAST
))
363 bcopy(ac
->ac_enaddr
, th
->iso88025_dhost
,
365 sa
.sa_family
= AF_UNSPEC
;
366 sa
.sa_len
= sizeof(sa
);
367 th2
= (struct iso88025_sockaddr_data
*)sa
.sa_data
;
368 for (i
= 0; i
< ISO88025_ADDR_LEN
; i
++) {
369 th2
->ether_shost
[i
] = c
= th
->iso88025_dhost
[i
];
370 th2
->ether_dhost
[i
] = th
->iso88025_dhost
[i
] = th
->iso88025_shost
[i
];
371 th
->iso88025_shost
[i
] = c
;
374 th2
->fc
= TR_LLC_FRAME
;
375 ifp
->if_output(ifp
, m
, &sa
, NULL
);
379 kprintf("iso88025_input: unexpected llc control 0x%02x\n", l
->llc_control
);
384 m
->m_pkthdr
.len
-= 8;
386 m
->m_data
+= 8; /* Length of LLC header in our case */
388 ifp
->if_ibytes
+= m
->m_pkthdr
.len
+ sizeof(*th
);
389 if (th
->iso88025_dhost
[0] & 1) {
390 if (bcmp(ifp
->if_broadcastaddr
, th
->iso88025_dhost
,
391 ifp
->if_addrlen
) == 0)
392 m
->m_flags
|= M_BCAST
;
394 m
->m_flags
|= M_MCAST
;
396 if (m
->m_flags
& (M_BCAST
|M_MCAST
))
399 ether_type
= ntohs(l
->llc_un
.type_snap
.ether_type
);
401 switch (ether_type
) {
404 th
->iso88025_shost
[0] &= ~(TR_RII
);
405 if (ipflow_fastforward(m
, ifp
->if_serializer
))
411 if (ifp
->if_flags
& IFF_NOARP
) {
423 netisr_dispatch(isr
, m
);