if_fddisubr.c revision 11819
1/* 2 * Copyright (c) 1982, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp 34 * $Id: if_fddisubr.c,v 1.5 1995/05/30 08:08:05 rgrimes Exp $ 35 */ 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/kernel.h> 40#include <sys/malloc.h> 41#include <sys/mbuf.h> 42#include <sys/protosw.h> 43#include <sys/socket.h> 44#include <sys/ioctl.h> 45#include <sys/errno.h> 46#include <sys/syslog.h> 47 48#include <machine/cpu.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#ifdef INET 58#include <netinet/in.h> 59#include <netinet/in_var.h> 60#endif 61#include <netinet/if_ether.h> 62#include <netinet/if_fddi.h> 63 64#ifdef IPX 65#include <netipx/ipx.h> 66#include <netipx/ipx_if.h> 67#endif 68 69#ifdef NS 70#include <netns/ns.h> 71#include <netns/ns_if.h> 72#endif 73 74#ifdef DECNET 75#include <netdnet/dn.h> 76#endif 77 78#ifdef ISO 79#include <netiso/argo_debug.h> 80#include <netiso/iso.h> 81#include <netiso/iso_var.h> 82#include <netiso/iso_snpac.h> 83#endif 84 85#include "bpfilter.h" 86 87#ifdef LLC 88#include <netccitt/dll.h> 89#include <netccitt/llc_var.h> 90#endif 91 92#if defined(LLC) && defined(CCITT) 93extern struct ifqueue pkintrq; 94#endif 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#ifdef __bsdi__ 106#define RTALLOC1(a, b) rtalloc1(a, b) 107#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e) 108#else 109#define RTALLOC1(a, b) rtalloc1(a, b, 0UL) 110#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e, f) 111#endif 112/* 113 * FDDI output routine. 114 * Encapsulate a packet of type family for the local net. 115 * Use trailer local net encapsulation if enough data in first 116 * packet leaves a multiple of 512 bytes of data in remainder. 117 * Assumes that ifp is actually pointer to arpcom structure. 118 */ 119int 120fddi_output(ifp, m0, dst, rt0) 121 register struct ifnet *ifp; 122 struct mbuf *m0; 123 struct sockaddr *dst; 124 struct rtentry *rt0; 125{ 126 short type; 127 int s, error = 0; 128 u_char edst[6]; 129 register struct mbuf *m = m0; 130 register struct rtentry *rt; 131 struct mbuf *mcopy = (struct mbuf *)0; 132 register struct fddi_header *fh; 133 struct arpcom *ac = (struct arpcom *)ifp; 134 135 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 136 senderr(ENETDOWN); 137 ifp->if_lastchange = time; 138 if (rt = rt0) { 139 if ((rt->rt_flags & RTF_UP) == 0) { 140 if (rt0 = rt = RTALLOC1(dst, 1)) 141 rt->rt_refcnt--; 142 else 143 senderr(EHOSTUNREACH); 144 } 145 if (rt->rt_flags & RTF_GATEWAY) { 146 if (rt->rt_gwroute == 0) 147 goto lookup; 148 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 149 rtfree(rt); rt = rt0; 150 lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 1); 151 if ((rt = rt->rt_gwroute) == 0) 152 senderr(EHOSTUNREACH); 153 } 154 } 155 if (rt->rt_flags & RTF_REJECT) 156 if (rt->rt_rmx.rmx_expire == 0 || 157 time.tv_sec < rt->rt_rmx.rmx_expire) 158 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 159 } 160 switch (dst->sa_family) { 161 162#ifdef INET 163 case AF_INET: 164 if (!ARPRESOLVE(ac, rt, m, dst, edst, rt0)) 165 return (0); /* if not yet resolved */ 166 /* If broadcasting on a simplex interface, loopback a copy */ 167 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 168 mcopy = m_copy(m, 0, (int)M_COPYALL); 169 type = ETHERTYPE_IP; 170 break; 171#endif 172#ifdef IPX 173 case AF_IPX: 174 type = ETHERTYPE_IPX; 175 bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 176 (caddr_t)edst, sizeof (edst)); 177 if (!bcmp((caddr_t)edst, (caddr_t)&ipx_thishost, sizeof(edst))) 178 return (looutput(ifp, m, dst, rt)); 179 /* If broadcasting on a simplex interface, loopback a copy */ 180 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 181 mcopy = m_copy(m, 0, (int)M_COPYALL); 182 break; 183#endif 184#ifdef NS 185 case AF_NS: 186 type = ETHERTYPE_NS; 187 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 188 (caddr_t)edst, sizeof (edst)); 189 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))) 190 return (looutput(ifp, m, dst, rt)); 191 /* If broadcasting on a simplex interface, loopback a copy */ 192 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 193 mcopy = m_copy(m, 0, (int)M_COPYALL); 194 break; 195#endif 196#ifdef ISO 197 case AF_ISO: { 198 int snpalen; 199 struct llc *l; 200 register struct sockaddr_dl *sdl; 201 202 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) && 203 sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) { 204 bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst)); 205 } else if (error = 206 iso_snparesolve(ifp, (struct sockaddr_iso *)dst, 207 (char *)edst, &snpalen)) 208 goto bad; /* Not Resolved */ 209 /* If broadcasting on a simplex interface, loopback a copy */ 210 if (*edst & 1) 211 m->m_flags |= (M_BCAST|M_MCAST); 212 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && 213 (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 214 M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT); 215 if (mcopy) { 216 fh = mtod(mcopy, struct fddi_header *); 217 bcopy((caddr_t)edst, 218 (caddr_t)fh->fddi_dhost, sizeof (edst)); 219 bcopy((caddr_t)ac->ac_enaddr, 220 (caddr_t)fh->fddi_shost, sizeof (edst)); 221 } 222 } 223 M_PREPEND(m, 3, M_DONTWAIT); 224 if (m == NULL) 225 return (0); 226 type = 0; 227 l = mtod(m, struct llc *); 228 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; 229 l->llc_control = LLC_UI; 230 IFDEBUG(D_ETHER) 231 int i; 232 printf("unoutput: sending pkt to: "); 233 for (i=0; i<6; i++) 234 printf("%x ", edst[i] & 0xff); 235 printf("\n"); 236 ENDDEBUG 237 } break; 238#endif /* ISO */ 239#ifdef LLC 240/* case AF_NSAP: */ 241 case AF_CCITT: { 242 register struct sockaddr_dl *sdl = 243 (struct sockaddr_dl *) rt -> rt_gateway; 244 245 if (sdl && sdl->sdl_family == AF_LINK 246 && sdl->sdl_alen > 0) { 247 bcopy(LLADDR(sdl), (char *)edst, 248 sizeof(edst)); 249 } else goto bad; /* Not a link interface ? Funny ... */ 250 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) && 251 (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 252 M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT); 253 if (mcopy) { 254 fh = mtod(mcopy, struct fddi_header *); 255 bcopy((caddr_t)edst, 256 (caddr_t)fh->fddi_dhost, sizeof (edst)); 257 bcopy((caddr_t)ac->ac_enaddr, 258 (caddr_t)fh->fddi_shost, sizeof (edst)); 259 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 260 } 261 } 262 type = 0; 263#ifdef LLC_DEBUG 264 { 265 int i; 266 register struct llc *l = mtod(m, struct llc *); 267 268 printf("fddi_output: sending LLC2 pkt to: "); 269 for (i=0; i<6; i++) 270 printf("%x ", edst[i] & 0xff); 271 printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n", 272 type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff, 273 l->llc_control & 0xff); 274 275 } 276#endif /* LLC_DEBUG */ 277 } break; 278#endif /* LLC */ 279 280 case AF_UNSPEC: 281 { 282 struct ether_header *eh; 283 eh = (struct ether_header *)dst->sa_data; 284 (void)memcpy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); 285 if (*edst & 1) 286 m->m_flags |= (M_BCAST|M_MCAST); 287 type = eh->ether_type; 288 break; 289 } 290 291#if NBPFILTER > 0 292 case AF_IMPLINK: 293 { 294 fh = mtod(m, struct fddi_header *); 295 error = EPROTONOSUPPORT; 296 switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 297 case FDDIFC_LLC_ASYNC: { 298 /* legal priorities are 0 through 7 */ 299 if ((fh->fddi_fc & FDDIFC_Z) > 7) 300 goto bad; 301 break; 302 } 303 case FDDIFC_LLC_SYNC: { 304 /* FDDIFC_Z bits reserved, must be zero */ 305 if (fh->fddi_fc & FDDIFC_Z) 306 goto bad; 307 break; 308 } 309 case FDDIFC_SMT: { 310 /* FDDIFC_Z bits must be non zero */ 311 if ((fh->fddi_fc & FDDIFC_Z) == 0) 312 goto bad; 313 break; 314 } 315 default: { 316 /* anything else is too dangerous */ 317 goto bad; 318 } 319 } 320 error = 0; 321 if (fh->fddi_dhost[0] & 1) 322 m->m_flags |= (M_BCAST|M_MCAST); 323 goto queue_it; 324 } 325#endif 326 default: 327 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 328 dst->sa_family); 329 senderr(EAFNOSUPPORT); 330 } 331 332 333 if (mcopy) 334 (void) looutput(ifp, mcopy, dst, rt); 335 if (type != 0) { 336 register struct llc *l; 337 M_PREPEND(m, sizeof (struct llc), M_DONTWAIT); 338 if (m == 0) 339 senderr(ENOBUFS); 340 l = mtod(m, struct llc *); 341 l->llc_control = LLC_UI; 342 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 343 l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0; 344 type = ntohs(type); 345 (void)memcpy((caddr_t) &l->llc_snap.ether_type, (caddr_t) &type, 346 sizeof(u_short)); 347 } 348 /* 349 * Add local net header. If no space in first mbuf, 350 * allocate another. 351 */ 352 M_PREPEND(m, sizeof (struct fddi_header), M_DONTWAIT); 353 if (m == 0) 354 senderr(ENOBUFS); 355 fh = mtod(m, struct fddi_header *); 356 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 357 (void)memcpy((caddr_t)fh->fddi_dhost, (caddr_t)edst, sizeof (edst)); 358 queue_it: 359 (void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)ac->ac_enaddr, 360 sizeof(fh->fddi_shost)); 361 s = splimp(); 362 /* 363 * Queue message on interface, and start output if interface 364 * not yet active. 365 */ 366 if (IF_QFULL(&ifp->if_snd)) { 367 IF_DROP(&ifp->if_snd); 368 splx(s); 369 senderr(ENOBUFS); 370 } 371 ifp->if_obytes += m->m_pkthdr.len; 372 IF_ENQUEUE(&ifp->if_snd, m); 373 if ((ifp->if_flags & IFF_OACTIVE) == 0) 374 (*ifp->if_start)(ifp); 375 splx(s); 376 if (m->m_flags & M_MCAST) 377 ifp->if_omcasts++; 378 return (error); 379 380bad: 381 if (m) 382 m_freem(m); 383 return (error); 384} 385 386/* 387 * Process a received FDDI packet; 388 * the packet is in the mbuf chain m without 389 * the fddi header, which is provided separately. 390 */ 391void 392fddi_input(ifp, fh, m) 393 struct ifnet *ifp; 394 register struct fddi_header *fh; 395 struct mbuf *m; 396{ 397 register struct ifqueue *inq; 398 register struct llc *l; 399 int s; 400 401 if ((ifp->if_flags & IFF_UP) == 0) { 402 m_freem(m); 403 return; 404 } 405 ifp->if_lastchange = time; 406 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh); 407 if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost, 408 sizeof(fddibroadcastaddr)) == 0) 409 m->m_flags |= M_BCAST; 410 else if (fh->fddi_dhost[0] & 1) 411 m->m_flags |= M_MCAST; 412 if (m->m_flags & (M_BCAST|M_MCAST)) 413 ifp->if_imcasts++; 414 415 l = mtod(m, struct llc *); 416 switch (l->llc_dsap) { 417#if defined(INET) || defined(NS) || defined(DECNET) 418 case LLC_SNAP_LSAP: 419 { 420 unsigned fddi_type; 421 if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP) 422 goto dropanyway; 423 if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0) 424 goto dropanyway; 425 fddi_type = ntohs(l->llc_snap.ether_type); 426 m_adj(m, 8); 427 switch (fddi_type) { 428#ifdef INET 429 case ETHERTYPE_IP: 430 schednetisr(NETISR_IP); 431 inq = &ipintrq; 432 break; 433 434 case ETHERTYPE_ARP: 435 schednetisr(NETISR_ARP); 436 inq = &arpintrq; 437 break; 438#endif 439#ifdef NS 440 case ETHERTYPE_NS: 441 schednetisr(NETISR_NS); 442 inq = &nsintrq; 443 break; 444#endif 445#ifdef DECNET 446 case ETHERTYPE_DECENT: 447 schednetisr(NETISR_DECNET); 448 inq = &decnetintrq; 449 break; 450#endif 451 default: 452 printf("fddi_input: unknown protocol 0x%x\n", fddi_type); 453 ifp->if_noproto++; 454 goto dropanyway; 455 } 456 break; 457 } 458#endif /* INET || NS */ 459#ifdef ISO 460 case LLC_ISO_LSAP: 461 switch (l->llc_control) { 462 case LLC_UI: 463 /* LLC_UI_P forbidden in class 1 service */ 464 if ((l->llc_dsap == LLC_ISO_LSAP) && 465 (l->llc_ssap == LLC_ISO_LSAP)) { 466 /* LSAP for ISO */ 467 m->m_data += 3; /* XXX */ 468 m->m_len -= 3; /* XXX */ 469 m->m_pkthdr.len -= 3; /* XXX */ 470 M_PREPEND(m, sizeof *fh, M_DONTWAIT); 471 if (m == 0) 472 return; 473 *mtod(m, struct fddi_header *) = *fh; 474 IFDEBUG(D_ETHER) 475 printf("clnp packet"); 476 ENDDEBUG 477 schednetisr(NETISR_ISO); 478 inq = &clnlintrq; 479 break; 480 } 481 goto dropanyway; 482 483 case LLC_XID: 484 case LLC_XID_P: 485 if(m->m_len < 6) 486 goto dropanyway; 487 l->llc_window = 0; 488 l->llc_fid = 9; 489 l->llc_class = 1; 490 l->llc_dsap = l->llc_ssap = 0; 491 /* Fall through to */ 492 case LLC_TEST: 493 case LLC_TEST_P: 494 { 495 struct sockaddr sa; 496 register struct ether_header *eh2; 497 int i; 498 u_char c = l->llc_dsap; 499 500 l->llc_dsap = l->llc_ssap; 501 l->llc_ssap = c; 502 if (m->m_flags & (M_BCAST | M_MCAST)) 503 bcopy((caddr_t)ac->ac_enaddr, 504 (caddr_t)eh->ether_dhost, 6); 505 sa.sa_family = AF_UNSPEC; 506 sa.sa_len = sizeof(sa); 507 eh2 = (struct ether_header *)sa.sa_data; 508 for (i = 0; i < 6; i++) { 509 eh2->ether_shost[i] = c = eh->fddi_dhost[i]; 510 eh2->ether_dhost[i] = 511 eh->ether_dhost[i] = eh->fddi_shost[i]; 512 eh2->ether_shost[i] = c; 513 } 514 eh2->ether_type = 0; 515 ifp->if_output(ifp, m, &sa, NULL); 516 return; 517 } 518 default: 519 m_freem(m); 520 return; 521 } 522 break; 523#endif /* ISO */ 524#ifdef LLC 525 case LLC_X25_LSAP: 526 { 527 M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT); 528 if (m == 0) 529 return; 530 if ( !sdl_sethdrif(ifp, fh->fddi_shost, LLC_X25_LSAP, 531 fh->fddi_dhost, LLC_X25_LSAP, 6, 532 mtod(m, struct sdl_hdr *))) 533 panic("ETHER cons addr failure"); 534 mtod(m, struct sdl_hdr *)->sdlhdr_len = m->m_pkthdr.len - sizeof(struct sdl_hdr); 535#ifdef LLC_DEBUG 536 printf("llc packet\n"); 537#endif /* LLC_DEBUG */ 538 schednetisr(NETISR_CCITT); 539 inq = &llcintrq; 540 break; 541 } 542#endif /* LLC */ 543 544 default: 545 printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); 546 ifp->if_noproto++; 547 dropanyway: 548 m_freem(m); 549 return; 550 } 551 552 s = splimp(); 553 if (IF_QFULL(inq)) { 554 IF_DROP(inq); 555 m_freem(m); 556 } else 557 IF_ENQUEUE(inq, m); 558 splx(s); 559} 560/* 561 * Perform common duties while attaching to interface list 562 */ 563void 564fddi_ifattach(ifp) 565 register struct ifnet *ifp; 566{ 567 register struct ifaddr *ifa; 568 register struct sockaddr_dl *sdl; 569 570 ifp->if_type = IFT_FDDI; 571 ifp->if_addrlen = 6; 572 ifp->if_hdrlen = 21; 573 ifp->if_mtu = FDDIMTU; 574 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 575 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 576 sdl->sdl_family == AF_LINK) { 577 sdl->sdl_type = IFT_FDDI; 578 sdl->sdl_alen = ifp->if_addrlen; 579 bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, 580 LLADDR(sdl), ifp->if_addrlen); 581 break; 582 } 583} 584