if_fddisubr.c revision 93368
1/* 2 * Copyright (c) 1995, 1996 3 * Matt Thomas <matt@3am-software.com>. All rights reserved. 4 * Copyright (c) 1982, 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp 36 * $FreeBSD: head/sys/net/if_fddisubr.c 93368 2002-03-29 07:30:22Z mdodd $ 37 */ 38 39#include "opt_atalk.h" 40#include "opt_inet.h" 41#include "opt_inet6.h" 42#include "opt_ipx.h" 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/mbuf.h> 47#include <sys/socket.h> 48#include <sys/malloc.h> 49 50#include <net/if.h> 51#include <net/netisr.h> 52#include <net/route.h> 53#include <net/if_llc.h> 54#include <net/if_dl.h> 55#include <net/if_types.h> 56 57#if defined(INET) || defined(INET6) 58#include <netinet/in.h> 59#include <netinet/in_var.h> 60#include <netinet/if_ether.h> 61#endif 62#ifdef INET6 63#include <netinet6/nd6.h> 64#endif 65#include <netinet/if_fddi.h> 66 67#ifdef IPX 68#include <netipx/ipx.h> 69#include <netipx/ipx_if.h> 70#endif 71 72#ifdef NS 73#include <netns/ns.h> 74#include <netns/ns_if.h> 75#endif 76 77#ifdef DECNET 78#include <netdnet/dn.h> 79#endif 80 81#ifdef NETATALK 82#include <netatalk/at.h> 83#include <netatalk/at_var.h> 84#include <netatalk/at_extern.h> 85 86#define llc_snap_org_code llc_un.type_snap.org_code 87#define llc_snap_ether_type llc_un.type_snap.ether_type 88 89extern u_char at_org_code[ 3 ]; 90extern u_char aarp_org_code[ 3 ]; 91#endif /* NETATALK */ 92 93static int fddi_resolvemulti(struct ifnet *, struct sockaddr **, 94 struct sockaddr *); 95 96#define senderr(e) { error = (e); goto bad;} 97 98/* 99 * This really should be defined in if_llc.h but in case it isn't. 100 */ 101#ifndef llc_snap 102#define llc_snap llc_un.type_snap 103#endif 104 105#define RTALLOC1(a, b) rtalloc1(a, b, 0UL) 106#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e, f) 107/* 108 * FDDI output routine. 109 * Encapsulate a packet of type family for the local net. 110 * Use trailer local net encapsulation if enough data in first 111 * packet leaves a multiple of 512 bytes of data in remainder. 112 * Assumes that ifp is actually pointer to arpcom structure. 113 */ 114int 115fddi_output(ifp, m, dst, rt0) 116 struct ifnet *ifp; 117 struct mbuf *m; 118 struct sockaddr *dst; 119 struct rtentry *rt0; 120{ 121 u_int16_t type; 122 int loop_copy = 0, error = 0, hdrcmplt = 0; 123 u_char esrc[6], edst[6]; 124 struct rtentry *rt; 125 struct fddi_header *fh; 126 struct arpcom *ac = (struct arpcom *)ifp; 127 128 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 129 senderr(ENETDOWN); 130 getmicrotime(&ifp->if_lastchange); 131 if ((rt = rt0) != NULL) { 132 if ((rt->rt_flags & RTF_UP) == 0) { 133 if ((rt0 = rt = RTALLOC1(dst, 1)) != NULL) 134 rt->rt_refcnt--; 135 else 136 senderr(EHOSTUNREACH); 137 } 138 if (rt->rt_flags & RTF_GATEWAY) { 139 if (rt->rt_gwroute == 0) 140 goto lookup; 141 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 142 rtfree(rt); rt = rt0; 143 lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 1); 144 if ((rt = rt->rt_gwroute) == 0) 145 senderr(EHOSTUNREACH); 146 } 147 } 148 if (rt->rt_flags & RTF_REJECT) 149 if (rt->rt_rmx.rmx_expire == 0 || 150 time_second < rt->rt_rmx.rmx_expire) 151 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 152 } 153 switch (dst->sa_family) { 154 155#ifdef INET 156 case AF_INET: { 157 if (!ARPRESOLVE(ifp, rt, m, dst, edst, rt0)) 158 return (0); /* if not yet resolved */ 159 type = htons(ETHERTYPE_IP); 160 break; 161 } 162#endif 163#ifdef INET6 164 case AF_INET6: 165 if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) { 166 /* Something bad happened */ 167 return(0); 168 } 169 type = htons(ETHERTYPE_IPV6); 170 break; 171#endif 172#ifdef IPX 173 case AF_IPX: 174 type = htons(ETHERTYPE_IPX); 175 bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 176 (caddr_t)edst, sizeof (edst)); 177 break; 178#endif 179#ifdef NETATALK 180 case AF_APPLETALK: { 181 struct at_ifaddr *aa; 182 if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) 183 return (0); 184 /* 185 * ifaddr is the first thing in at_ifaddr 186 */ 187 if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0) 188 goto bad; 189 190 /* 191 * In the phase 2 case, we need to prepend an mbuf for the llc header. 192 * Since we must preserve the value of m, which is passed to us by 193 * value, we m_copy() the first mbuf, and use it for our llc header. 194 */ 195 if (aa->aa_flags & AFA_PHASE2) { 196 struct llc llc; 197 198 M_PREPEND(m, sizeof(struct llc), M_TRYWAIT); 199 if (m == 0) 200 senderr(ENOBUFS); 201 llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 202 llc.llc_control = LLC_UI; 203 bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code)); 204 llc.llc_snap_ether_type = htons(ETHERTYPE_AT); 205 bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc)); 206 type = 0; 207 } else { 208 type = htons(ETHERTYPE_AT); 209 } 210 break; 211 } 212#endif /* NETATALK */ 213#ifdef NS 214 case AF_NS: 215 type = htons(ETHERTYPE_NS); 216 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 217 (caddr_t)edst, sizeof (edst)); 218 break; 219#endif 220 221 case pseudo_AF_HDRCMPLT: 222 { 223 struct ether_header *eh; 224 hdrcmplt = 1; 225 eh = (struct ether_header *)dst->sa_data; 226 (void)memcpy((caddr_t)esrc, (caddr_t)eh->ether_shost, sizeof (esrc)); 227 /* FALLTHROUGH */ 228 } 229 230 case AF_UNSPEC: 231 { 232 struct ether_header *eh; 233 loop_copy = -1; 234 eh = (struct ether_header *)dst->sa_data; 235 (void)memcpy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); 236 if (*edst & 1) 237 m->m_flags |= (M_BCAST|M_MCAST); 238 type = eh->ether_type; 239 break; 240 } 241 242 case AF_IMPLINK: 243 { 244 fh = mtod(m, struct fddi_header *); 245 error = EPROTONOSUPPORT; 246 switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 247 case FDDIFC_LLC_ASYNC: { 248 /* legal priorities are 0 through 7 */ 249 if ((fh->fddi_fc & FDDIFC_Z) > 7) 250 goto bad; 251 break; 252 } 253 case FDDIFC_LLC_SYNC: { 254 /* FDDIFC_Z bits reserved, must be zero */ 255 if (fh->fddi_fc & FDDIFC_Z) 256 goto bad; 257 break; 258 } 259 case FDDIFC_SMT: { 260 /* FDDIFC_Z bits must be non zero */ 261 if ((fh->fddi_fc & FDDIFC_Z) == 0) 262 goto bad; 263 break; 264 } 265 default: { 266 /* anything else is too dangerous */ 267 goto bad; 268 } 269 } 270 error = 0; 271 if (fh->fddi_dhost[0] & 1) 272 m->m_flags |= (M_BCAST|M_MCAST); 273 goto queue_it; 274 } 275 default: 276 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 277 dst->sa_family); 278 senderr(EAFNOSUPPORT); 279 } 280 281 if (type != 0) { 282 struct llc *l; 283 M_PREPEND(m, sizeof (struct llc), M_DONTWAIT); 284 if (m == 0) 285 senderr(ENOBUFS); 286 l = mtod(m, struct llc *); 287 l->llc_control = LLC_UI; 288 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 289 l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0; 290 (void)memcpy((caddr_t) &l->llc_snap.ether_type, (caddr_t) &type, 291 sizeof(u_int16_t)); 292 } 293 294 /* 295 * Add local net header. If no space in first mbuf, 296 * allocate another. 297 */ 298 M_PREPEND(m, sizeof (struct fddi_header), M_DONTWAIT); 299 if (m == 0) 300 senderr(ENOBUFS); 301 fh = mtod(m, struct fddi_header *); 302 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 303 (void)memcpy((caddr_t)fh->fddi_dhost, (caddr_t)edst, sizeof (edst)); 304 queue_it: 305 if (hdrcmplt) 306 (void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)esrc, 307 sizeof(fh->fddi_shost)); 308 else 309 (void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)ac->ac_enaddr, 310 sizeof(fh->fddi_shost)); 311 /* 312 * If a simplex interface, and the packet is being sent to our 313 * Ethernet address or a broadcast address, loopback a copy. 314 * XXX To make a simplex device behave exactly like a duplex 315 * device, we should copy in the case of sending to our own 316 * ethernet address (thus letting the original actually appear 317 * on the wire). However, we don't do that here for security 318 * reasons and compatibility with the original behavior. 319 */ 320 if ((ifp->if_flags & IFF_SIMPLEX) && 321 (loop_copy != -1)) { 322 if ((m->m_flags & M_BCAST) || loop_copy) { 323 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 324 325 (void) if_simloop(ifp, 326 n, dst->sa_family, sizeof(struct fddi_header)); 327 } else if (bcmp(fh->fddi_dhost, 328 fh->fddi_shost, sizeof(fh->fddi_shost)) == 0) { 329 (void) if_simloop(ifp, 330 m, dst->sa_family, sizeof(struct fddi_header)); 331 return(0); /* XXX */ 332 } 333 } 334 335 if (! IF_HANDOFF(&ifp->if_snd, m, ifp)) 336 senderr(ENOBUFS); 337 return (error); 338 339bad: 340 if (m) 341 m_freem(m); 342 return (error); 343} 344 345/* 346 * Process a received FDDI packet; 347 * the packet is in the mbuf chain m without 348 * the fddi header, which is provided separately. 349 */ 350void 351fddi_input(ifp, fh, m) 352 struct ifnet *ifp; 353 struct fddi_header *fh; 354 struct mbuf *m; 355{ 356 struct ifqueue *inq; 357 struct llc *l; 358 359 if ((ifp->if_flags & IFF_UP) == 0) { 360 m_freem(m); 361 return; 362 } 363 getmicrotime(&ifp->if_lastchange); 364 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh); 365 if (fh->fddi_dhost[0] & 1) { 366 if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost, 367 sizeof(fddibroadcastaddr)) == 0) 368 m->m_flags |= M_BCAST; 369 else 370 m->m_flags |= M_MCAST; 371 ifp->if_imcasts++; 372 } else if ((ifp->if_flags & IFF_PROMISC) 373 && bcmp(((struct arpcom *)ifp)->ac_enaddr, (caddr_t)fh->fddi_dhost, 374 sizeof(fh->fddi_dhost)) != 0) { 375 m_freem(m); 376 return; 377 } 378 379#ifdef M_LINK0 380 /* 381 * If this has a LLC priority of 0, then mark it so upper 382 * layers have a hint that it really came via a FDDI/Ethernet 383 * bridge. 384 */ 385 if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 386 m->m_flags |= M_LINK0; 387#endif 388 389 l = mtod(m, struct llc *); 390 switch (l->llc_dsap) { 391#if defined(INET) || defined(INET6) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK) 392 case LLC_SNAP_LSAP: 393 { 394 u_int16_t type; 395 if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP) 396 goto dropanyway; 397#ifdef NETATALK 398 if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code, 399 sizeof(at_org_code)) == 0 && 400 ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) { 401 inq = &atintrq2; 402 m_adj( m, sizeof( struct llc )); 403 schednetisr(NETISR_ATALK); 404 break; 405 } 406 407 if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code, 408 sizeof(aarp_org_code)) == 0 && 409 ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) { 410 m_adj( m, sizeof( struct llc )); 411 aarpinput((struct arpcom *)ifp, m); /* XXX */ 412 return; 413 } 414#endif /* NETATALK */ 415 if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0) 416 goto dropanyway; 417 type = ntohs(l->llc_snap.ether_type); 418 m_adj(m, 8); 419 switch (type) { 420#ifdef INET 421 case ETHERTYPE_IP: 422 if (ipflow_fastforward(m)) 423 return; 424 schednetisr(NETISR_IP); 425 inq = &ipintrq; 426 break; 427 428 case ETHERTYPE_ARP: 429 if (ifp->if_flags & IFF_NOARP) 430 goto dropanyway; 431 schednetisr(NETISR_ARP); 432 inq = &arpintrq; 433 break; 434#endif 435#ifdef INET6 436 case ETHERTYPE_IPV6: 437 schednetisr(NETISR_IPV6); 438 inq = &ip6intrq; 439 break; 440#endif 441#ifdef IPX 442 case ETHERTYPE_IPX: 443 schednetisr(NETISR_IPX); 444 inq = &ipxintrq; 445 break; 446#endif 447#ifdef NS 448 case ETHERTYPE_NS: 449 schednetisr(NETISR_NS); 450 inq = &nsintrq; 451 break; 452#endif 453#ifdef DECNET 454 case ETHERTYPE_DECNET: 455 schednetisr(NETISR_DECNET); 456 inq = &decnetintrq; 457 break; 458#endif 459#ifdef NETATALK 460 case ETHERTYPE_AT: 461 schednetisr(NETISR_ATALK); 462 inq = &atintrq1; 463 break; 464 case ETHERTYPE_AARP: 465 /* probably this should be done with a NETISR as well */ 466 aarpinput((struct arpcom *)ifp, m); /* XXX */ 467 return; 468#endif /* NETATALK */ 469 default: 470 /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 471 ifp->if_noproto++; 472 goto dropanyway; 473 } 474 break; 475 } 476#endif /* INET || NS */ 477 478 default: 479 /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 480 ifp->if_noproto++; 481 dropanyway: 482 m_freem(m); 483 return; 484 } 485 486 (void) IF_HANDOFF(inq, m, NULL); 487} 488/* 489 * Perform common duties while attaching to interface list 490 */ 491 492void 493fddi_ifattach(ifp) 494 struct ifnet *ifp; 495{ 496 struct ifaddr *ifa; 497 struct sockaddr_dl *sdl; 498 499 ifp->if_type = IFT_FDDI; 500 ifp->if_addrlen = 6; 501 ifp->if_hdrlen = 21; 502 ifp->if_mtu = FDDIMTU; 503 ifp->if_resolvemulti = fddi_resolvemulti; 504 ifp->if_baudrate = 100000000; 505#ifdef IFF_NOTRAILERS 506 ifp->if_flags |= IFF_NOTRAILERS; 507#endif 508 ifp->if_broadcastaddr = fddibroadcastaddr; 509 ifa = ifaddr_byindex(ifp->if_index); 510 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 511 sdl->sdl_type = IFT_FDDI; 512 sdl->sdl_alen = ifp->if_addrlen; 513 bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 514} 515 516static int 517fddi_resolvemulti(ifp, llsa, sa) 518 struct ifnet *ifp; 519 struct sockaddr **llsa; 520 struct sockaddr *sa; 521{ 522 struct sockaddr_dl *sdl; 523 struct sockaddr_in *sin; 524#ifdef INET6 525 struct sockaddr_in6 *sin6; 526#endif 527 u_char *e_addr; 528 529 switch(sa->sa_family) { 530 case AF_LINK: 531 /* 532 * No mapping needed. Just check that it's a valid MC address. 533 */ 534 sdl = (struct sockaddr_dl *)sa; 535 e_addr = LLADDR(sdl); 536 if ((e_addr[0] & 1) != 1) 537 return EADDRNOTAVAIL; 538 *llsa = 0; 539 return 0; 540 541#ifdef INET 542 case AF_INET: 543 sin = (struct sockaddr_in *)sa; 544 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 545 return EADDRNOTAVAIL; 546 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 547 M_WAITOK); 548 sdl->sdl_len = sizeof *sdl; 549 sdl->sdl_family = AF_LINK; 550 sdl->sdl_index = ifp->if_index; 551 sdl->sdl_type = IFT_FDDI; 552 sdl->sdl_nlen = 0; 553 sdl->sdl_alen = ETHER_ADDR_LEN; /* XXX */ 554 sdl->sdl_slen = 0; 555 e_addr = LLADDR(sdl); 556 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 557 *llsa = (struct sockaddr *)sdl; 558 return 0; 559#endif 560#ifdef INET6 561 case AF_INET6: 562 sin6 = (struct sockaddr_in6 *)sa; 563 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 564 /* 565 * An IP6 address of 0 means listen to all 566 * of the Ethernet multicast address used for IP6. 567 * (This is used for multicast routers.) 568 */ 569 ifp->if_flags |= IFF_ALLMULTI; 570 *llsa = 0; 571 return 0; 572 } 573 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 574 return EADDRNOTAVAIL; 575 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 576 M_WAITOK); 577 sdl->sdl_len = sizeof *sdl; 578 sdl->sdl_family = AF_LINK; 579 sdl->sdl_index = ifp->if_index; 580 sdl->sdl_type = IFT_FDDI; 581 sdl->sdl_nlen = 0; 582 sdl->sdl_alen = ETHER_ADDR_LEN; /* XXX */ 583 sdl->sdl_slen = 0; 584 e_addr = LLADDR(sdl); 585 ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 586 *llsa = (struct sockaddr *)sdl; 587 return 0; 588#endif 589 590 default: 591 /* 592 * Well, the text isn't quite right, but it's the name 593 * that counts... 594 */ 595 return EAFNOSUPPORT; 596 } 597} 598