|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1989 Regents of the University of California. ! 3: * 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: * @(#)if_ethersubr.c 7.13 (Berkeley) 4/20/91 ! 34: */ ! 35: ! 36: #include "param.h" ! 37: #include "systm.h" ! 38: #include "kernel.h" ! 39: #include "malloc.h" ! 40: #include "mbuf.h" ! 41: #include "protosw.h" ! 42: #include "socket.h" ! 43: #include "ioctl.h" ! 44: #include "errno.h" ! 45: #include "syslog.h" ! 46: ! 47: #include "if.h" ! 48: #include "netisr.h" ! 49: #include "route.h" ! 50: #include "if_llc.h" ! 51: #include "if_dl.h" ! 52: ! 53: #include "machine/mtpr.h" ! 54: ! 55: #ifdef INET ! 56: #include "../netinet/in.h" ! 57: #include "../netinet/in_var.h" ! 58: #endif ! 59: #include "../netinet/if_ether.h" ! 60: ! 61: #ifdef NS ! 62: #include "../netns/ns.h" ! 63: #include "../netns/ns_if.h" ! 64: #endif ! 65: ! 66: #ifdef ISO ! 67: #include "../netiso/argo_debug.h" ! 68: #include "../netiso/iso.h" ! 69: #include "../netiso/iso_var.h" ! 70: #include "../netiso/iso_snpac.h" ! 71: #endif ! 72: ! 73: u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; ! 74: extern struct ifnet loif; ! 75: ! 76: /* ! 77: * Ethernet output routine. ! 78: * Encapsulate a packet of type family for the local net. ! 79: * Use trailer local net encapsulation if enough data in first ! 80: * packet leaves a multiple of 512 bytes of data in remainder. ! 81: * Assumes that ifp is actually pointer to arpcom structure. ! 82: */ ! 83: ether_output(ifp, m0, dst, rt) ! 84: register struct ifnet *ifp; ! 85: struct mbuf *m0; ! 86: struct sockaddr *dst; ! 87: struct rtentry *rt; ! 88: { ! 89: short type; ! 90: int s, error = 0; ! 91: u_char edst[6]; ! 92: struct in_addr idst; ! 93: register struct mbuf *m = m0; ! 94: struct mbuf *mcopy = (struct mbuf *)0; ! 95: register struct ether_header *eh; ! 96: int usetrailers, off, len = m->m_pkthdr.len; ! 97: #define ac ((struct arpcom *)ifp) ! 98: ! 99: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { ! 100: error = ENETDOWN; ! 101: goto bad; ! 102: } ! 103: ifp->if_lastchange = time; ! 104: switch (dst->sa_family) { ! 105: ! 106: #ifdef INET ! 107: case AF_INET: ! 108: idst = ((struct sockaddr_in *)dst)->sin_addr; ! 109: if (!arpresolve(ac, m, &idst, edst, &usetrailers)) ! 110: return (0); /* if not yet resolved */ ! 111: if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1)) ! 112: mcopy = m_copy(m, 0, (int)M_COPYALL); ! 113: off = m->m_pkthdr.len - m->m_len; ! 114: if (usetrailers && off > 0 && (off & 0x1ff) == 0 && ! 115: (m->m_flags & M_EXT) == 0 && ! 116: m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { ! 117: type = ETHERTYPE_TRAIL + (off>>9); ! 118: m->m_data -= 2 * sizeof (u_short); ! 119: m->m_len += 2 * sizeof (u_short); ! 120: len += 2 * sizeof (u_short); ! 121: *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); ! 122: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); ! 123: goto gottrailertype; ! 124: } ! 125: type = ETHERTYPE_IP; ! 126: goto gottype; ! 127: #endif ! 128: #ifdef NS ! 129: case AF_NS: ! 130: type = ETHERTYPE_NS; ! 131: bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), ! 132: (caddr_t)edst, sizeof (edst)); ! 133: if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))) ! 134: return (looutput(ifp, m, dst, rt)); ! 135: if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1)) ! 136: mcopy = m_copy(m, 0, (int)M_COPYALL); ! 137: goto gottype; ! 138: #endif ! 139: #ifdef ISO ! 140: case AF_ISO: { ! 141: int snpalen; ! 142: struct llc *l; ! 143: ! 144: iso_again: ! 145: if (rt && rt->rt_gateway && (rt->rt_flags & RTF_UP)) { ! 146: if (rt->rt_flags & RTF_GATEWAY) { ! 147: if (rt->rt_llinfo) { ! 148: rt = (struct rtentry *)rt->rt_llinfo; ! 149: goto iso_again; ! 150: } ! 151: } else { ! 152: register struct sockaddr_dl *sdl = ! 153: (struct sockaddr_dl *)rt->rt_gateway; ! 154: if (sdl && sdl->sdl_family == AF_LINK ! 155: && sdl->sdl_alen > 0) { ! 156: bcopy(LLADDR(sdl), (char *)edst, ! 157: sizeof(edst)); ! 158: goto iso_resolved; ! 159: } ! 160: } ! 161: } ! 162: if ((error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst, ! 163: (char *)edst, &snpalen)) > 0) ! 164: goto bad; /* Not Resolved */ ! 165: iso_resolved: ! 166: if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) && ! 167: (mcopy = m_copy(m, 0, (int)M_COPYALL))) { ! 168: M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT); ! 169: if (mcopy) { ! 170: eh = mtod(mcopy, struct ether_header *); ! 171: bcopy((caddr_t)edst, ! 172: (caddr_t)eh->ether_dhost, sizeof (edst)); ! 173: bcopy((caddr_t)ac->ac_enaddr, ! 174: (caddr_t)eh->ether_shost, sizeof (edst)); ! 175: } ! 176: } ! 177: M_PREPEND(m, 3, M_DONTWAIT); ! 178: if (m == NULL) ! 179: return (0); ! 180: type = m->m_pkthdr.len; ! 181: l = mtod(m, struct llc *); ! 182: l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; ! 183: l->llc_control = LLC_UI; ! 184: len += 3; ! 185: IFDEBUG(D_ETHER) ! 186: int i; ! 187: printf("unoutput: sending pkt to: "); ! 188: for (i=0; i<6; i++) ! 189: printf("%x ", edst[i] & 0xff); ! 190: printf("\n"); ! 191: ENDDEBUG ! 192: } goto gottype; ! 193: #endif ISO ! 194: #ifdef RMP ! 195: case AF_RMP: ! 196: /* ! 197: * This is IEEE 802.3 -- the Ethernet `type' field is ! 198: * really a `length' field. ! 199: */ ! 200: type = m->m_len; ! 201: bcopy((caddr_t)dst->sa_data, (caddr_t)edst, sizeof(edst)); ! 202: break; ! 203: #endif ! 204: ! 205: case AF_UNSPEC: ! 206: eh = (struct ether_header *)dst->sa_data; ! 207: bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); ! 208: type = eh->ether_type; ! 209: goto gottype; ! 210: ! 211: default: ! 212: printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, ! 213: dst->sa_family); ! 214: error = EAFNOSUPPORT; ! 215: goto bad; ! 216: } ! 217: ! 218: gottrailertype: ! 219: /* ! 220: * Packet to be sent as trailer: move first packet ! 221: * (control information) to end of chain. ! 222: */ ! 223: while (m->m_next) ! 224: m = m->m_next; ! 225: m->m_next = m0; ! 226: m = m0->m_next; ! 227: m0->m_next = 0; ! 228: ! 229: gottype: ! 230: if (mcopy) ! 231: (void) looutput(ifp, mcopy, dst, rt); ! 232: /* ! 233: * Add local net header. If no space in first mbuf, ! 234: * allocate another. ! 235: */ ! 236: M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); ! 237: if (m == 0) { ! 238: error = ENOBUFS; ! 239: goto bad; ! 240: } ! 241: eh = mtod(m, struct ether_header *); ! 242: type = htons((u_short)type); ! 243: bcopy((caddr_t)&type,(caddr_t)&eh->ether_type, ! 244: sizeof(eh->ether_type)); ! 245: bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); ! 246: bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost, ! 247: sizeof(eh->ether_shost)); ! 248: s = splimp(); ! 249: /* ! 250: * Queue message on interface, and start output if interface ! 251: * not yet active. ! 252: */ ! 253: if (IF_QFULL(&ifp->if_snd)) { ! 254: IF_DROP(&ifp->if_snd); ! 255: splx(s); ! 256: error = ENOBUFS; ! 257: goto bad; ! 258: } ! 259: IF_ENQUEUE(&ifp->if_snd, m); ! 260: if ((ifp->if_flags & IFF_OACTIVE) == 0) ! 261: (*ifp->if_start)(ifp); ! 262: splx(s); ! 263: ifp->if_obytes += len + sizeof (struct ether_header); ! 264: if (edst[0] & 1) ! 265: ifp->if_omcasts++; ! 266: return (error); ! 267: ! 268: bad: ! 269: if (m) ! 270: m_freem(m); ! 271: return (error); ! 272: } ! 273: ! 274: /* ! 275: * Process a received Ethernet packet; ! 276: * the packet is in the mbuf chain m without ! 277: * the ether header, which is provided separately. ! 278: */ ! 279: ether_input(ifp, eh, m) ! 280: struct ifnet *ifp; ! 281: register struct ether_header *eh; ! 282: struct mbuf *m; ! 283: { ! 284: register struct ifqueue *inq; ! 285: register struct llc *l; ! 286: int s; ! 287: ! 288: ifp->if_lastchange = time; ! 289: ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); ! 290: if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, ! 291: sizeof(etherbroadcastaddr)) == 0) ! 292: m->m_flags |= M_BCAST; ! 293: else if (eh->ether_dhost[0] & 1) ! 294: m->m_flags |= M_MCAST; ! 295: if (m->m_flags & (M_BCAST|M_MCAST)) ! 296: ifp->if_imcasts++; ! 297: ! 298: switch (eh->ether_type) { ! 299: #ifdef INET ! 300: case ETHERTYPE_IP: ! 301: schednetisr(NETISR_IP); ! 302: inq = &ipintrq; ! 303: break; ! 304: ! 305: case ETHERTYPE_ARP: ! 306: arpinput((struct arpcom *)ifp, m); ! 307: return; ! 308: #endif ! 309: #ifdef NS ! 310: case ETHERTYPE_NS: ! 311: schednetisr(NETISR_NS); ! 312: inq = &nsintrq; ! 313: break; ! 314: ! 315: #endif ! 316: default: ! 317: #ifdef ISO ! 318: if (eh->ether_type > ETHERMTU) ! 319: goto dropanyway; ! 320: l = mtod(m, struct llc *); ! 321: switch (l->llc_control) { ! 322: case LLC_UI: ! 323: /* LLC_UI_P forbidden in class 1 service */ ! 324: if ((l->llc_dsap == LLC_ISO_LSAP) && ! 325: (l->llc_ssap == LLC_ISO_LSAP)) { ! 326: /* LSAP for ISO */ ! 327: if (m->m_pkthdr.len > eh->ether_type) ! 328: m_adj(m, eh->ether_type - m->m_pkthdr.len); ! 329: m->m_data += 3; /* XXX */ ! 330: m->m_len -= 3; /* XXX */ ! 331: m->m_pkthdr.len -= 3; /* XXX */ ! 332: M_PREPEND(m, sizeof *eh, M_DONTWAIT); ! 333: if (m == 0) ! 334: return; ! 335: *mtod(m, struct ether_header *) = *eh; ! 336: IFDEBUG(D_ETHER) ! 337: printf("clnp packet"); ! 338: ENDDEBUG ! 339: schednetisr(NETISR_ISO); ! 340: inq = &clnlintrq; ! 341: break; ! 342: } ! 343: goto dropanyway; ! 344: ! 345: case LLC_XID: ! 346: case LLC_XID_P: ! 347: if(m->m_len < 6) ! 348: goto dropanyway; ! 349: l->llc_window = 0; ! 350: l->llc_fid = 9; ! 351: l->llc_class = 1; ! 352: l->llc_dsap = l->llc_ssap = 0; ! 353: /* Fall through to */ ! 354: case LLC_TEST: ! 355: case LLC_TEST_P: ! 356: { ! 357: struct sockaddr sa; ! 358: register struct ether_header *eh2; ! 359: int i; ! 360: u_char c = l->llc_dsap; ! 361: l->llc_dsap = l->llc_ssap; ! 362: l->llc_ssap = c; ! 363: if (m->m_flags & (M_BCAST | M_MCAST)) ! 364: bcopy((caddr_t)ac->ac_enaddr, ! 365: (caddr_t)eh->ether_dhost, 6); ! 366: sa.sa_family = AF_UNSPEC; ! 367: sa.sa_len = sizeof(sa); ! 368: eh2 = (struct ether_header *)sa.sa_data; ! 369: for (i = 0; i < 6; i++) { ! 370: eh2->ether_shost[i] = c = eh->ether_dhost[i]; ! 371: eh2->ether_dhost[i] = ! 372: eh->ether_dhost[i] = eh->ether_shost[i]; ! 373: eh->ether_shost[i] = c; ! 374: } ! 375: ifp->if_output(ifp, m, &sa); ! 376: return; ! 377: } ! 378: dropanyway: ! 379: default: ! 380: m_freem(m); ! 381: return; ! 382: } ! 383: #else ! 384: m_freem(m); ! 385: return; ! 386: #endif ISO ! 387: } ! 388: ! 389: s = splimp(); ! 390: if (IF_QFULL(inq)) { ! 391: IF_DROP(inq); ! 392: m_freem(m); ! 393: } else ! 394: IF_ENQUEUE(inq, m); ! 395: splx(s); ! 396: } ! 397: ! 398: /* ! 399: * Convert Ethernet address to printable (loggable) representation. ! 400: */ ! 401: static char digits[] = "0123456789abcdef"; ! 402: char * ! 403: ether_sprintf(ap) ! 404: register u_char *ap; ! 405: { ! 406: register i; ! 407: static char etherbuf[18]; ! 408: register char *cp = etherbuf; ! 409: ! 410: for (i = 0; i < 6; i++) { ! 411: *cp++ = digits[*ap >> 4]; ! 412: *cp++ = digits[*ap++ & 0xf]; ! 413: *cp++ = ':'; ! 414: } ! 415: *--cp = 0; ! 416: return (etherbuf); ! 417: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.