135379Skfall /* 2*39187Ssklower * Copyright (c) 1982, 1989 Regents of the University of California. 335379Skfall * All rights reserved. 435379Skfall * 535379Skfall * Redistribution and use in source and binary forms are permitted 635379Skfall * provided that the above copyright notice and this paragraph are 735379Skfall * duplicated in all such forms and that any documentation, 835379Skfall * advertising materials, and other materials related to such 935379Skfall * distribution and use acknowledge that the software was developed 1035379Skfall * by the University of California, Berkeley. The name of the 1135379Skfall * University may not be used to endorse or promote products derived 1235379Skfall * from this software without specific prior written permission. 1335379Skfall * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435379Skfall * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535379Skfall * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1635379Skfall * 17*39187Ssklower * @(#)if_ethersubr.c 7.5 (Berkeley) 09/20/89 1835379Skfall */ 1935379Skfall 2035379Skfall #include "param.h" 2135379Skfall #include "systm.h" 2235379Skfall #include "malloc.h" 2335379Skfall #include "mbuf.h" 2435379Skfall #include "protosw.h" 2535379Skfall #include "socket.h" 2635379Skfall #include "ioctl.h" 2735379Skfall #include "errno.h" 2835379Skfall #include "syslog.h" 2935379Skfall 3035379Skfall #include "if.h" 3135379Skfall #include "netisr.h" 3235379Skfall #include "route.h" 3335795Skarels #include "if_llc.h" 3435379Skfall 3537517Smckusick #include "machine/mtpr.h" 3635379Skfall 3735379Skfall #ifdef INET 3835379Skfall #include "../netinet/in.h" 3935379Skfall #include "../netinet/in_var.h" 4035379Skfall #include "../netinet/if_ether.h" 4135379Skfall #endif 4235379Skfall 4335379Skfall #ifdef NS 4435379Skfall #include "../netns/ns.h" 4535379Skfall #include "../netns/ns_if.h" 4635379Skfall #endif 4735379Skfall 4837472Ssklower #ifdef ISO 4937472Ssklower #include "../netiso/argo_debug.h" 5037472Ssklower #include "../netiso/iso.h" 5137472Ssklower #include "../netiso/iso_var.h" 5237472Ssklower #endif 5337472Ssklower 5435379Skfall u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 5535795Skarels extern struct ifnet loif; 5635379Skfall 5735379Skfall /* 5835379Skfall * Ethernet output routine. 5935379Skfall * Encapsulate a packet of type family for the local net. 6035379Skfall * Use trailer local net encapsulation if enough data in first 6135379Skfall * packet leaves a multiple of 512 bytes of data in remainder. 6235379Skfall * Assumes that ifp is actually pointer to arpcom structure. 6335379Skfall */ 6437472Ssklower ether_output(ifp, m0, dst) 6535379Skfall register struct ifnet *ifp; 6635379Skfall struct mbuf *m0; 6735379Skfall struct sockaddr *dst; 6835379Skfall { 6935795Skarels short type; 7035795Skarels int s, error = 0; 7135379Skfall u_char edst[6]; 7235379Skfall struct in_addr idst; 7335379Skfall register struct mbuf *m = m0; 7435795Skarels struct mbuf *mcopy = (struct mbuf *)0; 7535379Skfall register struct ether_header *eh; 76*39187Ssklower int usetrailers, off, len = m->m_pkthdr.len; 77*39187Ssklower extern struct timeval time; 7835379Skfall #define ac ((struct arpcom *)ifp) 7935379Skfall 8035379Skfall if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 8135379Skfall error = ENETDOWN; 8235379Skfall goto bad; 8335379Skfall } 84*39187Ssklower ifp->if_lastchange = time; 8535379Skfall switch (dst->sa_family) { 8635379Skfall 8735379Skfall #ifdef INET 8835379Skfall case AF_INET: 8935379Skfall idst = ((struct sockaddr_in *)dst)->sin_addr; 9035379Skfall if (!arpresolve(ac, m, &idst, edst, &usetrailers)) 9135379Skfall return (0); /* if not yet resolved */ 9237472Ssklower if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1)) 9337472Ssklower mcopy = m_copy(m, 0, (int)M_COPYALL); 9435379Skfall off = m->m_pkthdr.len - m->m_len; 9535379Skfall if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 9635379Skfall (m->m_flags & M_EXT) == 0 && 9735379Skfall m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { 9835379Skfall type = ETHERTYPE_TRAIL + (off>>9); 9935379Skfall m->m_data -= 2 * sizeof (u_short); 10035379Skfall m->m_len += 2 * sizeof (u_short); 101*39187Ssklower len += 2 * sizeof (u_short); 10235379Skfall *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 10335379Skfall *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 10435379Skfall goto gottrailertype; 10535379Skfall } 10635379Skfall type = ETHERTYPE_IP; 10735379Skfall goto gottype; 10835379Skfall #endif 10935379Skfall #ifdef NS 11035379Skfall case AF_NS: 11135379Skfall type = ETHERTYPE_NS; 112*39187Ssklower bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 113*39187Ssklower (caddr_t)edst, sizeof (edst)); 11435795Skarels if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))) 11535795Skarels return(looutput(&loif, m, dst)); 11637472Ssklower if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1)) 11737472Ssklower mcopy = m_copy(m, 0, (int)M_COPYALL); 11835379Skfall goto gottype; 11935379Skfall #endif 12035795Skarels #ifdef ISO 12135795Skarels case AF_ISO: { 12237472Ssklower int len; 12335795Skarels int ret; 12437472Ssklower struct llc *l; 12537472Ssklower 12637472Ssklower if ((ret = iso_tryloopback(m, (struct sockaddr_iso *)dst)) >= 0) 12737472Ssklower return (ret); 12837472Ssklower ret = iso_snparesolve(ifp, (struct sockaddr_iso *)dst, 12937472Ssklower (char *)edst, &len); 13037472Ssklower if (ret > 0) { 13137472Ssklower m_freem(m); /* Not Resolved */ 13237472Ssklower return(ret); 13335795Skarels } 13435795Skarels M_PREPEND(m, 3, M_DONTWAIT); 13537472Ssklower if (m == NULL) 13635795Skarels return(0); 13735795Skarels type = m->m_pkthdr.len; 13835795Skarels l = mtod(m, struct llc *); 13935795Skarels l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP; 14035795Skarels l->llc_control = LLC_UI; 141*39187Ssklower len += 3; 14235795Skarels IFDEBUG(D_ETHER) 14335795Skarels int i; 14435795Skarels printf("unoutput: sending pkt to: "); 14535795Skarels for (i=0; i<6; i++) 14635795Skarels printf("%x ", edst[i] & 0xff); 14735795Skarels printf("\n"); 14835795Skarels ENDDEBUG 14935795Skarels } goto gottype; 15035795Skarels #endif ISO 15135379Skfall case AF_UNSPEC: 15235379Skfall eh = (struct ether_header *)dst->sa_data; 15335379Skfall bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); 15435379Skfall type = eh->ether_type; 15535379Skfall goto gottype; 15635379Skfall 15735379Skfall default: 15835379Skfall printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 15935379Skfall dst->sa_family); 16035379Skfall error = EAFNOSUPPORT; 16135379Skfall goto bad; 16235379Skfall } 16335379Skfall 16435379Skfall gottrailertype: 16535379Skfall /* 16635379Skfall * Packet to be sent as trailer: move first packet 16735379Skfall * (control information) to end of chain. 16835379Skfall */ 16935379Skfall while (m->m_next) 17035379Skfall m = m->m_next; 17135379Skfall m->m_next = m0; 17235379Skfall m = m0->m_next; 17335379Skfall m0->m_next = 0; 17435379Skfall 17535379Skfall gottype: 17635379Skfall /* 17735379Skfall * Add local net header. If no space in first mbuf, 17835379Skfall * allocate another. 17935379Skfall */ 18035379Skfall M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); 18135379Skfall if (m == 0) { 18235379Skfall error = ENOBUFS; 18335379Skfall goto bad; 18435379Skfall } 18535379Skfall eh = mtod(m, struct ether_header *); 18635795Skarels type = htons((u_short)type); 18735795Skarels bcopy((caddr_t)&type,(caddr_t)&eh->ether_type, 18835795Skarels sizeof(eh->ether_type)); 18935379Skfall bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); 19035379Skfall bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost, 19135379Skfall sizeof(eh->ether_shost)); 19235379Skfall /* 19335379Skfall * Queue message on interface, and start output if interface 19435379Skfall * not yet active. 19535379Skfall */ 19635379Skfall s = splimp(); 19735379Skfall if (IF_QFULL(&ifp->if_snd)) { 19835379Skfall IF_DROP(&ifp->if_snd); 19935379Skfall splx(s); 20035795Skarels error = ENOBUFS; 20135795Skarels goto bad; 20235379Skfall } 20335379Skfall IF_ENQUEUE(&ifp->if_snd, m); 20435379Skfall if ((ifp->if_flags & IFF_OACTIVE) == 0) 20538845Sroot (*ifp->if_start)(ifp); 20635379Skfall splx(s); 20735795Skarels if (mcopy) 20835795Skarels (void) looutput(&loif, mcopy, dst); 209*39187Ssklower ifp->if_obytes += len + sizeof (struct ether_header); 210*39187Ssklower if (edst[0] & 1) 211*39187Ssklower ifp->if_omcasts++; 21235795Skarels return (error); 21335379Skfall 21435379Skfall bad: 21535795Skarels if (mcopy) 21635795Skarels m_freem(mcopy); 21735795Skarels if (m) 21835795Skarels m_freem(m); 21935379Skfall return (error); 22035379Skfall } 22135379Skfall 22235379Skfall /* 22338845Sroot * Process a received Ethernet packet; 22438845Sroot * the packet is in the mbuf chain m without 22538845Sroot * the ether header, which is provided separately. 22635379Skfall */ 22737472Ssklower ether_input(ifp, eh, m) 22835379Skfall struct ifnet *ifp; 22935379Skfall register struct ether_header *eh; 23035379Skfall struct mbuf *m; 23135379Skfall { 23235379Skfall register struct ifqueue *inq; 23335795Skarels register struct llc *l; 23435379Skfall int s; 23535379Skfall 236*39187Ssklower ifp->if_lastchange = time; 237*39187Ssklower ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh); 23835795Skarels if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost, 23935379Skfall sizeof(etherbroadcastaddr)) == 0) 24035379Skfall m->m_flags |= M_BCAST; 24135795Skarels else if (eh->ether_dhost[0] & 1) 24235795Skarels m->m_flags |= M_MCAST; 243*39187Ssklower if (m->m_flags & (M_BCAST|M_MCAST)) 244*39187Ssklower ifp->if_imcasts++; 24535379Skfall 24635379Skfall switch (eh->ether_type) { 24735379Skfall #ifdef INET 24835379Skfall case ETHERTYPE_IP: 24935379Skfall schednetisr(NETISR_IP); 25035379Skfall inq = &ipintrq; 25135379Skfall break; 25235379Skfall 25335379Skfall case ETHERTYPE_ARP: 25435379Skfall arpinput((struct arpcom *)ifp, m); 25535379Skfall return; 25635379Skfall #endif 25735379Skfall #ifdef NS 25835379Skfall case ETHERTYPE_NS: 25935379Skfall schednetisr(NETISR_NS); 26035379Skfall inq = &nsintrq; 26135379Skfall break; 26235379Skfall 26335379Skfall #endif 26435379Skfall default: 26538845Sroot #ifdef ISO 26637472Ssklower if (eh->ether_type > ETHERMTU) 26735795Skarels goto dropanyway; 26835795Skarels l = mtod(m, struct llc *); 26935795Skarels switch (l->llc_control) { 27035795Skarels case LLC_UI: 27135795Skarels /* LLC_UI_P forbidden in class 1 service */ 27235795Skarels if ((l->llc_dsap == LLC_ISO_LSAP) && 27335795Skarels (l->llc_ssap == LLC_ISO_LSAP)) { 27435795Skarels /* LSAP for ISO */ 27538845Sroot m->m_data += 3; /* XXX */ 27638845Sroot m->m_len -= 3; /* XXX */ 27738845Sroot m->m_pkthdr.len -= 3; /* XXX */ 27837472Ssklower M_PREPEND(m, sizeof *eh, M_DONTWAIT); 27937472Ssklower if (m == 0) 28037472Ssklower return; 28137472Ssklower *mtod(m, struct ether_header *) = *eh; 28237472Ssklower IFDEBUG(D_ETHER) 28337472Ssklower printf("clnp packet"); 28437472Ssklower ENDDEBUG 28537472Ssklower schednetisr(NETISR_ISO); 28635795Skarels inq = &clnlintrq; 28738845Sroot break; 28835795Skarels } 28938845Sroot goto dropanyway; 29038845Sroot 29135795Skarels case LLC_XID: 29235795Skarels case LLC_XID_P: 29335795Skarels if(m->m_len < 6) 29435795Skarels goto dropanyway; 29535795Skarels l->llc_window = 0; 29635795Skarels l->llc_fid = 9; 29735795Skarels l->llc_class = 1; 29835795Skarels l->llc_dsap = l->llc_ssap = 0; 29935795Skarels /* Fall through to */ 30035795Skarels case LLC_TEST: 30135795Skarels case LLC_TEST_P: 30235795Skarels { 30335795Skarels struct sockaddr sa; 30435795Skarels register struct ether_header *eh2; 30535795Skarels int i; 30635795Skarels u_char c = l->llc_dsap; 30735795Skarels l->llc_dsap = l->llc_ssap; 30835795Skarels l->llc_ssap = c; 30937472Ssklower if (m->m_flags & (M_BCAST | M_MCAST)) 31037472Ssklower bcopy((caddr_t)ac->ac_enaddr, 31137472Ssklower (caddr_t)eh->ether_dhost, 6); 31235795Skarels sa.sa_family = AF_UNSPEC; 31337472Ssklower sa.sa_len = sizeof(sa); 31435795Skarels eh2 = (struct ether_header *)sa.sa_data; 31535795Skarels for (i = 0; i < 6; i++) { 31635795Skarels eh2->ether_shost[i] = c = eh->ether_dhost[i]; 31735795Skarels eh2->ether_dhost[i] = 31835795Skarels eh->ether_dhost[i] = eh->ether_shost[i]; 31935795Skarels eh->ether_shost[i] = c; 32035795Skarels } 32135795Skarels ifp->if_output(ifp, m, &sa); 32235795Skarels return; 32335795Skarels } 32435795Skarels dropanyway: 32535795Skarels default: 32635795Skarels m_freem(m); 32735795Skarels return; 32835795Skarels } 32938845Sroot #else 33038845Sroot m_freem(m); 33138845Sroot return; 33238845Sroot #endif ISO 33335379Skfall } 33435379Skfall 33535379Skfall s = splimp(); 33635379Skfall if (IF_QFULL(inq)) { 33735379Skfall IF_DROP(inq); 33835379Skfall m_freem(m); 33935379Skfall } else 34035379Skfall IF_ENQUEUE(inq, m); 34135379Skfall splx(s); 34235379Skfall } 34335379Skfall 34435379Skfall /* 34535379Skfall * Convert Ethernet address to printable (loggable) representation. 34635379Skfall */ 34737472Ssklower static char digits[] = "0123456789abcdef"; 34835379Skfall char * 34935379Skfall ether_sprintf(ap) 35035379Skfall register u_char *ap; 35135379Skfall { 35235379Skfall register i; 35335379Skfall static char etherbuf[18]; 35435379Skfall register char *cp = etherbuf; 35535379Skfall 35635379Skfall for (i = 0; i < 6; i++) { 35735379Skfall *cp++ = digits[*ap >> 4]; 35835379Skfall *cp++ = digits[*ap++ & 0xf]; 35935379Skfall *cp++ = ':'; 36035379Skfall } 36135379Skfall *--cp = 0; 36235379Skfall return (etherbuf); 36335379Skfall } 364