1*35379Skfall /* 2*35379Skfall * Copyright (c) 1982, 1986, 1988 Regents of the University of California. 3*35379Skfall * All rights reserved. 4*35379Skfall * 5*35379Skfall * Redistribution and use in source and binary forms are permitted 6*35379Skfall * provided that the above copyright notice and this paragraph are 7*35379Skfall * duplicated in all such forms and that any documentation, 8*35379Skfall * advertising materials, and other materials related to such 9*35379Skfall * distribution and use acknowledge that the software was developed 10*35379Skfall * by the University of California, Berkeley. The name of the 11*35379Skfall * University may not be used to endorse or promote products derived 12*35379Skfall * from this software without specific prior written permission. 13*35379Skfall * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*35379Skfall * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*35379Skfall * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*35379Skfall * 17*35379Skfall * @(#)if_ethersubr.c 1.1 (Berkeley) 08/18/88 18*35379Skfall */ 19*35379Skfall 20*35379Skfall #include "param.h" 21*35379Skfall #include "systm.h" 22*35379Skfall #include "malloc.h" 23*35379Skfall #include "mbuf.h" 24*35379Skfall #include "protosw.h" 25*35379Skfall #include "socket.h" 26*35379Skfall #include "ioctl.h" 27*35379Skfall #include "errno.h" 28*35379Skfall #include "syslog.h" 29*35379Skfall 30*35379Skfall #include "if.h" 31*35379Skfall #include "netisr.h" 32*35379Skfall #include "route.h" 33*35379Skfall 34*35379Skfall #include "../machine/mtpr.h" 35*35379Skfall 36*35379Skfall #ifdef INET 37*35379Skfall #include "../netinet/in.h" 38*35379Skfall #include "../netinet/in_var.h" 39*35379Skfall #include "../netinet/if_ether.h" 40*35379Skfall #endif 41*35379Skfall 42*35379Skfall #ifdef NS 43*35379Skfall #include "../netns/ns.h" 44*35379Skfall #include "../netns/ns_if.h" 45*35379Skfall #endif 46*35379Skfall 47*35379Skfall u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 48*35379Skfall 49*35379Skfall /* 50*35379Skfall * Ethernet output routine. 51*35379Skfall * Encapsulate a packet of type family for the local net. 52*35379Skfall * Use trailer local net encapsulation if enough data in first 53*35379Skfall * packet leaves a multiple of 512 bytes of data in remainder. 54*35379Skfall * Assumes that ifp is actually pointer to arpcom structure. 55*35379Skfall */ 56*35379Skfall enoutput(ifp, m0, dst) 57*35379Skfall register struct ifnet *ifp; 58*35379Skfall struct mbuf *m0; 59*35379Skfall struct sockaddr *dst; 60*35379Skfall { 61*35379Skfall int type, s, error; 62*35379Skfall u_char edst[6]; 63*35379Skfall struct in_addr idst; 64*35379Skfall register struct mbuf *m = m0; 65*35379Skfall register struct ether_header *eh; 66*35379Skfall register int off; 67*35379Skfall int usetrailers; 68*35379Skfall #define ac ((struct arpcom *)ifp) 69*35379Skfall 70*35379Skfall if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 71*35379Skfall error = ENETDOWN; 72*35379Skfall goto bad; 73*35379Skfall } 74*35379Skfall switch (dst->sa_family) { 75*35379Skfall 76*35379Skfall #ifdef INET 77*35379Skfall case AF_INET: 78*35379Skfall idst = ((struct sockaddr_in *)dst)->sin_addr; 79*35379Skfall if (!arpresolve(ac, m, &idst, edst, &usetrailers)) 80*35379Skfall return (0); /* if not yet resolved */ 81*35379Skfall off = m->m_pkthdr.len - m->m_len; 82*35379Skfall if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 83*35379Skfall (m->m_flags & M_EXT) == 0 && 84*35379Skfall m->m_data >= m->m_pktdat + 2 * sizeof (u_short)) { 85*35379Skfall type = ETHERTYPE_TRAIL + (off>>9); 86*35379Skfall m->m_data -= 2 * sizeof (u_short); 87*35379Skfall m->m_len += 2 * sizeof (u_short); 88*35379Skfall *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 89*35379Skfall *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 90*35379Skfall goto gottrailertype; 91*35379Skfall } 92*35379Skfall type = ETHERTYPE_IP; 93*35379Skfall off = 0; 94*35379Skfall goto gottype; 95*35379Skfall #endif 96*35379Skfall #ifdef NS 97*35379Skfall case AF_NS: 98*35379Skfall type = ETHERTYPE_NS; 99*35379Skfall bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 100*35379Skfall (caddr_t)edst, sizeof (edst)); 101*35379Skfall off = 0; 102*35379Skfall goto gottype; 103*35379Skfall #endif 104*35379Skfall 105*35379Skfall case AF_UNSPEC: 106*35379Skfall eh = (struct ether_header *)dst->sa_data; 107*35379Skfall bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); 108*35379Skfall type = eh->ether_type; 109*35379Skfall goto gottype; 110*35379Skfall 111*35379Skfall default: 112*35379Skfall printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 113*35379Skfall dst->sa_family); 114*35379Skfall error = EAFNOSUPPORT; 115*35379Skfall goto bad; 116*35379Skfall } 117*35379Skfall 118*35379Skfall gottrailertype: 119*35379Skfall /* 120*35379Skfall * Packet to be sent as trailer: move first packet 121*35379Skfall * (control information) to end of chain. 122*35379Skfall */ 123*35379Skfall while (m->m_next) 124*35379Skfall m = m->m_next; 125*35379Skfall m->m_next = m0; 126*35379Skfall m = m0->m_next; 127*35379Skfall m0->m_next = 0; 128*35379Skfall m0 = m; 129*35379Skfall 130*35379Skfall gottype: 131*35379Skfall /* 132*35379Skfall * Add local net header. If no space in first mbuf, 133*35379Skfall * allocate another. 134*35379Skfall */ 135*35379Skfall M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT); 136*35379Skfall if (m == 0) { 137*35379Skfall error = ENOBUFS; 138*35379Skfall goto bad; 139*35379Skfall } 140*35379Skfall eh = mtod(m, struct ether_header *); 141*35379Skfall eh->ether_type = htons((u_short)type); 142*35379Skfall bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); 143*35379Skfall bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost, 144*35379Skfall sizeof(eh->ether_shost)); 145*35379Skfall 146*35379Skfall /* 147*35379Skfall * Queue message on interface, and start output if interface 148*35379Skfall * not yet active. 149*35379Skfall */ 150*35379Skfall s = splimp(); 151*35379Skfall if (IF_QFULL(&ifp->if_snd)) { 152*35379Skfall IF_DROP(&ifp->if_snd); 153*35379Skfall splx(s); 154*35379Skfall m_freem(m); 155*35379Skfall return (ENOBUFS); 156*35379Skfall } 157*35379Skfall IF_ENQUEUE(&ifp->if_snd, m); 158*35379Skfall if ((ifp->if_flags & IFF_OACTIVE) == 0) 159*35379Skfall (*ifp->if_start)(ifp->if_unit); 160*35379Skfall splx(s); 161*35379Skfall return (0); 162*35379Skfall 163*35379Skfall bad: 164*35379Skfall m_freem(m0); 165*35379Skfall return (error); 166*35379Skfall } 167*35379Skfall 168*35379Skfall /* 169*35379Skfall * Pull packet off interface. Off is nonzero if packet 170*35379Skfall * has trailing header; we still have to drop 171*35379Skfall * the type and length which are at the front of any trailer data. 172*35379Skfall */ 173*35379Skfall en_doproto(ifp, eh, m) 174*35379Skfall struct ifnet *ifp; 175*35379Skfall register struct ether_header *eh; 176*35379Skfall struct mbuf *m; 177*35379Skfall { 178*35379Skfall register struct ifqueue *inq; 179*35379Skfall int s; 180*35379Skfall 181*35379Skfall if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_shost, 182*35379Skfall sizeof(etherbroadcastaddr)) == 0) 183*35379Skfall m->m_flags |= M_BCAST; 184*35379Skfall 185*35379Skfall switch (eh->ether_type) { 186*35379Skfall #ifdef INET 187*35379Skfall case ETHERTYPE_IP: 188*35379Skfall schednetisr(NETISR_IP); 189*35379Skfall inq = &ipintrq; 190*35379Skfall break; 191*35379Skfall 192*35379Skfall case ETHERTYPE_ARP: 193*35379Skfall arpinput((struct arpcom *)ifp, m); 194*35379Skfall return; 195*35379Skfall #endif 196*35379Skfall #ifdef NS 197*35379Skfall case ETHERTYPE_NS: 198*35379Skfall schednetisr(NETISR_NS); 199*35379Skfall inq = &nsintrq; 200*35379Skfall break; 201*35379Skfall 202*35379Skfall #endif 203*35379Skfall default: 204*35379Skfall m_freem(m); 205*35379Skfall return; 206*35379Skfall } 207*35379Skfall 208*35379Skfall s = splimp(); 209*35379Skfall if (IF_QFULL(inq)) { 210*35379Skfall IF_DROP(inq); 211*35379Skfall m_freem(m); 212*35379Skfall } else 213*35379Skfall IF_ENQUEUE(inq, m); 214*35379Skfall splx(s); 215*35379Skfall } 216*35379Skfall 217*35379Skfall /* 218*35379Skfall * Convert Ethernet address to printable (loggable) representation. 219*35379Skfall */ 220*35379Skfall char * 221*35379Skfall ether_sprintf(ap) 222*35379Skfall register u_char *ap; 223*35379Skfall { 224*35379Skfall register i; 225*35379Skfall static char etherbuf[18]; 226*35379Skfall register char *cp = etherbuf; 227*35379Skfall static char digits[] = "0123456789abcdef"; 228*35379Skfall 229*35379Skfall for (i = 0; i < 6; i++) { 230*35379Skfall *cp++ = digits[*ap >> 4]; 231*35379Skfall *cp++ = digits[*ap++ & 0xf]; 232*35379Skfall *cp++ = ':'; 233*35379Skfall } 234*35379Skfall *--cp = 0; 235*35379Skfall return (etherbuf); 236*35379Skfall } 237