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.10 2004/12/21 02:54:14 hsu 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>
56 #include <net/netisr.h>
57 #include <net/route.h>
58 #include <net/if_llc.h>
59 #include <net/if_dl.h>
60 #include <net/if_types.h>
62 #include <net/if_arp.h>
64 #include <net/iso88025.h>
67 #include <netinet/in.h>
68 #include <netinet/in_var.h>
69 #include <netinet/if_ether.h>
74 #include <machine/clock.h>
75 #include <machine/md_var.h>
77 #include <bus/isa/i386/isa_device.h>
80 #include <vm/vm_param.h>
83 #include <sys/kernel.h>
84 #include <net/iso88025.h>
86 static int iso88025_output(struct ifnet
*, struct mbuf
*,
87 struct sockaddr
*, struct rtentry
*);
88 static void iso88025_input(struct ifnet
*, struct mbuf
*);
91 iso88025_ifattach(struct ifnet
*ifp
)
93 struct ifaddr
*ifa
= NULL
;
94 struct sockaddr_dl
*sdl
;
96 ifp
->if_input
= iso88025_input
;
97 ifp
->if_output
= iso88025_output
;
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 ifa
= ifnet_addrs
[ifp
->if_index
- 1];
109 printf("iso88025_ifattach: no lladdr!\n");
112 sdl
= (struct sockaddr_dl
*)ifa
->ifa_addr
;
113 sdl
->sdl_type
= IFT_ISO88025
;
114 sdl
->sdl_alen
= ifp
->if_addrlen
;
115 bcopy(((struct arpcom
*)ifp
)->ac_enaddr
, LLADDR(sdl
), ifp
->if_addrlen
);
116 bpfattach(ifp
, DLT_IEEE802
, sizeof(struct iso88025_header
));
120 iso88025_ioctl(struct ifnet
*ifp
, int command
, caddr_t data
)
122 struct ifaddr
*ifa
= (struct ifaddr
*) data
;
123 struct ifreq
*ifr
= (struct ifreq
*) data
;
128 ifp
->if_flags
|= IFF_UP
;
130 switch (ifa
->ifa_addr
->sa_family
) {
133 ifp
->if_init(ifp
->if_softc
); /* before arpwhohas */
134 arp_ifinit(ifp
, ifa
);
138 ifp
->if_init(ifp
->if_softc
);
144 bcopy(((struct arpcom
*)ifp
->if_softc
)->ac_enaddr
,
145 ((struct sockaddr
*)ifr
->ifr_data
)->sa_data
,
151 * Set the interface MTU.
153 if (ifr
->ifr_mtu
> ISO88025_MAX_MTU
) {
156 ifp
->if_mtu
= ifr
->ifr_mtu
;
164 * ISO88025 encapsulation
167 iso88025_output(struct ifnet
*ifp
, struct mbuf
*m
, struct sockaddr
*dst
,
170 struct iso88025_header
*th
;
171 struct iso88025_header gen_th
;
172 struct iso88025_sockaddr_data
*sd
= (struct iso88025_sockaddr_data
*)dst
->sa_data
;
174 struct sockaddr_dl
*sdl
= NULL
;
175 int s
, error
= 0, rif_len
= 0;
178 int len
= m
->m_pkthdr
.len
, loop_copy
= 0;
179 struct arpcom
*ac
= (struct arpcom
*)ifp
;
181 if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
))
185 senderr(EHOSTUNREACH
);
186 error
= rt_llroute(dst
, rt0
, &rt
);
190 /* Calculate routing info length based on arp table entry. */
191 if (rt
&& (sdl
= (struct sockaddr_dl
*)rt
->rt_gateway
))
192 if (SDL_ISO88025(sdl
)->trld_rcf
!= NULL
)
193 rif_len
= TR_RCF_RIFLEN(SDL_ISO88025(sdl
)->trld_rcf
);
195 /* Generate a generic 802.5 header for the packet. */
197 gen_th
.fc
= TR_LLC_FRAME
;
198 memcpy(gen_th
.iso88025_shost
, ac
->ac_enaddr
, sizeof ac
->ac_enaddr
);
200 gen_th
.iso88025_shost
[0] |= TR_RII
;
202 gen_th
.rcf
= sdl
->sdl_rcf
;
203 memcpy(gen_th
.rd
, sdl
->sdl_route
, rif_len
- 2);
208 switch (dst
->sa_family
) {
211 if (!arpresolve(ifp
, rt0
, m
, dst
, edst
))
212 return (0); /* if not yet resolved */
213 /* Add LLC and SNAP headers */
214 M_PREPEND(m
, 8, MB_DONTWAIT
);
217 l
= mtod(m
, struct llc
*);
218 l
->llc_un
.type_snap
.ether_type
= htons(ETHERTYPE_IP
);
219 l
->llc_dsap
= l
->llc_ssap
= LLC_SNAP_LSAP
;
220 l
->llc_un
.type_snap
.control
= LLC_UI
;
221 l
->llc_un
.type_snap
.org_code
[0] = 0x0;
222 l
->llc_un
.type_snap
.org_code
[1] = 0x0;
223 l
->llc_un
.type_snap
.org_code
[2] = 0x0;
224 memcpy(gen_th
.iso88025_dhost
, edst
, sizeof(edst
));
230 * For AF_UNSPEC sockaddr.sa_data must contain all of the
231 * mac information needed to send the packet. This allows
232 * full mac, llc, and source routing function to be controlled.
233 * llc and source routing information must already be in the
234 * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data
235 * should be a iso88025_sockaddr_data structure see iso88025.h
238 sd
= (struct iso88025_sockaddr_data
*)dst
->sa_data
;
241 memcpy(gen_th
.iso88025_dhost
, sd
->ether_dhost
, sizeof(sd
->ether_dhost
));
242 memcpy(gen_th
.iso88025_shost
, sd
->ether_shost
, sizeof(sd
->ether_shost
));
247 printf("%s: can't handle af%d\n", ifp
->if_xname
,
249 senderr(EAFNOSUPPORT
);
253 * Add local net header. If no space in first mbuf,
257 M_PREPEND(m
, ISO88025_HDR_LEN
+ rif_len
, MB_DONTWAIT
);
261 /* Copy as much of the generic header as is needed into the mbuf */
262 th
= mtod(m
, struct iso88025_header
*);
263 memcpy(th
, &gen_th
, ISO88025_HDR_LEN
+ rif_len
);
266 * If a simplex interface, and the packet is being sent to our
267 * Ethernet address or a broadcast address, loopback a copy.
268 * XXX To make a simplex device behave exactly like a duplex
269 * device, we should copy in the case of sending to our own
270 * ethernet address (thus letting the original actually appear
271 * on the wire). However, we don't do that here for security
272 * reasons and compatibility with the original behavior.
274 if ((ifp
->if_flags
& IFF_SIMPLEX
) &&
276 if ((m
->m_flags
& M_BCAST
) || (loop_copy
> 0)) {
277 struct mbuf
*n
= m_copypacket(m
, MB_DONTWAIT
);
279 if_simloop(ifp
, n
, dst
->sa_family
, ISO88025_HDR_LEN
);
280 } else if (bcmp(th
->iso88025_dhost
,
281 th
->iso88025_shost
, ETHER_ADDR_LEN
) == 0) {
282 if_simloop(ifp
, m
, dst
->sa_family
, ISO88025_HDR_LEN
);
283 return (0); /* XXX */
289 * Queue message on interface, and start output if interface
292 if (IF_QFULL(&ifp
->if_snd
)) {
293 printf("iso88025_output: packet dropped QFULL.\n");
294 IF_DROP(&ifp
->if_snd
);
298 if (m
->m_flags
& M_MCAST
)
300 IF_ENQUEUE(&ifp
->if_snd
, m
);
301 if (!(ifp
->if_flags
& IFF_OACTIVE
))
302 (*ifp
->if_start
)(ifp
);
304 ifp
->if_obytes
+= len
+ ISO88025_HDR_LEN
+ 8;
314 * ISO 88025 de-encapsulation
317 iso88025_input(struct ifnet
*ifp
, struct mbuf
*m
)
320 struct iso88025_header
*th
= mtod(m
, struct iso88025_header
*);
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 printf("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 printf("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
))
411 if (ifp
->if_flags
& IFF_NOARP
) {
423 netisr_dispatch(isr
, m
);