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