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