if_iso88025subr.c revision 96184
1271609Savg/*
2271609Savg * Copyright (c) 1998, Larry Lile
3271609Savg * All rights reserved.
4271609Savg *
5271609Savg * For latest sources and information on this driver, please
6271609Savg * go to http://anarchy.stdio.com.
7271609Savg *
8271609Savg * Questions, comments or suggestions should be directed to
9271609Savg * Larry Lile <lile@stdio.com>.
10271609Savg *
11271609Savg * Redistribution and use in source and binary forms, with or without
12271609Savg * modification, are permitted provided that the following conditions
13271609Savg * are met:
14271609Savg * 1. Redistributions of source code must retain the above copyright
15271609Savg *    notice unmodified, this list of conditions, and the following
16271609Savg *    disclaimer.
17271609Savg * 2. Redistributions in binary form must reproduce the above copyright
18271609Savg *    notice, this list of conditions and the following disclaimer in the
19271609Savg *    documentation and/or other materials provided with the distribution.
20271609Savg *
21271609Savg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22271609Savg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23271609Savg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24271609Savg * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25271609Savg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26271609Savg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27271609Savg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28271609Savg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29271609Savg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30271609Savg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31271609Savg * SUCH DAMAGE.
32271609Savg *
33271609Savg * $FreeBSD: head/sys/net/if_iso88025subr.c 96184 2002-05-07 22:14:06Z kbyanc $
34271609Savg *
35271609Savg */
36271609Savg
37271609Savg/*
38271609Savg *
39271609Savg * General ISO 802.5 (Token Ring) support routines
40271609Savg *
41271609Savg */
42271609Savg
43271609Savg#include "opt_inet.h"
44271609Savg#include "opt_inet6.h"
45271609Savg#include "opt_ipx.h"
46271609Savg
47271609Savg#include <sys/param.h>
48271609Savg#include <sys/systm.h>
49271609Savg#include <sys/mbuf.h>
50271609Savg#include <sys/socket.h>
51271609Savg#include <sys/sockio.h>
52271609Savg#include <sys/sysctl.h>
53271609Savg
54271609Savg#include <net/if.h>
55271609Savg#include <net/netisr.h>
56271609Savg#include <net/route.h>
57271609Savg#include <net/if_llc.h>
58271609Savg#include <net/if_dl.h>
59271609Savg#include <net/if_types.h>
60271609Savg
61271609Savg#include <net/if_arp.h>
62271609Savg
63271609Savg#include <net/iso88025.h>
64271609Savg
65271609Savg#if defined(INET) || defined(INET6)
66271609Savg#include <netinet/in.h>
67271609Savg#include <netinet/in_var.h>
68271609Savg#include <netinet/if_ether.h>
69271609Savg#endif
70271609Savg#ifdef INET6
71271609Savg#include <netinet6/nd6.h>
72271609Savg#endif
73271609Savg
74271609Savg#ifdef IPX
75271609Savg#include <netipx/ipx.h>
76271609Savg#include <netipx/ipx_if.h>
77271609Savg#endif
78271609Savg
79271609Savg#include <net/bpf.h>
80271609Savg
81271609Savg#include <machine/md_var.h>
82271609Savg
83271609Savg#include <vm/vm.h>
84271609Savg#include <vm/vm_param.h>
85271609Savg#include <vm/pmap.h>
86271609Savg
87271609Savg#include <net/iso88025.h>
88271609Savg
89271609Savg#define IFP2AC(IFP) ((struct arpcom *)IFP)
90271609Savg
91271609Savgvoid
92271609Savgiso88025_ifattach(struct ifnet *ifp)
93271609Savg{
94271609Savg    register struct ifaddr *ifa = NULL;
95271609Savg    register struct sockaddr_dl *sdl;
96271609Savg
97271609Savg    ifp->if_type = IFT_ISO88025;
98271609Savg    ifp->if_addrlen = ISO88025_ADDR_LEN;
99271609Savg    ifp->if_hdrlen = ISO88025_HDR_LEN;
100271609Savg    if (ifp->if_baudrate == 0)
101271609Savg        ifp->if_baudrate = TR_16MBPS; /* 16Mbit should be a safe default */
102271609Savg    if (ifp->if_mtu == 0)
103271609Savg        ifp->if_mtu = ISO88025_DEFAULT_MTU;
104271609Savg    ifp->if_broadcastaddr = etherbroadcastaddr;
105271609Savg
106271609Savg        ifa = ifaddr_byindex(ifp->if_index);
107271609Savg        if (ifa == 0) {
108271609Savg                printf("iso88025_ifattach: no lladdr!\n");
109271609Savg                return;
110271609Savg        }
111271609Savg        sdl = (struct sockaddr_dl *)ifa->ifa_addr;
112271609Savg        sdl->sdl_type = IFT_ISO88025;
113271609Savg        sdl->sdl_alen = ifp->if_addrlen;
114271609Savg        bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
115271609Savg}
116271609Savg
117271609Savg/*
118271609Savg * Perform common duties while detaching a Token Ring interface
119271609Savg */
120271609Savgvoid
121271609Savgiso88025_ifdetach(ifp, bpf)
122271609Savg        struct ifnet *ifp;
123271609Savg        int bpf;
124271609Savg{
125271609Savg	if (bpf)
126271609Savg                bpfdetach(ifp);
127271609Savg	if_detach(ifp);
128271609Savg}
129271609Savg
130271609Savg
131271609Savgint
132271609Savgiso88025_ioctl(struct ifnet *ifp, int command, caddr_t data)
133271609Savg{
134271609Savg        struct ifaddr *ifa = (struct ifaddr *) data;
135271609Savg        struct ifreq *ifr = (struct ifreq *) data;
136271609Savg        int error = 0;
137271609Savg
138271609Savg        switch (command) {
139271609Savg        case SIOCSIFADDR:
140271609Savg                ifp->if_flags |= IFF_UP;
141271609Savg
142271609Savg                switch (ifa->ifa_addr->sa_family) {
143271609Savg#ifdef INET
144271609Savg                case AF_INET:
145271609Savg                        ifp->if_init(ifp->if_softc);    /* before arpwhohas */
146271609Savg                        arp_ifinit(ifp, ifa);
147271609Savg                        break;
148271609Savg#endif	/* INET */
149271609Savg#ifdef IPX
150271609Savg                /*
151271609Savg                 * XXX - This code is probably wrong
152271609Savg                 */
153271609Savg                case AF_IPX:
154271609Savg                        {
155271609Savg                        register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
156271609Savg                        struct arpcom *ac = IFP2AC(ifp);
157271609Savg
158271609Savg                        if (ipx_nullhost(*ina))
159271609Savg                                ina->x_host =
160271609Savg                                    *(union ipx_host *)
161271609Savg                                    ac->ac_enaddr;
162271609Savg                        else {
163271609Savg                                bcopy((caddr_t) ina->x_host.c_host,
164271609Savg                                      (caddr_t) ac->ac_enaddr,
165271609Savg                                      sizeof(ac->ac_enaddr));
166271609Savg                        }
167271609Savg
168271609Savg                        /*
169271609Savg                         * Set new address
170271609Savg                         */
171271609Savg                        ifp->if_init(ifp->if_softc);
172271609Savg                        break;
173271609Savg                        }
174271609Savg#endif	/* IPX */
175271609Savg                default:
176271609Savg                        ifp->if_init(ifp->if_softc);
177271609Savg                        break;
178271609Savg                }
179271609Savg                break;
180271609Savg
181271609Savg        case SIOCGIFADDR:
182271609Savg                {
183271609Savg                        struct sockaddr *sa;
184271609Savg
185271609Savg                        sa = (struct sockaddr *) & ifr->ifr_data;
186271609Savg                        bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr,
187271609Savg                              (caddr_t) sa->sa_data, ISO88025_ADDR_LEN);
188271609Savg                }
189271609Savg                break;
190271609Savg
191271609Savg        case SIOCSIFMTU:
192271609Savg                /*
193271609Savg                 * Set the interface MTU.
194                 */
195                if (ifr->ifr_mtu > ISO88025_MAX_MTU) {
196                        error = EINVAL;
197                } else {
198                        ifp->if_mtu = ifr->ifr_mtu;
199                }
200                break;
201        }
202        return (error);
203}
204
205/*
206 * ISO88025 encapsulation
207 */
208int
209iso88025_output(ifp, m, dst, rt0)
210	struct ifnet *ifp;
211	struct mbuf *m;
212	struct sockaddr *dst;
213	struct rtentry *rt0;
214{
215	u_int16_t snap_type = 0;
216	int loop_copy = 0, error = 0, rif_len = 0;
217	u_char edst[ISO88025_ADDR_LEN];
218	struct iso88025_header *th;
219	struct iso88025_header gen_th;
220	struct sockaddr_dl *sdl = NULL;
221	struct rtentry *rt;
222	struct arpcom *ac = (struct arpcom *)ifp;
223
224	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
225		senderr(ENETDOWN);
226	getmicrotime(&ifp->if_lastchange);
227
228	rt = rt0;
229	if (rt != NULL) {
230		if ((rt->rt_flags & RTF_UP) == 0) {
231			rt0 = rt = rtalloc1(dst, 1, 0UL);
232			if (rt0)
233				rt->rt_refcnt--;
234			else
235				senderr(EHOSTUNREACH);
236		}
237		if (rt->rt_flags & RTF_GATEWAY) {
238			if (rt->rt_gwroute == 0)
239				goto lookup;
240			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
241				rtfree(rt); rt = rt0;
242			lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1,
243							  0UL);
244				if ((rt = rt->rt_gwroute) == 0)
245					senderr(EHOSTUNREACH);
246			}
247		}
248		if (rt->rt_flags & RTF_REJECT)
249			if (rt->rt_rmx.rmx_expire == 0 ||
250			    time_second < rt->rt_rmx.rmx_expire)
251				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
252	}
253
254	/* Calculate routing info length based on arp table entry */
255	if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway))
256		if (SDL_ISO88025(sdl)->trld_rcf != NULL)
257			rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf);
258
259	/* Generate a generic 802.5 header for the packet */
260	gen_th.ac = TR_AC;
261	gen_th.fc = TR_LLC_FRAME;
262	(void)memcpy((caddr_t)gen_th.iso88025_shost, (caddr_t)ac->ac_enaddr,
263		sizeof(ac->ac_enaddr));
264	if (rif_len) {
265		gen_th.iso88025_shost[0] |= TR_RII;
266		if (rif_len > 2) {
267			gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf;
268			(void)memcpy((caddr_t)gen_th.rd,
269				(caddr_t)SDL_ISO88025(sdl)->trld_route,
270				rif_len - 2);
271		}
272	}
273
274	switch (dst->sa_family) {
275#ifdef INET
276	case AF_INET:
277		if (!arpresolve(ifp, rt, m, dst, edst, rt0))
278			return (0);	/* if not yet resolved */
279		snap_type = ETHERTYPE_IP;
280		break;
281#endif	/* INET */
282#ifdef NOT_YET
283#ifdef INET6
284	case AF_INET6:
285		if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) {
286			/* Something bad happened */
287			return(0);
288		}
289		snap_type = ETHERTYPE_IPV6;
290		break;
291#endif	/* INET6 */
292#endif	/* NOT_YET */
293#ifdef IPX
294	case AF_IPX:
295	{
296		u_int8_t	*cp;
297
298		snap_type = 0;
299		bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst,
300			sizeof (edst));
301
302		M_PREPEND(m, 3, M_TRYWAIT);
303		if (m == 0)
304			senderr(ENOBUFS);
305		m = m_pullup(m, 3);
306		if (m == 0)
307			senderr(ENOBUFS);
308		cp = mtod(m, u_int8_t *);
309		*cp++ = ETHERTYPE_IPX_8022;
310		*cp++ = ETHERTYPE_IPX_8022;
311		*cp++ = LLC_UI;
312	}
313	break;
314#endif	/* IPX */
315	case AF_UNSPEC:
316	{
317		struct iso88025_sockaddr_data *sd;
318		/*
319		 * For AF_UNSPEC sockaddr.sa_data must contain all of the
320		 * mac information needed to send the packet.  This allows
321		 * full mac, llc, and source routing function to be controlled.
322		 * llc and source routing information must already be in the
323		 * mbuf provided, ac/fc are set in sa_data.  sockaddr.sa_data
324		 * should be a iso88025_sockaddr_data structure see iso88025.h
325		 */
326                loop_copy = -1;
327		sd = (struct iso88025_sockaddr_data *)dst->sa_data;
328		gen_th.ac = sd->ac;
329		gen_th.fc = sd->fc;
330		(void)memcpy((caddr_t)edst, (caddr_t)sd->ether_dhost,
331			sizeof(sd->ether_dhost));
332		(void)memcpy((caddr_t)gen_th.iso88025_shost,
333			(caddr_t)sd->ether_shost, sizeof(sd->ether_shost));
334		rif_len = 0;
335		break;
336	}
337	default:
338		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
339			dst->sa_family);
340		senderr(EAFNOSUPPORT);
341		break;
342	}
343
344	if (snap_type != 0) {
345        	struct llc *l;
346		M_PREPEND(m, sizeof (struct llc), M_DONTWAIT);
347		if (m == 0)
348			senderr(ENOBUFS);
349		l = mtod(m, struct llc *);
350		l->llc_un.type_snap.ether_type = htons(snap_type);
351		l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
352		l->llc_un.type_snap.control = LLC_UI;
353		l->llc_un.type_snap.org_code[0] =
354			l->llc_un.type_snap.org_code[1] =
355			l->llc_un.type_snap.org_code[2] = 0;
356	}
357
358	/*
359	 * Add local net header.  If no space in first mbuf,
360	 * allocate another.
361	 */
362	M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_DONTWAIT);
363	if (m == 0)
364		senderr(ENOBUFS);
365
366	(void)memcpy((caddr_t)&gen_th.iso88025_dhost, (caddr_t)edst,
367		     sizeof(edst));
368
369	/* Copy as much of the generic header as is needed into the mbuf */
370	th = mtod(m, struct iso88025_header *);
371	memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len);
372
373        /*
374         * If a simplex interface, and the packet is being sent to our
375         * Ethernet address or a broadcast address, loopback a copy.
376         * XXX To make a simplex device behave exactly like a duplex
377         * device, we should copy in the case of sending to our own
378         * ethernet address (thus letting the original actually appear
379         * on the wire). However, we don't do that here for security
380         * reasons and compatibility with the original behavior.
381         */
382        if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
383                if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
384                        struct mbuf *n;
385			n = m_copy(m, 0, (int)M_COPYALL);
386                        (void)if_simloop(ifp, n, dst->sa_family,
387					  ISO88025_HDR_LEN);
388                } else
389			if (bcmp(th->iso88025_dhost, th->iso88025_shost,
390				 ETHER_ADDR_LEN) == 0) {
391				(void)if_simloop(ifp, m, dst->sa_family,
392						 ISO88025_HDR_LEN);
393                        	return(0);      /* XXX */
394			}
395        }
396
397	if (! IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, ISO88025_HDR_LEN + (sizeof(struct llc))) ) {
398		printf("iso88025_output: packet dropped QFULL.\n");
399		senderr(ENOBUFS);
400	}
401	return (error);
402
403bad:
404	if (m)
405		m_freem(m);
406	return (error);
407}
408
409/*
410 * ISO 88025 de-encapsulation
411 */
412void
413iso88025_input(ifp, th, m)
414	struct ifnet *ifp;
415	struct iso88025_header *th;
416	struct mbuf *m;
417{
418	register struct ifqueue *inq;
419	register struct llc *l;
420
421	if ((ifp->if_flags & IFF_UP) == 0) {
422		m_freem(m);
423		return;
424	}
425
426	getmicrotime(&ifp->if_lastchange);
427	ifp->if_ibytes += m->m_pkthdr.len + sizeof(*th);
428
429	if (th->iso88025_dhost[0] & 1) {
430		if (bcmp((caddr_t)etherbroadcastaddr,
431			 (caddr_t)th->iso88025_dhost,
432			 sizeof(etherbroadcastaddr)) == 0)
433			m->m_flags |= M_BCAST;
434		else
435			m->m_flags |= M_MCAST;
436		ifp->if_imcasts++;
437	}
438
439	l = mtod(m, struct llc *);
440
441	switch (l->llc_dsap) {
442#ifdef IPX
443	case ETHERTYPE_IPX_8022:	/* Thanks a bunch Novell */
444		if ((l->llc_control != LLC_UI) ||
445		    (l->llc_ssap != ETHERTYPE_IPX_8022))
446			goto dropanyway;
447
448		th->iso88025_shost[0] &= ~(TR_RII);
449		m_adj(m, 3);
450		schednetisr(NETISR_IPX);
451		inq = &ipxintrq;
452		break;
453#endif	/* IPX */
454	case LLC_SNAP_LSAP: {
455		u_int16_t type;
456		if ((l->llc_control != LLC_UI) ||
457		    (l->llc_ssap != LLC_SNAP_LSAP))
458			goto dropanyway;
459
460		if (l->llc_un.type_snap.org_code[0] != 0 ||
461		    l->llc_un.type_snap.org_code[1] != 0 ||
462		    l->llc_un.type_snap.org_code[2] != 0)
463			goto dropanyway;
464
465		type = ntohs(l->llc_un.type_snap.ether_type);
466		m_adj(m, sizeof(struct llc));
467		switch (type) {
468#ifdef INET
469		case ETHERTYPE_IP:
470			th->iso88025_shost[0] &= ~(TR_RII);
471			if (ipflow_fastforward(m))
472				return;
473			schednetisr(NETISR_IP);
474			inq = &ipintrq;
475			break;
476
477		case ETHERTYPE_ARP:
478			if (ifp->if_flags & IFF_NOARP)
479				goto dropanyway;
480			schednetisr(NETISR_ARP);
481			inq = &arpintrq;
482			break;
483#endif	/* INET */
484#ifdef IPX_SNAP	/* XXX: Not supported! */
485		case ETHERTYPE_IPX:
486			th->iso88025_shost[0] &= ~(TR_RII);
487			schednetisr(NETISR_IPX);
488			inq = &ipxintrq;
489			break;
490#endif	/* IPX_SNAP */
491#ifdef NOT_YET
492#ifdef INET6
493		case ETHERTYPE_IPV6:
494			th->iso88025_shost[0] &= ~(TR_RII);
495			schednetisr(NETISR_IPV6);
496			inq = &ip6intrq;
497			break;
498#endif	/* INET6 */
499#endif	/* NOT_YET */
500		default:
501			printf("iso88025_input: unexpected llc_snap ether_type  0x%02x\n", type);
502			m_freem(m);
503			return;
504		}
505		break;
506	}
507	case LLC_ISO_LSAP:
508		switch (l->llc_control) {
509		case LLC_UI:
510			goto dropanyway;
511			break;
512                case LLC_XID:
513                case LLC_XID_P:
514			if(m->m_len < ISO88025_ADDR_LEN)
515				goto dropanyway;
516			l->llc_window = 0;
517			l->llc_fid = 9;
518			l->llc_class = 1;
519			l->llc_dsap = l->llc_ssap = 0;
520			/* Fall through to */
521		case LLC_TEST:
522		case LLC_TEST_P:
523		{
524			struct sockaddr sa;
525			struct arpcom *ac = (struct arpcom *)ifp;
526			struct iso88025_sockaddr_data *th2;
527			int i;
528			u_char c = l->llc_dsap;
529
530			if (th->iso88025_shost[0] & TR_RII) { /* XXX */
531				printf("iso88025_input: dropping source routed LLC_TEST\n");
532				m_free(m);
533				return;
534			}
535			l->llc_dsap = l->llc_ssap;
536			l->llc_ssap = c;
537			if (m->m_flags & (M_BCAST | M_MCAST))
538				bcopy((caddr_t)ac->ac_enaddr,
539			      		(caddr_t)th->iso88025_dhost,
540					ISO88025_ADDR_LEN);
541			sa.sa_family = AF_UNSPEC;
542			sa.sa_len = sizeof(sa);
543			th2 = (struct iso88025_sockaddr_data *)sa.sa_data;
544			for (i = 0; i < ISO88025_ADDR_LEN; i++) {
545				th2->ether_shost[i] = c = th->iso88025_dhost[i];
546				th2->ether_dhost[i] = th->iso88025_dhost[i] =
547					th->iso88025_shost[i];
548				th->iso88025_shost[i] = c;
549			}
550			th2->ac = TR_AC;
551			th2->fc = TR_LLC_FRAME;
552			ifp->if_output(ifp, m, &sa, NULL);
553			return;
554		}
555		default:
556			printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control);
557			m_freem(m);
558			return;
559		}
560		break;
561	default:
562		printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap);
563		ifp->if_noproto++;
564	dropanyway:
565		m_freem(m);
566		return;
567	}
568
569	if (! IF_HANDOFF(inq, m, NULL))
570                printf("iso88025_input: Packet dropped (Queue full).\n");
571}
572