if_fddisubr.c revision 7090
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.2 1995/03/14 22:15:36 davidg 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 NS 65#include <netns/ns.h> 66#include <netns/ns_if.h> 67#endif 68 69#ifdef DECNET 70#include <netdnet/dn.h> 71#endif 72 73#ifdef ISO 74#include <netiso/argo_debug.h> 75#include <netiso/iso.h> 76#include <netiso/iso_var.h> 77#include <netiso/iso_snpac.h> 78#endif 79 80#include "bpfilter.h" 81 82#ifdef LLC 83#include <netccitt/dll.h> 84#include <netccitt/llc_var.h> 85#endif 86 87#if defined(LLC) && defined(CCITT) 88extern struct ifqueue pkintrq; 89#endif 90 91#define senderr(e) { error = (e); goto bad;} 92 93/* 94 * This really should be defined in if_llc.h but in case it isn't. 95 */ 96#ifndef llc_snap 97#define llc_snap llc_un.type_snap 98#endif 99 100#ifdef __bsdi__ 101#define RTALLOC1(a, b) rtalloc1(a, b) 102#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e) 103#else 104#define RTALLOC1(a, b) rtalloc1(a, b, 0UL) 105#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e, f) 106#endif 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, m0, dst, rt0) 116 register struct ifnet *ifp; 117 struct mbuf *m0; 118 struct sockaddr *dst; 119 struct rtentry *rt0; 120{ 121 short type; 122 int s, error = 0; 123 u_char edst[6]; 124 register struct mbuf *m = m0; 125 register struct rtentry *rt; 126 struct mbuf *mcopy = (struct mbuf *)0; 127 register struct fddi_header *fh; 128 struct arpcom *ac = (struct arpcom *)ifp; 129 130 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 131 senderr(ENETDOWN); 132 ifp->if_lastchange = time; 133 if (rt = rt0) { 134 if ((rt->rt_flags & RTF_UP) == 0) { 135 if (rt0 = rt = RTALLOC1(dst, 1)) 136 rt->rt_refcnt--; 137 else 138 senderr(EHOSTUNREACH); 139 } 140 if (rt->rt_flags & RTF_GATEWAY) { 141 if (rt->rt_gwroute == 0) 142 goto lookup; 143 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 144 rtfree(rt); rt = rt0; 145 lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 1); 146 if ((rt = rt->rt_gwroute) == 0) 147 senderr(EHOSTUNREACH); 148 } 149 } 150 if (rt->rt_flags & RTF_REJECT) 151 if (rt->rt_rmx.rmx_expire == 0 || 152 time.tv_sec < rt->rt_rmx.rmx_expire) 153 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 154 } 155 switch (dst->sa_family) { 156 157#ifdef INET 158 case AF_INET: 159 if (!ARPRESOLVE(ac, rt, m, dst, edst, rt0)) 160 return (0); /* if not yet resolved */ 161 /* If broadcasting on a simplex interface, loopback a copy */ 162 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 163 mcopy = m_copy(m, 0, (int)M_COPYALL); 164 type = ETHERTYPE_IP; 165 break; 166#endif 167#ifdef NS 168 case AF_NS: 169 type = ETHERTYPE_NS; 170 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 171 (caddr_t)edst, sizeof (edst)); 172 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))) 173 return (looutput(ifp, m, dst, rt)); 174 /* If broadcasting on a simplex interface, loopback a copy */ 175 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 176 mcopy = m_copy(m, 0, (int)M_COPYALL); 177 break; 178#endif 179#ifdef ISO 180 case AF_ISO: { 181 int snpalen; 182 struct llc *l; 183 register struct sockaddr_dl *sdl; 184 185 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) && 186 sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) { 187 bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst)); 188 } else if (error = 189 iso_snparesolve(ifp, (struct sockaddr_iso *)dst, 190 (char *)edst, &snpalen)) 191 goto bad; /* Not Resolved */ 192 /* If broadcasting on a simplex interface, loopback a copy */ 193 if (*edst & 1) 194 m->m_flags |= (M_BCAST|M_MCAST); 195 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) && 196 (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 197 M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT); 198 if (mcopy) { 199 fh = mtod(mcopy, struct fddi_header *); 200 bcopy((caddr_t)edst, 201 (caddr_t)fh->fddi_dhost, sizeof (edst)); 202 bcopy((caddr_t)ac->ac_enaddr, 203 (caddr_t)fh->fddi_shost, sizeof (edst)); 204 } 205 } 206 M_PREPEND(m, 3, M_DONTWAIT); 207 if (m == NULL) 208 return (0); 209 type = 0; 210 l = mtod(m, struct llc *); 211 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; 212 l->llc_control = LLC_UI; 213 IFDEBUG(D_ETHER) 214 int i; 215 printf("unoutput: sending pkt to: "); 216 for (i=0; i<6; i++) 217 printf("%x ", edst[i] & 0xff); 218 printf("\n"); 219 ENDDEBUG 220 } break; 221#endif /* ISO */ 222#ifdef LLC 223/* case AF_NSAP: */ 224 case AF_CCITT: { 225 register struct sockaddr_dl *sdl = 226 (struct sockaddr_dl *) rt -> rt_gateway; 227 228 if (sdl && sdl->sdl_family == AF_LINK 229 && sdl->sdl_alen > 0) { 230 bcopy(LLADDR(sdl), (char *)edst, 231 sizeof(edst)); 232 } else goto bad; /* Not a link interface ? Funny ... */ 233 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) && 234 (mcopy = m_copy(m, 0, (int)M_COPYALL))) { 235 M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT); 236 if (mcopy) { 237 fh = mtod(mcopy, struct fddi_header *); 238 bcopy((caddr_t)edst, 239 (caddr_t)fh->fddi_dhost, sizeof (edst)); 240 bcopy((caddr_t)ac->ac_enaddr, 241 (caddr_t)fh->fddi_shost, sizeof (edst)); 242 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 243 } 244 } 245 type = 0; 246#ifdef LLC_DEBUG 247 { 248 int i; 249 register struct llc *l = mtod(m, struct llc *); 250 251 printf("fddi_output: sending LLC2 pkt to: "); 252 for (i=0; i<6; i++) 253 printf("%x ", edst[i] & 0xff); 254 printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n", 255 type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff, 256 l->llc_control & 0xff); 257 258 } 259#endif /* LLC_DEBUG */ 260 } break; 261#endif /* LLC */ 262 263 case AF_UNSPEC: 264 { 265 struct ether_header *eh; 266 eh = (struct ether_header *)dst->sa_data; 267 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); 268 if (*edst & 1) 269 m->m_flags |= (M_BCAST|M_MCAST); 270 type = eh->ether_type; 271 break; 272 } 273 274#if NBPFILTER > 0 275 case AF_IMPLINK: 276 { 277 fh = mtod(m, struct fddi_header *); 278 error = EPROTONOSUPPORT; 279 switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 280 case FDDIFC_LLC_ASYNC: { 281 /* legal priorities are 0 through 7 */ 282 if ((fh->fddi_fc & FDDIFC_Z) > 7) 283 goto bad; 284 break; 285 } 286 case FDDIFC_LLC_SYNC: { 287 /* FDDIFC_Z bits reserved, must be zero */ 288 if (fh->fddi_fc & FDDIFC_Z) 289 goto bad; 290 break; 291 } 292 case FDDIFC_SMT: { 293 /* FDDIFC_Z bits must be non zero */ 294 if ((fh->fddi_fc & FDDIFC_Z) == 0) 295 goto bad; 296 break; 297 } 298 default: { 299 /* anything else is too dangerous */ 300 goto bad; 301 } 302 } 303 error = 0; 304 if (fh->fddi_dhost[0] & 1) 305 m->m_flags |= (M_BCAST|M_MCAST); 306 goto queue_it; 307 } 308#endif 309 default: 310 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 311 dst->sa_family); 312 senderr(EAFNOSUPPORT); 313 } 314 315 316 if (mcopy) 317 (void) looutput(ifp, mcopy, dst, rt); 318 if (type != 0) { 319 register struct llc *l; 320 M_PREPEND(m, sizeof (struct llc), M_DONTWAIT); 321 if (m == 0) 322 senderr(ENOBUFS); 323 l = mtod(m, struct llc *); 324 l->llc_control = LLC_UI; 325 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 326 l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0; 327 type = ntohs(type); 328 bcopy((caddr_t) &type, (caddr_t) &l->llc_snap.ether_type, 329 sizeof(u_short)); 330 } 331 /* 332 * Add local net header. If no space in first mbuf, 333 * allocate another. 334 */ 335 M_PREPEND(m, sizeof (struct fddi_header), M_DONTWAIT); 336 if (m == 0) 337 senderr(ENOBUFS); 338 fh = mtod(m, struct fddi_header *); 339 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 340 bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, sizeof (edst)); 341 queue_it: 342 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)fh->fddi_shost, 343 sizeof(fh->fddi_shost)); 344 s = splimp(); 345 /* 346 * Queue message on interface, and start output if interface 347 * not yet active. 348 */ 349 if (IF_QFULL(&ifp->if_snd)) { 350 IF_DROP(&ifp->if_snd); 351 splx(s); 352 senderr(ENOBUFS); 353 } 354 ifp->if_obytes += m->m_pkthdr.len; 355 IF_ENQUEUE(&ifp->if_snd, m); 356 if ((ifp->if_flags & IFF_OACTIVE) == 0) 357 (*ifp->if_start)(ifp); 358 splx(s); 359 if (m->m_flags & M_MCAST) 360 ifp->if_omcasts++; 361 return (error); 362 363bad: 364 if (m) 365 m_freem(m); 366 return (error); 367} 368 369/* 370 * Process a received FDDI packet; 371 * the packet is in the mbuf chain m without 372 * the fddi header, which is provided separately. 373 */ 374void 375fddi_input(ifp, fh, m) 376 struct ifnet *ifp; 377 register struct fddi_header *fh; 378 struct mbuf *m; 379{ 380 register struct ifqueue *inq; 381 register struct llc *l; 382 int s; 383 384 if ((ifp->if_flags & IFF_UP) == 0) { 385 m_freem(m); 386 return; 387 } 388 ifp->if_lastchange = time; 389 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh); 390 if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost, 391 sizeof(fddibroadcastaddr)) == 0) 392 m->m_flags |= M_BCAST; 393 else if (fh->fddi_dhost[0] & 1) 394 m->m_flags |= M_MCAST; 395 if (m->m_flags & (M_BCAST|M_MCAST)) 396 ifp->if_imcasts++; 397 398 l = mtod(m, struct llc *); 399 switch (l->llc_dsap) { 400#if defined(INET) || defined(NS) || defined(DECNET) 401 case LLC_SNAP_LSAP: 402 { 403 unsigned fddi_type; 404 if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP) 405 goto dropanyway; 406 if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0) 407 goto dropanyway; 408 fddi_type = ntohs(l->llc_snap.ether_type); 409 m_adj(m, 8); 410 switch (fddi_type) { 411#ifdef INET 412 case ETHERTYPE_IP: 413 schednetisr(NETISR_IP); 414 inq = &ipintrq; 415 break; 416 417 case ETHERTYPE_ARP: 418 schednetisr(NETISR_ARP); 419 inq = &arpintrq; 420 break; 421#endif 422#ifdef NS 423 case ETHERTYPE_NS: 424 schednetisr(NETISR_NS); 425 inq = &nsintrq; 426 break; 427#endif 428#ifdef DECNET 429 case ETHERTYPE_DECENT: 430 schednetisr(NETISR_DECNET); 431 inq = &decnetintrq; 432 break; 433#endif 434 default: 435 printf("fddi_input: unknown protocol 0x%x\n", fddi_type); 436 ifp->if_noproto++; 437 goto dropanyway; 438 } 439 break; 440 } 441#endif /* INET || NS */ 442#ifdef ISO 443 case LLC_ISO_LSAP: 444 switch (l->llc_control) { 445 case LLC_UI: 446 /* LLC_UI_P forbidden in class 1 service */ 447 if ((l->llc_dsap == LLC_ISO_LSAP) && 448 (l->llc_ssap == LLC_ISO_LSAP)) { 449 /* LSAP for ISO */ 450 m->m_data += 3; /* XXX */ 451 m->m_len -= 3; /* XXX */ 452 m->m_pkthdr.len -= 3; /* XXX */ 453 M_PREPEND(m, sizeof *fh, M_DONTWAIT); 454 if (m == 0) 455 return; 456 *mtod(m, struct fddi_header *) = *fh; 457 IFDEBUG(D_ETHER) 458 printf("clnp packet"); 459 ENDDEBUG 460 schednetisr(NETISR_ISO); 461 inq = &clnlintrq; 462 break; 463 } 464 goto dropanyway; 465 466 case LLC_XID: 467 case LLC_XID_P: 468 if(m->m_len < 6) 469 goto dropanyway; 470 l->llc_window = 0; 471 l->llc_fid = 9; 472 l->llc_class = 1; 473 l->llc_dsap = l->llc_ssap = 0; 474 /* Fall through to */ 475 case LLC_TEST: 476 case LLC_TEST_P: 477 { 478 struct sockaddr sa; 479 register struct ether_header *eh2; 480 int i; 481 u_char c = l->llc_dsap; 482 483 l->llc_dsap = l->llc_ssap; 484 l->llc_ssap = c; 485 if (m->m_flags & (M_BCAST | M_MCAST)) 486 bcopy((caddr_t)ac->ac_enaddr, 487 (caddr_t)eh->ether_dhost, 6); 488 sa.sa_family = AF_UNSPEC; 489 sa.sa_len = sizeof(sa); 490 eh2 = (struct ether_header *)sa.sa_data; 491 for (i = 0; i < 6; i++) { 492 eh2->ether_shost[i] = c = eh->fddi_dhost[i]; 493 eh2->ether_dhost[i] = 494 eh->ether_dhost[i] = eh->fddi_shost[i]; 495 eh2->ether_shost[i] = c; 496 } 497 eh2->ether_type = 0; 498 ifp->if_output(ifp, m, &sa, NULL); 499 return; 500 } 501 default: 502 m_freem(m); 503 return; 504 } 505 break; 506#endif /* ISO */ 507#ifdef LLC 508 case LLC_X25_LSAP: 509 { 510 M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT); 511 if (m == 0) 512 return; 513 if ( !sdl_sethdrif(ifp, fh->fddi_shost, LLC_X25_LSAP, 514 fh->fddi_dhost, LLC_X25_LSAP, 6, 515 mtod(m, struct sdl_hdr *))) 516 panic("ETHER cons addr failure"); 517 mtod(m, struct sdl_hdr *)->sdlhdr_len = m->m_pkthdr.len - sizeof(struct sdl_hdr); 518#ifdef LLC_DEBUG 519 printf("llc packet\n"); 520#endif /* LLC_DEBUG */ 521 schednetisr(NETISR_CCITT); 522 inq = &llcintrq; 523 break; 524 } 525#endif /* LLC */ 526 527 default: 528 printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); 529 ifp->if_noproto++; 530 dropanyway: 531 m_freem(m); 532 return; 533 } 534 535 s = splimp(); 536 if (IF_QFULL(inq)) { 537 IF_DROP(inq); 538 m_freem(m); 539 } else 540 IF_ENQUEUE(inq, m); 541 splx(s); 542} 543/* 544 * Perform common duties while attaching to interface list 545 */ 546void 547fddi_ifattach(ifp) 548 register struct ifnet *ifp; 549{ 550 register struct ifaddr *ifa; 551 register struct sockaddr_dl *sdl; 552 553 ifp->if_type = IFT_FDDI; 554 ifp->if_addrlen = 6; 555 ifp->if_hdrlen = 21; 556 ifp->if_mtu = FDDIMTU; 557 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 558 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 559 sdl->sdl_family == AF_LINK) { 560 sdl->sdl_type = IFT_FDDI; 561 sdl->sdl_alen = ifp->if_addrlen; 562 bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr, 563 LLADDR(sdl), ifp->if_addrlen); 564 break; 565 } 566} 567