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