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