1 /* $NetBSD: if_arcsubr.c,v 1.11 1996/10/13 02:10:58 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1994, 1995 Ignatios Souvatzis 5 * Copyright (c) 1982, 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp 37 * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 38 * 39 */ 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/malloc.h> 45 #include <sys/mbuf.h> 46 #include <sys/protosw.h> 47 #include <sys/socket.h> 48 #include <sys/ioctl.h> 49 #include <sys/errno.h> 50 #include <sys/syslog.h> 51 52 #include <machine/cpu.h> 53 54 #include <net/if.h> 55 #include <net/netisr.h> 56 #include <net/route.h> 57 #include <net/if_dl.h> 58 #include <net/if_types.h> 59 60 #ifdef INET 61 #include <netinet/in.h> 62 #include <netinet/in_var.h> 63 #endif 64 #include <netinet/if_arc.h> 65 66 #ifndef ARC_PHDSMTU 67 #define ARC_PHDSMTU 1500 68 #endif 69 70 static struct mbuf *arc_defrag __P((struct ifnet *, struct mbuf *)); 71 72 /* 73 * RC1201 requires us to have this configurable. We have it only per 74 * machine at the moment... there is no generic "set mtu" ioctl, AFAICS. 75 * Anyway, it is possible to binpatch this or set it per kernel config 76 * option. 77 */ 78 #if ARC_PHDSMTU > 60480 79 ERROR: The arc_phdsmtu is ARC_PHDSMTU, but must not exceed 60480. 80 #endif 81 u_int16_t arc_phdsmtu = ARC_PHDSMTU; 82 u_int8_t arcbroadcastaddr = 0; 83 84 #define senderr(e) { error = (e); goto bad;} 85 #define SIN(s) ((struct sockaddr_in *)s) 86 87 /* 88 * ARCnet output routine. 89 * Encapsulate a packet of type family for the local net. 90 * Assumes that ifp is actually pointer to arccom structure. 91 */ 92 int 93 arc_output(ifp, m0, dst, rt0) 94 register struct ifnet *ifp; 95 struct mbuf *m0; 96 struct sockaddr *dst; 97 struct rtentry *rt0; 98 { 99 struct mbuf *m, *m1, *mcopy; 100 struct rtentry *rt; 101 struct arccom *ac; 102 register struct arc_header *ah; 103 int s, error, newencoding; 104 u_int8_t atype, adst; 105 int tfrags, sflag, fsflag, rsflag; 106 107 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 108 return(ENETDOWN); /* m, m1 aren't initialized yet */ 109 110 error = newencoding = 0; 111 ac = (struct arccom *)ifp; 112 m = m0; 113 mcopy = m1 = NULL; 114 115 ifp->if_lastchange = time; 116 if ((rt = rt0)) { 117 if ((rt->rt_flags & RTF_UP) == 0) { 118 if ((rt0 = rt = rtalloc1(dst, 1))) 119 rt->rt_refcnt--; 120 else 121 senderr(EHOSTUNREACH); 122 } 123 if (rt->rt_flags & RTF_GATEWAY) { 124 if (rt->rt_gwroute == 0) 125 goto lookup; 126 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 127 rtfree(rt); rt = rt0; 128 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); 129 if ((rt = rt->rt_gwroute) == 0) 130 senderr(EHOSTUNREACH); 131 } 132 } 133 if (rt->rt_flags & RTF_REJECT) 134 if (rt->rt_rmx.rmx_expire == 0 || 135 time.tv_sec < rt->rt_rmx.rmx_expire) 136 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 137 } 138 139 switch (dst->sa_family) { 140 #ifdef INET 141 case AF_INET: 142 143 /* 144 * For now, use the simple IP addr -> ARCnet addr mapping 145 */ 146 if (m->m_flags & (M_BCAST|M_MCAST)) 147 adst = arcbroadcastaddr; /* ARCnet broadcast address */ 148 else 149 adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF; 150 151 /* If broadcasting on a simplex interface, loopback a copy */ 152 if ((m->m_flags & (M_BCAST|M_MCAST)) && 153 (ifp->if_flags & IFF_SIMPLEX)) 154 mcopy = m_copy(m, 0, (int)M_COPYALL); 155 if (ifp->if_flags & IFF_LINK0) { 156 atype = ARCTYPE_IP; 157 newencoding = 1; 158 } else { 159 atype = ARCTYPE_IP_OLD; 160 newencoding = 0; 161 } 162 break; 163 #endif 164 165 case AF_UNSPEC: 166 ah = (struct arc_header *)dst->sa_data; 167 adst = ah->arc_dhost; 168 atype = ah->arc_type; 169 break; 170 171 default: 172 printf("%s: can't handle af%d\n", ifp->if_xname, 173 dst->sa_family); 174 senderr(EAFNOSUPPORT); 175 } 176 177 if (mcopy) 178 (void) looutput(ifp, mcopy, dst, rt); 179 180 /* 181 * Add local net header. If no space in first mbuf, 182 * allocate another. 183 * 184 * For ARCnet, this is just symbolic. The header changes 185 * form and position on its way into the hardware and out of 186 * the wire. At this point, it contains source, destination and 187 * packet type. 188 */ 189 if (newencoding) { 190 ++ac->ac_seqid; /* make the seqid unique */ 191 192 tfrags = (m->m_pkthdr.len + 503) / 504; 193 fsflag = 2 * tfrags - 3; 194 sflag = 0; 195 rsflag = fsflag; 196 197 while (sflag < fsflag) { 198 /* we CAN'T have short packets here */ 199 m1 = m_split(m, 504, M_DONTWAIT); 200 if (m1 == 0) 201 senderr(ENOBUFS); 202 203 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT); 204 if (m == 0) 205 senderr(ENOBUFS); 206 ah = mtod(m, struct arc_header *); 207 ah->arc_type = atype; 208 ah->arc_dhost = adst; 209 ah->arc_shost = ac->ac_anaddr; 210 ah->arc_flag = rsflag; 211 ah->arc_seqid = ac->ac_seqid; 212 213 s = splimp(); 214 /* 215 * Queue message on interface, and start output if 216 * interface not yet active. 217 */ 218 if (IF_QFULL(&ifp->if_snd)) { 219 IF_DROP(&ifp->if_snd); 220 splx(s); 221 senderr(ENOBUFS); 222 } 223 ifp->if_obytes += m->m_pkthdr.len; 224 IF_ENQUEUE(&ifp->if_snd, m); 225 if ((ifp->if_flags & IFF_OACTIVE) == 0) 226 (*ifp->if_start)(ifp); 227 splx(s); 228 229 m = m1; 230 sflag += 2; 231 rsflag = sflag; 232 } 233 m1 = NULL; 234 235 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT); 236 if (m == 0) 237 senderr(ENOBUFS); 238 ah = mtod(m, struct arc_header *); 239 ah->arc_type = atype; 240 ah->arc_flag = sflag; 241 ah->arc_seqid = ac->ac_seqid; 242 243 /* here we can have small, especially forbidden packets */ 244 245 if ((m->m_pkthdr.len >= ARC_MIN_FORBID_LEN + 2) && 246 (m->m_pkthdr.len <= ARC_MAX_FORBID_LEN + 2)) { 247 M_PREPEND(m, 4, M_DONTWAIT); 248 if (m == 0) 249 senderr(ENOBUFS); 250 m = m_pullup(m, ARC_HDRNEWLEN); 251 if (m == 0) 252 senderr(ENOBUFS); 253 ah = mtod(m, struct arc_header *); 254 ah->arc_type = atype; 255 ah->arc_flag = 0xFF; 256 ah->arc_seqid = 0xFFFF; 257 } 258 259 ah->arc_dhost = adst; 260 ah->arc_shost = ac->ac_anaddr; 261 } else { 262 M_PREPEND(m, ARC_HDRLEN, M_DONTWAIT); 263 if (m == 0) 264 senderr(ENOBUFS); 265 ah = mtod(m, struct arc_header *); 266 ah->arc_type = atype; 267 ah->arc_dhost = adst; 268 ah->arc_shost = ac->ac_anaddr; 269 } 270 271 s = splimp(); 272 /* 273 * Queue message on interface, and start output if interface 274 * not yet active. 275 */ 276 if (IF_QFULL(&ifp->if_snd)) { 277 IF_DROP(&ifp->if_snd); 278 splx(s); 279 senderr(ENOBUFS); 280 } 281 ifp->if_obytes += m->m_pkthdr.len; 282 IF_ENQUEUE(&ifp->if_snd, m); 283 if ((ifp->if_flags & IFF_OACTIVE) == 0) 284 (*ifp->if_start)(ifp); 285 splx(s); 286 287 return (error); 288 289 bad: 290 if (m1) 291 m_freem(m1); 292 if (m) 293 m_freem(m); 294 return (error); 295 } 296 297 /* 298 * Defragmenter. Returns mbuf if last packet found, else 299 * NULL. frees imcoming mbuf as necessary. 300 */ 301 302 __inline struct mbuf * 303 arc_defrag(ifp, m) 304 struct ifnet *ifp; 305 struct mbuf *m; 306 { 307 struct arc_header *ah, *ah1; 308 struct arccom *ac; 309 struct ac_frag *af; 310 struct mbuf *m1; 311 char *s; 312 int newflen; 313 u_char src,dst,typ; 314 315 ac = (struct arccom *)ifp; 316 317 m = m_pullup(m, ARC_HDRNEWLEN); 318 if (m == NULL) { 319 ++ifp->if_ierrors; 320 return NULL; 321 } 322 323 ah = mtod(m, struct arc_header *); 324 typ = ah->arc_type; 325 326 if (!arc_isphds(typ)) 327 return m; 328 329 src = ah->arc_shost; 330 dst = ah->arc_dhost; 331 332 if (ah->arc_flag == 0xff) { 333 m_adj(m, 4); 334 335 m = m_pullup(m, ARC_HDRNEWLEN); 336 if (m == NULL) { 337 ++ifp->if_ierrors; 338 return NULL; 339 } 340 341 ah = mtod(m, struct arc_header *); 342 ah->arc_shost = src; 343 ah->arc_dhost = dst; 344 ah->arc_type = typ; 345 } 346 347 af = &ac->ac_fragtab[src]; 348 m1 = af->af_packet; 349 s = "debug code error"; 350 351 if (ah->arc_flag & 1) { 352 /* 353 * first fragment. We always initialize, which is 354 * about the right thing to do, as we only want to 355 * accept one fragmented packet per src at a time. 356 */ 357 if (m1 != NULL) 358 m_freem(m1); 359 360 af->af_packet = m; 361 m1 = m; 362 af->af_maxflag = ah->arc_flag; 363 af->af_lastseen = 0; 364 af->af_seqid = ah->arc_seqid; 365 366 return NULL; 367 /* notreached */ 368 } else { 369 /* check for unfragmented packet */ 370 if (ah->arc_flag == 0) 371 return m; 372 373 /* do we have a first packet from that src? */ 374 if (m1 == NULL) { 375 s = "no first frag"; 376 goto outofseq; 377 } 378 379 ah1 = mtod(m1, struct arc_header *); 380 381 if (ah->arc_seqid != ah1->arc_seqid) { 382 s = "seqid differs"; 383 goto outofseq; 384 } 385 386 if (ah->arc_type != ah1->arc_type) { 387 s = "type differs"; 388 goto outofseq; 389 } 390 391 if (ah->arc_dhost != ah1->arc_dhost) { 392 s = "dest host differs"; 393 goto outofseq; 394 } 395 396 /* typ, seqid and dst are ok here. */ 397 398 if (ah->arc_flag == af->af_lastseen) { 399 m_freem(m); 400 return NULL; 401 } 402 403 if (ah->arc_flag == af->af_lastseen + 2) { 404 /* ok, this is next fragment */ 405 af->af_lastseen = ah->arc_flag; 406 m_adj(m,ARC_HDRNEWLEN); 407 408 /* 409 * m_cat might free the first mbuf (with pkthdr) 410 * in 2nd chain; therefore: 411 */ 412 413 newflen = m->m_pkthdr.len; 414 415 m_cat(m1,m); 416 417 m1->m_pkthdr.len += newflen; 418 419 /* is it the last one? */ 420 if (af->af_lastseen > af->af_maxflag) { 421 af->af_packet = NULL; 422 return(m1); 423 } else 424 return NULL; 425 } 426 s = "other reason"; 427 /* if all else fails, it is out of sequence, too */ 428 } 429 outofseq: 430 if (m1) { 431 m_freem(m1); 432 af->af_packet = NULL; 433 } 434 435 if (m) 436 m_freem(m); 437 438 log(LOG_INFO,"%s: got out of seq. packet: %s\n", 439 ifp->if_xname, s); 440 441 return NULL; 442 } 443 444 /* 445 * return 1 if Packet Header Definition Standard, else 0. 446 * For now: old IP, old ARP aren't obviously. Lacking correct information, 447 * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS. 448 * (Apple and Novell corporations were involved, among others, in PHDS work). 449 * Easiest is to assume that everybody else uses that, too. 450 */ 451 int 452 arc_isphds(type) 453 u_int8_t type; 454 { 455 return ((type != ARCTYPE_IP_OLD && 456 type != ARCTYPE_ARP_OLD)); 457 } 458 459 /* 460 * Process a received Arcnet packet; 461 * the packet is in the mbuf chain m with 462 * the ARCnet header. 463 */ 464 void 465 arc_input(ifp, m) 466 struct ifnet *ifp; 467 struct mbuf *m; 468 { 469 register struct arc_header *ah; 470 register struct ifqueue *inq; 471 u_int8_t atype; 472 int s; 473 474 if ((ifp->if_flags & IFF_UP) == 0) { 475 m_freem(m); 476 return; 477 } 478 479 /* possibly defragment: */ 480 m = arc_defrag(ifp, m); 481 if (m == NULL) 482 return; 483 484 ah = mtod(m, struct arc_header *); 485 486 ifp->if_lastchange = time; 487 ifp->if_ibytes += m->m_pkthdr.len; 488 489 if (arcbroadcastaddr == ah->arc_dhost) { 490 m->m_flags |= M_BCAST|M_MCAST; 491 ifp->if_imcasts++; 492 } 493 494 atype = ah->arc_type; 495 switch (atype) { 496 #ifdef INET 497 case ARCTYPE_IP: 498 m_adj(m, ARC_HDRNEWLEN); 499 schednetisr(NETISR_IP); 500 inq = &ipintrq; 501 break; 502 503 case ARCTYPE_IP_OLD: 504 m_adj(m, ARC_HDRLEN); 505 schednetisr(NETISR_IP); 506 inq = &ipintrq; 507 break; 508 #endif 509 default: 510 m_freem(m); 511 return; 512 } 513 514 s = splimp(); 515 if (IF_QFULL(inq)) { 516 IF_DROP(inq); 517 m_freem(m); 518 } else 519 IF_ENQUEUE(inq, m); 520 splx(s); 521 } 522 523 /* 524 * Convert Arcnet address to printable (loggable) representation. 525 */ 526 static char digits[] = "0123456789abcdef"; 527 char * 528 arc_sprintf(ap) 529 register u_int8_t *ap; 530 { 531 static char arcbuf[3]; 532 register char *cp = arcbuf; 533 534 *cp++ = digits[*ap >> 4]; 535 *cp++ = digits[*ap++ & 0xf]; 536 *cp = 0; 537 return (arcbuf); 538 } 539 540 /* 541 * Perform common duties while attaching to interface list 542 */ 543 void 544 arc_ifattach(ifp) 545 register struct ifnet *ifp; 546 { 547 register struct ifaddr *ifa; 548 register struct sockaddr_dl *sdl; 549 register struct arccom *ac; 550 551 ifp->if_type = IFT_ARCNET; 552 ifp->if_addrlen = 1; 553 ifp->if_hdrlen = ARC_HDRLEN; 554 if (ifp->if_flags & IFF_BROADCAST) 555 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI; 556 if (ifp->if_flags & IFF_LINK0 && arc_phdsmtu > 60480) 557 log(LOG_ERR, 558 "%s: arc_phdsmtu is %d, but must not exceed 60480", 559 ifp->if_xname, arc_phdsmtu); 560 561 ifp->if_mtu = (ifp->if_flags & IFF_LINK0 ? arc_phdsmtu : ARCMTU); 562 ac = (struct arccom *)ifp; 563 ac->ac_seqid = (time.tv_sec) & 0xFFFF; /* try to make seqid unique */ 564 if (ac->ac_anaddr == 0) { 565 /* XXX this message isn't entirely clear, to me -- cgd */ 566 log(LOG_ERR,"%s: link address 0 reserved for broadcasts. Please change it and ifconfig %s down up\n", 567 ifp->if_xname, ifp->if_xname); 568 } 569 for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; 570 ifa = ifa->ifa_list.tqe_next) 571 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) && 572 sdl->sdl_family == AF_LINK) { 573 sdl->sdl_type = IFT_ARCNET; 574 sdl->sdl_alen = ifp->if_addrlen; 575 bcopy((caddr_t)&((struct arccom *)ifp)->ac_anaddr, 576 LLADDR(sdl), ifp->if_addrlen); 577 break; 578 } 579 } 580