I've got a patch against -CURRENT to get our token ring code working against Novell 802.2 style IPX. This patch also may enable IPv6, however additional patches (not included) are required. I also took the time to do some code cleanups. :/ Anyhow, please find attached. My test consisted of mounting a Netware share using NWFS. # mount -a Filesystem 1K-blocks Used Avail Capacity Mounted on ... /SEX_KITTEN:WINTER/SYS 91980 28256 63724 31% /mnt # cd /mnt # du -s . 24642 . # Interested parties will also note that tcpdump is unable to properly decode IPX packets over token ring; I've got a fix for this too... -- | Matthew N. Dodd | '78 Datsun 280Z | '75 Volvo 164E | FreeBSD/NetBSD | | [EMAIL PROTECTED] | 2 x '84 Volvo 245DL | ix86,sparc,pmax | | http://www.jurai.net/~winter | This Space For Rent | ISO8802.5 4ever |
Index: if_iso88025subr.c =================================================================== RCS file: /cvs/src/sys/net/if_iso88025subr.c,v retrieving revision 1.14 diff -u -r1.14 if_iso88025subr.c --- if_iso88025subr.c 2000/11/25 07:35:31 1.14 +++ if_iso88025subr.c 2001/03/09 10:18:47 @@ -41,6 +41,8 @@ */ #include "opt_inet.h" +#include "opt_inet6.h" +#include "opt_ipx.h" #include <sys/param.h> #include <sys/systm.h> @@ -60,11 +62,19 @@ #include <net/iso88025.h> -#ifdef INET +#if defined(INET) || defined(INET6) #include <netinet/in.h> #include <netinet/in_var.h> #include <netinet/if_ether.h> #endif +#ifdef INET6 +#include <netinet6/nd6.h> +#endif + +#ifdef IPX +#include <netipx/ipx.h> +#include <netipx/ipx_if.h> +#endif #include <net/bpf.h> @@ -78,6 +88,8 @@ #include <net/iso88025.h> +#define IFP2AC(IFP) ((struct arpcom *)IFP) + void iso88025_ifattach(struct ifnet *ifp) { @@ -103,6 +115,20 @@ bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); } +/* + * Perform common duties while detaching a Token Ring interface + */ +void +iso88025_ifdetach(ifp, bpf) + struct ifnet *ifp; + int bpf; +{ + if (bpf) + bpfdetach(ifp); + if_detach(ifp); +} + + int iso88025_ioctl(struct ifnet *ifp, int command, caddr_t data) { @@ -121,6 +147,32 @@ arp_ifinit((struct arpcom *)ifp, ifa); break; #endif +#ifdef IPX + /* + * XXX - This code is probably wrong + */ + case AF_IPX: + { + register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); + struct arpcom *ac = IFP2AC(ifp); + + if (ipx_nullhost(*ina)) + ina->x_host = + *(union ipx_host *) + ac->ac_enaddr; + else { + bcopy((caddr_t) ina->x_host.c_host, + (caddr_t) ac->ac_enaddr, + sizeof(ac->ac_enaddr)); + } + + /* + * Set new address + */ + ifp->if_init(ifp->if_softc); + break; + } +#endif default: ifp->if_init(ifp->if_softc); break; @@ -155,23 +207,27 @@ * ISO88025 encapsulation */ int -iso88025_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt0) +iso88025_output(ifp, m, dst, rt0) + struct ifnet *ifp; + struct mbuf *m; + struct sockaddr *dst; + struct rtentry *rt0; { - register struct iso88025_header *th; + u_int16_t type = 0; + int loop_copy = 0, error = 0, rif_len = 0; + u_char edst[ISO88025_ADDR_LEN]; + struct iso88025_header *th; struct iso88025_header gen_th; - register struct iso88025_sockaddr_data *sd = (struct iso88025_sockaddr_data *)dst->sa_data; - register struct llc *l; - register struct sockaddr_dl *sdl = NULL; - int error = 0, rif_len = 0; - u_char edst[6]; - register struct rtentry *rt; - int loop_copy = 0; + struct sockaddr_dl *sdl = NULL; + struct rtentry *rt; struct arpcom *ac = (struct arpcom *)ifp; if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) senderr(ENETDOWN); + getmicrotime(&ifp->if_lastchange); + rt = rt0; - if (rt) { + if (rt != NULL) { if ((rt->rt_flags & RTF_UP) == 0) { rt0 = rt = rtalloc1(dst, 1, 0UL); if (rt0) @@ -204,37 +260,61 @@ /* Generate a generic 802.5 header for the packet */ gen_th.ac = TR_AC; gen_th.fc = TR_LLC_FRAME; - memcpy(gen_th.iso88025_shost, ac->ac_enaddr, sizeof(ac->ac_enaddr)); + (void)memcpy((caddr_t)gen_th.iso88025_shost, (caddr_t)ac->ac_enaddr, + sizeof(ac->ac_enaddr)); if (rif_len) { gen_th.iso88025_shost[0] |= TR_RII; if (rif_len > 2) { gen_th.rcf = sdl->sdl_rcf; - memcpy(gen_th.rd, sdl->sdl_route, rif_len - 2); + (void)memcpy((caddr_t)gen_th.rd, + (caddr_t)sdl->sdl_route, rif_len - 2); } } - switch (dst->sa_family) { #ifdef INET case AF_INET: if (!arpresolve(ac, rt, m, dst, edst, rt0)) return (0); /* if not yet resolved */ - /* Add LLC and SNAP headers */ - M_PREPEND(m, 8, M_DONTWAIT); - if (m == 0) - senderr(ENOBUFS); - l = mtod(m, struct llc *); - l->llc_un.type_snap.ether_type = htons(ETHERTYPE_IP); - l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; - l->llc_un.type_snap.control = LLC_UI; - l->llc_un.type_snap.org_code[0] = 0x0; - l->llc_un.type_snap.org_code[1] = 0x0; - l->llc_un.type_snap.org_code[2] = 0x0; - memcpy(gen_th.iso88025_dhost, edst, sizeof(edst)); + type = ETHERTYPE_IP; + break; +#endif +#ifdef INET6 + case AF_INET6: + if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) { + /* this must be impossible, so we bark */ + printf("nd6_storelladdr failed\n"); + return(0); + } + type = ETHERTYPE_IPV6; break; #endif +#ifdef IPX + case AF_IPX: + { + u_int8_t *cp; + type = 0; + bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst, + sizeof (edst)); +/* &(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), */ + + M_PREPEND(m, 3, M_TRYWAIT); + if (m == 0) + senderr(ENOBUFS); + m = m_pullup(m, 3); + if (m == 0) + senderr(ENOBUFS); + cp = mtod(m, u_int8_t *); + *cp++ = ETHERTYPE_IPX_8022; + *cp++ = ETHERTYPE_IPX_8022; + *cp++ = 0x03; + } + break; +#endif case AF_UNSPEC: + { + struct iso88025_sockaddr_data *sd; /* * For AF_UNSPEC sockaddr.sa_data must contain all of the * mac information needed to send the packet. This allows @@ -247,26 +327,45 @@ sd = (struct iso88025_sockaddr_data *)dst->sa_data; gen_th.ac = sd->ac; gen_th.fc = sd->fc; - memcpy(gen_th.iso88025_dhost, sd->ether_dhost, sizeof(sd->ether_dhost)); - memcpy(gen_th.iso88025_shost, sd->ether_shost, sizeof(sd->ether_shost)); + (void)memcpy((caddr_t)edst, (caddr_t)sd->ether_dhost, + sizeof(sd->ether_dhost)); + (void)memcpy((caddr_t)gen_th.iso88025_shost, + (caddr_t)sd->ether_shost, sizeof(sd->ether_shost)); rif_len = 0; break; - + } default: printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, dst->sa_family); senderr(EAFNOSUPPORT); + break; } + if (type != 0) { + struct llc *l; + M_PREPEND(m, sizeof (struct llc), M_DONTWAIT); + if (m == 0) + senderr(ENOBUFS); + l = mtod(m, struct llc *); + l->llc_un.type_snap.ether_type = htons(type); + l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; + l->llc_un.type_snap.control = LLC_UI; + l->llc_un.type_snap.org_code[0] = + l->llc_un.type_snap.org_code[1] = + l->llc_un.type_snap.org_code[2] = 0; + } + /* * Add local net header. If no space in first mbuf, * allocate another. */ - M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_DONTWAIT); if (m == 0) senderr(ENOBUFS); + (void)memcpy((caddr_t)&gen_th.iso88025_dhost, (caddr_t)edst, + sizeof(edst)); + /* Copy as much of the generic header as is needed into the mbuf */ th = mtod(m, struct iso88025_header *); memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len); @@ -280,21 +379,22 @@ * on the wire). However, we don't do that here for security * reasons and compatibility with the original behavior. */ - if ((ifp->if_flags & IFF_SIMPLEX) && - (loop_copy != -1)) { + if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { - struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); - (void) if_simloop(ifp, - n, dst->sa_family, ISO88025_HDR_LEN); - } else if (bcmp(th->iso88025_dhost, - th->iso88025_shost, ETHER_ADDR_LEN) == 0) { - (void) if_simloop(ifp, - m, dst->sa_family, ISO88025_HDR_LEN); - return(0); /* XXX */ - } + struct mbuf *n; + n = m_copy(m, 0, (int)M_COPYALL); + (void)if_simloop(ifp, n, dst->sa_family, + ISO88025_HDR_LEN); + } else + if (bcmp(th->iso88025_dhost, th->iso88025_shost, + ETHER_ADDR_LEN) == 0) { + (void)if_simloop(ifp, m, dst->sa_family, + ISO88025_HDR_LEN); + return(0); /* XXX */ + } } - if (! IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, ISO88025_HDR_LEN + 8)) { + if (! IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp, ISO88025_HDR_LEN + (sizeof(struct +llc))) ) { printf("iso88025_output: packet dropped QFULL.\n"); senderr(ENOBUFS); } @@ -310,92 +410,151 @@ * ISO 88025 de-encapsulation */ void -iso88025_input(struct ifnet *ifp, struct iso88025_header *th, struct mbuf *m) +iso88025_input(ifp, th, m) + struct ifnet *ifp; + struct iso88025_header *th; + struct mbuf *m; { register struct ifqueue *inq; - u_short ether_type; - register struct llc *l = mtod(m, struct llc *); + register struct llc *l; if ((ifp->if_flags & IFF_UP) == 0) { m_freem(m); return; } - switch (l->llc_control) { - case LLC_UI: - break; - case LLC_TEST: - case LLC_TEST_P: - { - struct sockaddr sa; - struct arpcom *ac = (struct arpcom *)ifp; - struct iso88025_sockaddr_data *th2; - int i; - u_char c = l->llc_dsap; - - if (th->iso88025_shost[0] & TR_RII) { /* XXX */ - printf("iso88025_input: dropping source routed LLC_TEST\n"); - m_free(m); - return; - } - l->llc_dsap = l->llc_ssap; - l->llc_ssap = c; - if (m->m_flags & (M_BCAST | M_MCAST)) - bcopy((caddr_t)ac->ac_enaddr, - (caddr_t)th->iso88025_dhost, ISO88025_ADDR_LEN); - sa.sa_family = AF_UNSPEC; - sa.sa_len = sizeof(sa); - th2 = (struct iso88025_sockaddr_data *)sa.sa_data; - for (i = 0; i < ISO88025_ADDR_LEN; i++) { - th2->ether_shost[i] = c = th->iso88025_dhost[i]; - th2->ether_dhost[i] = th->iso88025_dhost[i] = th->iso88025_shost[i]; - th->iso88025_shost[i] = c; - } - th2->ac = TR_AC; - th2->fc = TR_LLC_FRAME; - ifp->if_output(ifp, m, &sa, NULL); - return; - } - default: - printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control); - m_freem(m); - return; - } - - m->m_pkthdr.len -= 8; - m->m_len -= 8; - m->m_data += 8; /* Length of LLC header in our case */ - + getmicrotime(&ifp->if_lastchange); ifp->if_ibytes += m->m_pkthdr.len + sizeof(*th); + if (th->iso88025_dhost[0] & 1) { - if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)th->iso88025_dhost, sizeof(etherbroadcastaddr)) == 0) + if (bcmp((caddr_t)etherbroadcastaddr, + (caddr_t)th->iso88025_dhost, + sizeof(etherbroadcastaddr)) == 0) m->m_flags |= M_BCAST; else m->m_flags |= M_MCAST; - } - if (m->m_flags & (M_BCAST|M_MCAST)) ifp->if_imcasts++; + } - ether_type = ntohs(l->llc_un.type_snap.ether_type); + l = mtod(m, struct llc *); - switch (ether_type) { -#ifdef INET - case ETHERTYPE_IP: + switch (l->llc_dsap) { +#ifdef IPX + case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */ + if (l->llc_ssap != ETHERTYPE_IPX_8022) + goto dropanyway; th->iso88025_shost[0] &= ~(TR_RII); - if (ipflow_fastforward(m)) - return; - schednetisr(NETISR_IP); - inq = &ipintrq; + m_adj(m, 3); + schednetisr(NETISR_IPX); + inq = &ipxintrq; break; - - case ETHERTYPE_ARP: - schednetisr(NETISR_ARP); - inq = &arpintrq; - break; #endif + case LLC_SNAP_LSAP: { + u_int16_t type; + if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP) + goto dropanyway; + if (l->llc_un.type_snap.org_code[0] != 0 || + l->llc_un.type_snap.org_code[1] != 0 || + l->llc_un.type_snap.org_code[2] != 0) + goto dropanyway; + type = ntohs(l->llc_un.type_snap.ether_type); + m_adj(m, sizeof(struct llc)); + switch (type) { +#ifdef INET + case ETHERTYPE_IP: + th->iso88025_shost[0] &= ~(TR_RII); + if (ipflow_fastforward(m)) + return; + schednetisr(NETISR_IP); + inq = &ipintrq; + break; + + case ETHERTYPE_ARP: + schednetisr(NETISR_ARP); + inq = &arpintrq; + break; +#endif +#ifdef IPX /* XXX: this, I think, is bogus. */ + case ETHERTYPE_IPX: + th->iso88025_shost[0] &= ~(TR_RII); + schednetisr(NETISR_IPX); + inq = &ipxintrq; + break; +#endif +#ifdef INET6 + case ETHERTYPE_IPV6: + th->iso88025_shost[0] &= ~(TR_RII); + schednetisr(NETISR_IPV6); + inq = &ip6intrq; + break; +#endif + default: + printf("iso88025_input: unexpected llc_snap ether_type +0x%02x\n", type); + m_freem(m); + return; + } + break; + } + case LLC_ISO_LSAP: + switch (l->llc_control) { + case LLC_UI: + goto dropanyway; + break; + case LLC_XID: + case LLC_XID_P: + if(m->m_len < ISO88025_ADDR_LEN) + goto dropanyway; + l->llc_window = 0; + l->llc_fid = 9; + l->llc_class = 1; + l->llc_dsap = l->llc_ssap = 0; + /* Fall through to */ + case LLC_TEST: + case LLC_TEST_P: + { + struct sockaddr sa; + struct arpcom *ac = (struct arpcom *)ifp; + struct iso88025_sockaddr_data *th2; + int i; + u_char c = l->llc_dsap; + + if (th->iso88025_shost[0] & TR_RII) { /* XXX */ + printf("iso88025_input: dropping source routed +LLC_TEST\n"); + m_free(m); + return; + } + l->llc_dsap = l->llc_ssap; + l->llc_ssap = c; + if (m->m_flags & (M_BCAST | M_MCAST)) + bcopy((caddr_t)ac->ac_enaddr, + (caddr_t)th->iso88025_dhost, + ISO88025_ADDR_LEN); + sa.sa_family = AF_UNSPEC; + sa.sa_len = sizeof(sa); + th2 = (struct iso88025_sockaddr_data *)sa.sa_data; + for (i = 0; i < ISO88025_ADDR_LEN; i++) { + th2->ether_shost[i] = c = th->iso88025_dhost[i]; + th2->ether_dhost[i] = th->iso88025_dhost[i] = + th->iso88025_shost[i]; + th->iso88025_shost[i] = c; + } + th2->ac = TR_AC; + th2->fc = TR_LLC_FRAME; + ifp->if_output(ifp, m, &sa, NULL); + return; + } + default: + printf("iso88025_input: unexpected llc control 0x%02x\n", +l->llc_control); + m_freem(m); + return; + } + break; default: - m_freem(m); - return; + printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap); + ifp->if_noproto++; + dropanyway: + m_freem(m); + return; } if (! IF_HANDOFF(inq, m, NULL)) Index: iso88025.h =================================================================== RCS file: /cvs/src/sys/net/iso88025.h,v retrieving revision 1.4 diff -u -r1.4 iso88025.h --- iso88025.h 2000/03/19 21:34:37 1.4 +++ iso88025.h 2001/03/08 02:01:43 @@ -75,6 +75,8 @@ * Minimum and maximum packet payload lengths. */ #define ISO88025_MIN_LEN 0 +#define ISO88025_MAX_LEN_4 4464 +#define ISO88025_MAX_LEN_16 17960 #define ISO88025_MAX_LEN 17960 /* @@ -87,13 +89,18 @@ * ISO 802.5 physical header */ struct iso88025_header { - u_char ac; /* access control field */ - u_char fc; /* frame control field */ - u_char iso88025_dhost[ISO88025_ADDR_LEN]; /* destination address */ - u_char iso88025_shost[ISO88025_ADDR_LEN]; /* source address */ - u_short rcf; /* route control field */ - u_short rd[RIF_MAX_RD]; /* routing designators */ -}; + u_int8_t ac; /* access control field */ + u_int8_t fc; /* frame control field */ + u_int8_t iso88025_dhost[ISO88025_ADDR_LEN]; /* destination address */ + u_int8_t iso88025_shost[ISO88025_ADDR_LEN]; /* source address */ + u_int16_t rcf; /* route control field */ + u_int16_t rd[RIF_MAX_RD]; /* routing designators */ +} __attribute__ ((__packed__)); + +struct iso88025_rif { + u_int16_t rcf; /* route control field */ + u_int16_t rd[RIF_MAX_RD]; /* routing designators */ +} __attribute__ ((__packed__)); struct iso88025_sockaddr_data { u_char ether_dhost[ISO88025_ADDR_LEN]; Index: if_llc.h =================================================================== RCS file: /cvs/src/sys/net/if_llc.h,v retrieving revision 1.7 diff -u -r1.7 if_llc.h --- if_llc.h 1999/08/28 00:48:18 1.7 +++ if_llc.h 2001/03/09 09:14:03 @@ -46,44 +46,45 @@ */ struct llc { - u_char llc_dsap; - u_char llc_ssap; + u_int8_t llc_dsap; + u_int8_t llc_ssap; union { struct { - u_char control; - u_char format_id; - u_char class; - u_char window_x2; - } type_u; - struct { - u_char num_snd_x2; - u_char num_rcv_x2; - } type_i; - struct { - u_char control; - u_char num_rcv_x2; - } type_s; + u_int8_t control; + u_int8_t format_id; + u_int8_t class; + u_int8_t window_x2; + } type_u __attribute__((__packed__)); + struct { + u_int8_t num_snd_x2; + u_int8_t num_rcv_x2; + } type_i __attribute__((__packed__)); + struct { + u_int8_t control; + u_int8_t num_rcv_x2; + } type_s __attribute__((__packed__)); struct { - u_char control; + u_int8_t control; struct frmrinfo { - u_char rej_pdu_0; - u_char rej_pdu_1; - u_char frmr_control; - u_char frmr_control_ext; - u_char frmr_cause; - } frmrinfo; - } type_frmr; + u_int8_t rej_pdu_0; + u_int8_t rej_pdu_1; + u_int8_t frmr_control; + u_int8_t frmr_control_ext; + u_int8_t frmr_cause; + } frmrinfo __attribute__((__packed__)); + } type_frmr __attribute__((__packed__)); struct { - u_char control; - u_char org_code[3]; + u_int8_t control; + u_int8_t org_code[3]; u_short ether_type; - } type_snap; + } type_snap __attribute__((__packed__)); struct { - u_char control; - u_char control_ext; - } type_raw; - } llc_un; -}; + u_int8_t control; + u_int8_t control_ext; + } type_raw __attribute__((__packed__)); + } llc_un __attribute__((__packed__)); +} __attribute__((__packed__)); + #define llc_control llc_un.type_u.control #define llc_control_ext llc_un.type_raw.control_ext #define llc_fid llc_un.type_u.format_id @@ -102,6 +103,8 @@ #define LLC_ISFRAMELEN 4 #define LLC_UFRAMELEN 3 #define LLC_FRMRLEN 7 +#define LLC_SNAPFRAMELEN 8 + /* * Unnumbered LLC format commands