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
39 * General ISO 802.5 (Token Ring) support routines
44 #include "opt_inet6.h"
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/malloc.h>
52 #include <sys/module.h>
53 #include <sys/socket.h>
54 #include <sys/sockio.h>
57 #include <net/if_var.h>
58 #include <net/if_arp.h>
59 #include <net/if_dl.h>
60 #include <net/if_llc.h>
61 #include <net/if_types.h>
62 #include <net/if_llatbl.h>
64 #include <net/ethernet.h>
65 #include <net/netisr.h>
66 #include <net/route.h>
68 #include <net/iso88025.h>
70 #if defined(INET) || defined(INET6)
71 #include <netinet/in.h>
72 #include <netinet/in_var.h>
73 #include <netinet/if_ether.h>
76 #include <netinet6/nd6.h>
80 #include <netipx/ipx.h>
81 #include <netipx/ipx_if.h>
84 #include <security/mac/mac_framework.h>
86 static const u_char iso88025_broadcastaddr[ISO88025_ADDR_LEN] =
87 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
89 static int iso88025_resolvemulti (struct ifnet *, struct sockaddr **,
92 #define senderr(e) do { error = (e); goto bad; } while (0)
95 * Perform common duties while attaching to interface list
98 iso88025_ifattach(struct ifnet *ifp, const u_int8_t *lla, int bpf)
101 struct sockaddr_dl *sdl;
105 ifp->if_type = IFT_ISO88025;
106 ifp->if_addrlen = ISO88025_ADDR_LEN;
107 ifp->if_hdrlen = ISO88025_HDR_LEN;
109 if_attach(ifp); /* Must be called before additional assignments */
111 ifp->if_output = iso88025_output;
112 ifp->if_input = iso88025_input;
113 ifp->if_resolvemulti = iso88025_resolvemulti;
114 ifp->if_broadcastaddr = iso88025_broadcastaddr;
116 if (ifp->if_baudrate == 0)
117 ifp->if_baudrate = TR_16MBPS; /* 16Mbit should be a safe default */
118 if (ifp->if_mtu == 0)
119 ifp->if_mtu = ISO88025_DEFAULT_MTU;
122 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
124 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
125 sdl->sdl_type = IFT_ISO88025;
126 sdl->sdl_alen = ifp->if_addrlen;
127 bcopy(lla, LLADDR(sdl), ifp->if_addrlen);
130 bpfattach(ifp, DLT_IEEE802, ISO88025_HDR_LEN);
136 * Perform common duties while detaching a Token Ring interface
139 iso88025_ifdetach(ifp, bpf)
153 iso88025_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
159 ifa = (struct ifaddr *) data;
160 ifr = (struct ifreq *) data;
165 ifp->if_flags |= IFF_UP;
167 switch (ifa->ifa_addr->sa_family) {
170 ifp->if_init(ifp->if_softc); /* before arpwhohas */
171 arp_ifinit(ifp, ifa);
176 * XXX - This code is probably wrong
179 struct ipx_addr *ina;
181 ina = &(IA_SIPX(ifa)->sipx_addr);
183 if (ipx_nullhost(*ina))
184 ina->x_host = *(union ipx_host *)
187 bcopy((caddr_t) ina->x_host.c_host,
188 (caddr_t) IF_LLADDR(ifp),
194 ifp->if_init(ifp->if_softc);
199 ifp->if_init(ifp->if_softc);
207 sa = (struct sockaddr *) & ifr->ifr_data;
208 bcopy(IF_LLADDR(ifp),
209 (caddr_t) sa->sa_data, ISO88025_ADDR_LEN);
215 * Set the interface MTU.
217 if (ifr->ifr_mtu > ISO88025_MAX_MTU) {
220 ifp->if_mtu = ifr->ifr_mtu;
224 error = EINVAL; /* XXX netbsd has ENOTTY??? */
232 * ISO88025 encapsulation
235 iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
238 u_int16_t snap_type = 0;
239 int loop_copy = 0, error = 0, rif_len = 0;
240 u_char edst[ISO88025_ADDR_LEN];
241 struct iso88025_header *th;
242 struct iso88025_header gen_th;
243 struct sockaddr_dl *sdl = NULL;
244 struct rtentry *rt0 = NULL;
245 #if defined(INET) || defined(INET6)
253 error = mac_ifnet_check_transmit(ifp, m);
258 if (ifp->if_flags & IFF_MONITOR)
260 if (!((ifp->if_flags & IFF_UP) &&
261 (ifp->if_drv_flags & IFF_DRV_RUNNING)))
263 getmicrotime(&ifp->if_lastchange);
265 /* Calculate routing info length based on arp table entry */
266 /* XXX any better way to do this ? */
268 if (rt0 && (sdl = (struct sockaddr_dl *)rt0->rt_gateway))
269 if (SDL_ISO88025(sdl)->trld_rcf != 0)
270 rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf);
272 /* Generate a generic 802.5 header for the packet */
274 gen_th.fc = TR_LLC_FRAME;
275 (void)memcpy((caddr_t)gen_th.iso88025_shost, IF_LLADDR(ifp),
278 gen_th.iso88025_shost[0] |= TR_RII;
280 gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf;
281 (void)memcpy((caddr_t)gen_th.rd,
282 (caddr_t)SDL_ISO88025(sdl)->trld_route,
287 switch (dst->sa_family) {
290 error = arpresolve(ifp, rt0, m, dst, edst, &lle);
292 return (error == EWOULDBLOCK ? 0 : error);
293 snap_type = ETHERTYPE_IP;
298 ah = mtod(m, struct arphdr *);
299 ah->ar_hrd = htons(ARPHRD_IEEE802);
301 loop_copy = -1; /* if this is for us, don't do it */
303 switch(ntohs(ah->ar_op)) {
304 case ARPOP_REVREQUEST:
306 snap_type = ETHERTYPE_REVARP;
311 snap_type = ETHERTYPE_ARP;
315 if (m->m_flags & M_BCAST)
316 bcopy(ifp->if_broadcastaddr, edst, ISO88025_ADDR_LEN);
318 bcopy(ar_tha(ah), edst, ISO88025_ADDR_LEN);
325 error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle);
328 snap_type = ETHERTYPE_IPV6;
336 bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst,
339 M_PREPEND(m, 3, M_WAITOK);
343 cp = mtod(m, u_int8_t *);
344 *cp++ = ETHERTYPE_IPX_8022;
345 *cp++ = ETHERTYPE_IPX_8022;
352 const struct iso88025_sockaddr_data *sd;
354 * For AF_UNSPEC sockaddr.sa_data must contain all of the
355 * mac information needed to send the packet. This allows
356 * full mac, llc, and source routing function to be controlled.
357 * llc and source routing information must already be in the
358 * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data
359 * should be an iso88025_sockaddr_data structure see iso88025.h
362 sd = (const struct iso88025_sockaddr_data *)dst->sa_data;
365 (void)memcpy(edst, sd->ether_dhost, ISO88025_ADDR_LEN);
366 (void)memcpy(gen_th.iso88025_shost, sd->ether_shost,
372 if_printf(ifp, "can't handle af%d\n", dst->sa_family);
373 senderr(EAFNOSUPPORT);
380 if (snap_type != 0) {
382 M_PREPEND(m, LLC_SNAPFRAMELEN, M_NOWAIT);
385 l = mtod(m, struct llc *);
386 l->llc_control = LLC_UI;
387 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
388 l->llc_snap.org_code[0] =
389 l->llc_snap.org_code[1] =
390 l->llc_snap.org_code[2] = 0;
391 l->llc_snap.ether_type = htons(snap_type);
395 * Add local net header. If no space in first mbuf,
398 M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_NOWAIT);
401 th = mtod(m, struct iso88025_header *);
402 bcopy((caddr_t)edst, (caddr_t)&gen_th.iso88025_dhost, ISO88025_ADDR_LEN);
404 /* Copy as much of the generic header as is needed into the mbuf */
405 memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len);
408 * If a simplex interface, and the packet is being sent to our
409 * Ethernet address or a broadcast address, loopback a copy.
410 * XXX To make a simplex device behave exactly like a duplex
411 * device, we should copy in the case of sending to our own
412 * ethernet address (thus letting the original actually appear
413 * on the wire). However, we don't do that here for security
414 * reasons and compatibility with the original behavior.
416 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
417 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
419 n = m_copy(m, 0, (int)M_COPYALL);
420 (void) if_simloop(ifp, n, dst->sa_family,
422 } else if (bcmp(th->iso88025_dhost, th->iso88025_shost,
423 ETHER_ADDR_LEN) == 0) {
424 (void) if_simloop(ifp, m, dst->sa_family,
430 IFQ_HANDOFF_ADJ(ifp, m, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN, error);
432 printf("iso88025_output: packet dropped QFULL.\n");
445 * ISO 88025 de-encapsulation
448 iso88025_input(ifp, m)
452 struct iso88025_header *th;
458 * Do consistency checks to verify assumptions
459 * made by code past this point.
461 if ((m->m_flags & M_PKTHDR) == 0) {
462 if_printf(ifp, "discard frame w/o packet header\n");
467 if (m->m_pkthdr.rcvif == NULL) {
468 if_printf(ifp, "discard frame w/o interface pointer\n");
474 m = m_pullup(m, ISO88025_HDR_LEN);
479 th = mtod(m, struct iso88025_header *);
482 * Discard packet if interface is not up.
484 if (!((ifp->if_flags & IFF_UP) &&
485 (ifp->if_drv_flags & IFF_DRV_RUNNING)))
489 * Give bpf a chance at the packet.
494 * Interface marked for monitoring; discard packet.
496 if (ifp->if_flags & IFF_MONITOR) {
502 mac_ifnet_create_mbuf(ifp, m);
506 * Update interface statistics.
508 ifp->if_ibytes += m->m_pkthdr.len;
509 getmicrotime(&ifp->if_lastchange);
512 * Discard non local unicast packets when interface
513 * is in promiscuous mode.
515 if ((ifp->if_flags & IFF_PROMISC) &&
516 ((th->iso88025_dhost[0] & 1) == 0) &&
517 (bcmp(IF_LLADDR(ifp), (caddr_t) th->iso88025_dhost,
518 ISO88025_ADDR_LEN) != 0))
522 * Set mbuf flags for bcast/mcast.
524 if (th->iso88025_dhost[0] & 1) {
525 if (bcmp(iso88025_broadcastaddr, th->iso88025_dhost,
526 ISO88025_ADDR_LEN) == 0)
527 m->m_flags |= M_BCAST;
529 m->m_flags |= M_MCAST;
533 mac_hdr_len = ISO88025_HDR_LEN;
534 /* Check for source routing info */
535 if (th->iso88025_shost[0] & TR_RII)
536 mac_hdr_len += TR_RCF_RIFLEN(th->rcf);
538 /* Strip off ISO88025 header. */
539 m_adj(m, mac_hdr_len);
541 m = m_pullup(m, LLC_SNAPFRAMELEN);
546 l = mtod(m, struct llc *);
548 switch (l->llc_dsap) {
550 case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */
551 if ((l->llc_control != LLC_UI) ||
552 (l->llc_ssap != ETHERTYPE_IPX_8022)) {
557 th->iso88025_shost[0] &= ~(TR_RII);
562 case LLC_SNAP_LSAP: {
564 if ((l->llc_control != LLC_UI) ||
565 (l->llc_ssap != LLC_SNAP_LSAP)) {
570 if (l->llc_snap.org_code[0] != 0 ||
571 l->llc_snap.org_code[1] != 0 ||
572 l->llc_snap.org_code[2] != 0) {
577 type = ntohs(l->llc_snap.ether_type);
578 m_adj(m, LLC_SNAPFRAMELEN);
582 th->iso88025_shost[0] &= ~(TR_RII);
583 if ((m = ip_fastforward(m)) == NULL)
589 if (ifp->if_flags & IFF_NOARP)
594 #ifdef IPX_SNAP /* XXX: Not supported! */
596 th->iso88025_shost[0] &= ~(TR_RII);
599 #endif /* IPX_SNAP */
602 th->iso88025_shost[0] &= ~(TR_RII);
607 printf("iso88025_input: unexpected llc_snap ether_type 0x%02x\n", type);
615 switch (l->llc_control) {
622 if(m->m_len < ISO88025_ADDR_LEN)
627 l->llc_dsap = l->llc_ssap = 0;
628 /* Fall through to */
634 struct iso88025_sockaddr_data *th2;
640 if (th->iso88025_shost[0] & TR_RII) { /* XXX */
641 printf("iso88025_input: dropping source routed LLC_TEST\n");
644 l->llc_dsap = l->llc_ssap;
646 if (m->m_flags & (M_BCAST | M_MCAST))
647 bcopy((caddr_t)IF_LLADDR(ifp),
648 (caddr_t)th->iso88025_dhost,
650 sa.sa_family = AF_UNSPEC;
651 sa.sa_len = sizeof(sa);
652 th2 = (struct iso88025_sockaddr_data *)sa.sa_data;
653 for (i = 0; i < ISO88025_ADDR_LEN; i++) {
654 th2->ether_shost[i] = c = th->iso88025_dhost[i];
655 th2->ether_dhost[i] = th->iso88025_dhost[i] =
656 th->iso88025_shost[i];
657 th->iso88025_shost[i] = c;
660 th2->fc = TR_LLC_FRAME;
661 ifp->if_output(ifp, m, &sa, NULL);
665 printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control);
673 printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap);
679 M_SETFIB(m, ifp->if_fib);
680 netisr_dispatch(isr, m);
691 iso88025_resolvemulti (ifp, llsa, sa)
693 struct sockaddr **llsa;
696 struct sockaddr_dl *sdl;
698 struct sockaddr_in *sin;
701 struct sockaddr_in6 *sin6;
705 switch(sa->sa_family) {
708 * No mapping needed. Just check that it's a valid MC address.
710 sdl = (struct sockaddr_dl *)sa;
711 e_addr = LLADDR(sdl);
712 if ((e_addr[0] & 1) != 1) {
713 return (EADDRNOTAVAIL);
720 sin = (struct sockaddr_in *)sa;
721 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
722 return (EADDRNOTAVAIL);
724 sdl = link_init_sdl(ifp, *llsa, IFT_ISO88025);
725 sdl->sdl_alen = ISO88025_ADDR_LEN;
726 e_addr = LLADDR(sdl);
727 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
728 *llsa = (struct sockaddr *)sdl;
733 sin6 = (struct sockaddr_in6 *)sa;
734 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
736 * An IP6 address of 0 means listen to all
737 * of the Ethernet multicast address used for IP6.
738 * (This is used for multicast routers.)
740 ifp->if_flags |= IFF_ALLMULTI;
744 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
745 return (EADDRNOTAVAIL);
747 sdl = link_init_sdl(ifp, *llsa, IFT_ISO88025);
748 sdl->sdl_alen = ISO88025_ADDR_LEN;
749 e_addr = LLADDR(sdl);
750 ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
751 *llsa = (struct sockaddr *)sdl;
757 * Well, the text isn't quite right, but it's the name
760 return (EAFNOSUPPORT);
766 static MALLOC_DEFINE(M_ISO88025, "arpcom", "802.5 interface internals");
769 iso88025_alloc(u_char type, struct ifnet *ifp)
773 ac = malloc(sizeof(struct arpcom), M_ISO88025, M_WAITOK | M_ZERO);
780 iso88025_free(void *com, u_char type)
783 free(com, M_ISO88025);
787 iso88025_modevent(module_t mod, int type, void *data)
792 if_register_com_alloc(IFT_ISO88025, iso88025_alloc,
796 if_deregister_com_alloc(IFT_ISO88025);
805 static moduledata_t iso88025_mod = {
811 DECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
812 MODULE_VERSION(iso88025, 1);