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