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