if_arcsubr.c revision 184680
1/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */ 2/* $FreeBSD: head/sys/net/if_arcsubr.c 184680 2008-11-05 11:43:01Z bz $ */ 3 4/*- 5 * Copyright (c) 1994, 1995 Ignatios Souvatzis 6 * Copyright (c) 1982, 1989, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp 38 * @(#)if_ethersubr.c 8.1 (Berkeley) 6/10/93 39 * 40 */ 41#include "opt_inet.h" 42#include "opt_inet6.h" 43#include "opt_ipx.h" 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/kernel.h> 48#include <sys/module.h> 49#include <sys/malloc.h> 50#include <sys/mbuf.h> 51#include <sys/protosw.h> 52#include <sys/socket.h> 53#include <sys/sockio.h> 54#include <sys/errno.h> 55#include <sys/syslog.h> 56 57#include <machine/cpu.h> 58 59#include <net/if.h> 60#include <net/netisr.h> 61#include <net/route.h> 62#include <net/if_dl.h> 63#include <net/if_types.h> 64#include <net/if_arc.h> 65#include <net/if_arp.h> 66#include <net/bpf.h> 67 68#if defined(INET) || defined(INET6) 69#include <netinet/in.h> 70#include <netinet/in_var.h> 71#include <netinet/if_ether.h> 72#endif 73 74#ifdef INET6 75#include <netinet6/nd6.h> 76#endif 77 78#ifdef IPX 79#include <netipx/ipx.h> 80#include <netipx/ipx_if.h> 81#endif 82 83#define ARCNET_ALLOW_BROKEN_ARP 84 85static struct mbuf *arc_defrag(struct ifnet *, struct mbuf *); 86static int arc_resolvemulti(struct ifnet *, struct sockaddr **, 87 struct sockaddr *); 88 89u_int8_t arcbroadcastaddr = 0; 90 91#define ARC_LLADDR(ifp) (*(u_int8_t *)IF_LLADDR(ifp)) 92 93#define senderr(e) { error = (e); goto bad;} 94#define SIN(s) ((struct sockaddr_in *)s) 95#define SIPX(s) ((struct sockaddr_ipx *)s) 96 97/* 98 * ARCnet output routine. 99 * Encapsulate a packet of type family for the local net. 100 * Assumes that ifp is actually pointer to arccom structure. 101 */ 102int 103arc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 104 struct rtentry *rt0) 105{ 106 struct arc_header *ah; 107 int error; 108 u_int8_t atype, adst; 109 int loop_copy = 0; 110 int isphds; 111 112 if (!((ifp->if_flags & IFF_UP) && 113 (ifp->if_drv_flags & IFF_DRV_RUNNING))) 114 return(ENETDOWN); /* m, m1 aren't initialized yet */ 115 116 error = 0; 117 118 switch (dst->sa_family) { 119#ifdef INET 120 case AF_INET: 121 122 /* 123 * For now, use the simple IP addr -> ARCnet addr mapping 124 */ 125 if (m->m_flags & (M_BCAST|M_MCAST)) 126 adst = arcbroadcastaddr; /* ARCnet broadcast address */ 127 else if (ifp->if_flags & IFF_NOARP) 128 adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF; 129 else { 130 error = arpresolve(ifp, rt0, m, dst, &adst); 131 if (error) 132 return (error == EWOULDBLOCK ? 0 : error); 133 } 134 135 atype = (ifp->if_flags & IFF_LINK0) ? 136 ARCTYPE_IP_OLD : ARCTYPE_IP; 137 break; 138 case AF_ARP: 139 { 140 struct arphdr *ah; 141 ah = mtod(m, struct arphdr *); 142 ah->ar_hrd = htons(ARPHRD_ARCNET); 143 144 loop_copy = -1; /* if this is for us, don't do it */ 145 146 switch(ntohs(ah->ar_op)) { 147 case ARPOP_REVREQUEST: 148 case ARPOP_REVREPLY: 149 atype = ARCTYPE_REVARP; 150 break; 151 case ARPOP_REQUEST: 152 case ARPOP_REPLY: 153 default: 154 atype = ARCTYPE_ARP; 155 break; 156 } 157 158 if (m->m_flags & M_BCAST) 159 bcopy(ifp->if_broadcastaddr, &adst, ARC_ADDR_LEN); 160 else 161 bcopy(ar_tha(ah), &adst, ARC_ADDR_LEN); 162 163 } 164 break; 165#endif 166#ifdef INET6 167 case AF_INET6: 168 error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)&adst); 169 if (error) 170 return (error); 171 atype = ARCTYPE_INET6; 172 break; 173#endif 174#ifdef IPX 175 case AF_IPX: 176 adst = SIPX(dst)->sipx_addr.x_host.c_host[5]; 177 atype = ARCTYPE_IPX; 178 if (adst == 0xff) 179 adst = arcbroadcastaddr; 180 break; 181#endif 182 183 case AF_UNSPEC: 184 loop_copy = -1; 185 ah = (struct arc_header *)dst->sa_data; 186 adst = ah->arc_dhost; 187 atype = ah->arc_type; 188 189 if (atype == ARCTYPE_ARP) { 190 atype = (ifp->if_flags & IFF_LINK0) ? 191 ARCTYPE_ARP_OLD: ARCTYPE_ARP; 192 193#ifdef ARCNET_ALLOW_BROKEN_ARP 194 /* 195 * XXX It's not clear per RFC826 if this is needed, but 196 * "assigned numbers" say this is wrong. 197 * However, e.g., AmiTCP 3.0Beta used it... we make this 198 * switchable for emergency cases. Not perfect, but... 199 */ 200 if (ifp->if_flags & IFF_LINK2) 201 mtod(m, struct arphdr *)->ar_pro = atype - 1; 202#endif 203 } 204 break; 205 206 default: 207 if_printf(ifp, "can't handle af%d\n", dst->sa_family); 208 senderr(EAFNOSUPPORT); 209 } 210 211 isphds = arc_isphds(atype); 212 M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_DONTWAIT); 213 if (m == 0) 214 senderr(ENOBUFS); 215 ah = mtod(m, struct arc_header *); 216 ah->arc_type = atype; 217 ah->arc_dhost = adst; 218 ah->arc_shost = ARC_LLADDR(ifp); 219 if (isphds) { 220 ah->arc_flag = 0; 221 ah->arc_seqid = 0; 222 } 223 224 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 225 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 226 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 227 228 (void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN); 229 } else if (ah->arc_dhost == ah->arc_shost) { 230 (void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN); 231 return (0); /* XXX */ 232 } 233 } 234 235 BPF_MTAP(ifp, m); 236 237 IFQ_HANDOFF(ifp, m, error); 238 239 return (error); 240 241bad: 242 if (m) 243 m_freem(m); 244 return (error); 245} 246 247void 248arc_frag_init(struct ifnet *ifp) 249{ 250 struct arccom *ac; 251 252 ac = (struct arccom *)ifp->if_l2com; 253 ac->curr_frag = 0; 254} 255 256struct mbuf * 257arc_frag_next(struct ifnet *ifp) 258{ 259 struct arccom *ac; 260 struct mbuf *m; 261 struct arc_header *ah; 262 263 ac = (struct arccom *)ifp->if_l2com; 264 if ((m = ac->curr_frag) == 0) { 265 int tfrags; 266 267 /* dequeue new packet */ 268 IF_DEQUEUE(&ifp->if_snd, m); 269 if (m == 0) 270 return 0; 271 272 ah = mtod(m, struct arc_header *); 273 if (!arc_isphds(ah->arc_type)) 274 return m; 275 276 ++ac->ac_seqid; /* make the seqid unique */ 277 tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA; 278 ac->fsflag = 2 * tfrags - 3; 279 ac->sflag = 0; 280 ac->rsflag = ac->fsflag; 281 ac->arc_dhost = ah->arc_dhost; 282 ac->arc_shost = ah->arc_shost; 283 ac->arc_type = ah->arc_type; 284 285 m_adj(m, ARC_HDRNEWLEN); 286 ac->curr_frag = m; 287 } 288 289 /* split out next fragment and return it */ 290 if (ac->sflag < ac->fsflag) { 291 /* we CAN'T have short packets here */ 292 ac->curr_frag = m_split(m, ARC_MAX_DATA, M_DONTWAIT); 293 if (ac->curr_frag == 0) { 294 m_freem(m); 295 return 0; 296 } 297 298 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT); 299 if (m == 0) { 300 m_freem(ac->curr_frag); 301 ac->curr_frag = 0; 302 return 0; 303 } 304 305 ah = mtod(m, struct arc_header *); 306 ah->arc_flag = ac->rsflag; 307 ah->arc_seqid = ac->ac_seqid; 308 309 ac->sflag += 2; 310 ac->rsflag = ac->sflag; 311 } else if ((m->m_pkthdr.len >= 312 ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) && 313 (m->m_pkthdr.len <= 314 ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) { 315 ac->curr_frag = 0; 316 317 M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_DONTWAIT); 318 if (m == 0) 319 return 0; 320 321 ah = mtod(m, struct arc_header *); 322 ah->arc_flag = 0xFF; 323 ah->arc_seqid = 0xFFFF; 324 ah->arc_type2 = ac->arc_type; 325 ah->arc_flag2 = ac->sflag; 326 ah->arc_seqid2 = ac->ac_seqid; 327 } else { 328 ac->curr_frag = 0; 329 330 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT); 331 if (m == 0) 332 return 0; 333 334 ah = mtod(m, struct arc_header *); 335 ah->arc_flag = ac->sflag; 336 ah->arc_seqid = ac->ac_seqid; 337 } 338 339 ah->arc_dhost = ac->arc_dhost; 340 ah->arc_shost = ac->arc_shost; 341 ah->arc_type = ac->arc_type; 342 343 return m; 344} 345 346/* 347 * Defragmenter. Returns mbuf if last packet found, else 348 * NULL. frees imcoming mbuf as necessary. 349 */ 350 351static __inline struct mbuf * 352arc_defrag(struct ifnet *ifp, struct mbuf *m) 353{ 354 struct arc_header *ah, *ah1; 355 struct arccom *ac; 356 struct ac_frag *af; 357 struct mbuf *m1; 358 char *s; 359 int newflen; 360 u_char src,dst,typ; 361 362 ac = (struct arccom *)ifp->if_l2com; 363 364 if (m->m_len < ARC_HDRNEWLEN) { 365 m = m_pullup(m, ARC_HDRNEWLEN); 366 if (m == NULL) { 367 ++ifp->if_ierrors; 368 return NULL; 369 } 370 } 371 372 ah = mtod(m, struct arc_header *); 373 typ = ah->arc_type; 374 375 if (!arc_isphds(typ)) 376 return m; 377 378 src = ah->arc_shost; 379 dst = ah->arc_dhost; 380 381 if (ah->arc_flag == 0xff) { 382 m_adj(m, 4); 383 384 if (m->m_len < ARC_HDRNEWLEN) { 385 m = m_pullup(m, ARC_HDRNEWLEN); 386 if (m == NULL) { 387 ++ifp->if_ierrors; 388 return NULL; 389 } 390 } 391 392 ah = mtod(m, struct arc_header *); 393 } 394 395 af = &ac->ac_fragtab[src]; 396 m1 = af->af_packet; 397 s = "debug code error"; 398 399 if (ah->arc_flag & 1) { 400 /* 401 * first fragment. We always initialize, which is 402 * about the right thing to do, as we only want to 403 * accept one fragmented packet per src at a time. 404 */ 405 if (m1 != NULL) 406 m_freem(m1); 407 408 af->af_packet = m; 409 m1 = m; 410 af->af_maxflag = ah->arc_flag; 411 af->af_lastseen = 0; 412 af->af_seqid = ah->arc_seqid; 413 414 return NULL; 415 /* notreached */ 416 } else { 417 /* check for unfragmented packet */ 418 if (ah->arc_flag == 0) 419 return m; 420 421 /* do we have a first packet from that src? */ 422 if (m1 == NULL) { 423 s = "no first frag"; 424 goto outofseq; 425 } 426 427 ah1 = mtod(m1, struct arc_header *); 428 429 if (ah->arc_seqid != ah1->arc_seqid) { 430 s = "seqid differs"; 431 goto outofseq; 432 } 433 434 if (typ != ah1->arc_type) { 435 s = "type differs"; 436 goto outofseq; 437 } 438 439 if (dst != ah1->arc_dhost) { 440 s = "dest host differs"; 441 goto outofseq; 442 } 443 444 /* typ, seqid and dst are ok here. */ 445 446 if (ah->arc_flag == af->af_lastseen) { 447 m_freem(m); 448 return NULL; 449 } 450 451 if (ah->arc_flag == af->af_lastseen + 2) { 452 /* ok, this is next fragment */ 453 af->af_lastseen = ah->arc_flag; 454 m_adj(m,ARC_HDRNEWLEN); 455 456 /* 457 * m_cat might free the first mbuf (with pkthdr) 458 * in 2nd chain; therefore: 459 */ 460 461 newflen = m->m_pkthdr.len; 462 463 m_cat(m1,m); 464 465 m1->m_pkthdr.len += newflen; 466 467 /* is it the last one? */ 468 if (af->af_lastseen > af->af_maxflag) { 469 af->af_packet = NULL; 470 return(m1); 471 } else 472 return NULL; 473 } 474 s = "other reason"; 475 /* if all else fails, it is out of sequence, too */ 476 } 477outofseq: 478 if (m1) { 479 m_freem(m1); 480 af->af_packet = NULL; 481 } 482 483 if (m) 484 m_freem(m); 485 486 log(LOG_INFO,"%s: got out of seq. packet: %s\n", 487 ifp->if_xname, s); 488 489 return NULL; 490} 491 492/* 493 * return 1 if Packet Header Definition Standard, else 0. 494 * For now: old IP, old ARP aren't obviously. Lacking correct information, 495 * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS. 496 * (Apple and Novell corporations were involved, among others, in PHDS work). 497 * Easiest is to assume that everybody else uses that, too. 498 */ 499int 500arc_isphds(u_int8_t type) 501{ 502 return (type != ARCTYPE_IP_OLD && 503 type != ARCTYPE_ARP_OLD && 504 type != ARCTYPE_DIAGNOSE); 505} 506 507/* 508 * Process a received Arcnet packet; 509 * the packet is in the mbuf chain m with 510 * the ARCnet header. 511 */ 512void 513arc_input(struct ifnet *ifp, struct mbuf *m) 514{ 515 struct arc_header *ah; 516 int isr; 517 u_int8_t atype; 518 519 if ((ifp->if_flags & IFF_UP) == 0) { 520 m_freem(m); 521 return; 522 } 523 524 /* possibly defragment: */ 525 m = arc_defrag(ifp, m); 526 if (m == NULL) 527 return; 528 529 BPF_MTAP(ifp, m); 530 531 ah = mtod(m, struct arc_header *); 532 /* does this belong to us? */ 533 if ((ifp->if_flags & IFF_PROMISC) == 0 534 && ah->arc_dhost != arcbroadcastaddr 535 && ah->arc_dhost != ARC_LLADDR(ifp)) { 536 m_freem(m); 537 return; 538 } 539 540 ifp->if_ibytes += m->m_pkthdr.len; 541 542 if (ah->arc_dhost == arcbroadcastaddr) { 543 m->m_flags |= M_BCAST|M_MCAST; 544 ifp->if_imcasts++; 545 } 546 547 atype = ah->arc_type; 548 switch (atype) { 549#ifdef INET 550 case ARCTYPE_IP: 551 m_adj(m, ARC_HDRNEWLEN); 552 if ((m = ip_fastforward(m)) == NULL) 553 return; 554 isr = NETISR_IP; 555 break; 556 557 case ARCTYPE_IP_OLD: 558 m_adj(m, ARC_HDRLEN); 559 if ((m = ip_fastforward(m)) == NULL) 560 return; 561 isr = NETISR_IP; 562 break; 563 564 case ARCTYPE_ARP: 565 if (ifp->if_flags & IFF_NOARP) { 566 /* Discard packet if ARP is disabled on interface */ 567 m_freem(m); 568 return; 569 } 570 m_adj(m, ARC_HDRNEWLEN); 571 isr = NETISR_ARP; 572#ifdef ARCNET_ALLOW_BROKEN_ARP 573 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 574#endif 575 break; 576 577 case ARCTYPE_ARP_OLD: 578 if (ifp->if_flags & IFF_NOARP) { 579 /* Discard packet if ARP is disabled on interface */ 580 m_freem(m); 581 return; 582 } 583 m_adj(m, ARC_HDRLEN); 584 isr = NETISR_ARP; 585#ifdef ARCNET_ALLOW_BROKEN_ARP 586 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 587#endif 588 break; 589#endif 590#ifdef INET6 591 case ARCTYPE_INET6: 592 m_adj(m, ARC_HDRNEWLEN); 593 isr = NETISR_IPV6; 594 break; 595#endif 596#ifdef IPX 597 case ARCTYPE_IPX: 598 m_adj(m, ARC_HDRNEWLEN); 599 isr = NETISR_IPX; 600 break; 601#endif 602 default: 603 m_freem(m); 604 return; 605 } 606 netisr_dispatch(isr, m); 607} 608 609/* 610 * Register (new) link level address. 611 */ 612void 613arc_storelladdr(struct ifnet *ifp, u_int8_t lla) 614{ 615 ARC_LLADDR(ifp) = lla; 616} 617 618/* 619 * Perform common duties while attaching to interface list 620 */ 621void 622arc_ifattach(struct ifnet *ifp, u_int8_t lla) 623{ 624 struct ifaddr *ifa; 625 struct sockaddr_dl *sdl; 626 struct arccom *ac; 627 628 if_attach(ifp); 629 ifp->if_addrlen = 1; 630 ifp->if_hdrlen = ARC_HDRLEN; 631 ifp->if_mtu = 1500; 632 ifp->if_resolvemulti = arc_resolvemulti; 633 if (ifp->if_baudrate == 0) 634 ifp->if_baudrate = 2500000; 635#if __FreeBSD_version < 500000 636 ifa = ifnet_addrs[ifp->if_index - 1]; 637#else 638 ifa = ifp->if_addr; 639#endif 640 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 641 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 642 sdl->sdl_type = IFT_ARCNET; 643 sdl->sdl_alen = ifp->if_addrlen; 644 645 if (ifp->if_flags & IFF_BROADCAST) 646 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI; 647 648 ac = (struct arccom *)ifp->if_l2com; 649 ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */ 650 if (lla == 0) { 651 /* XXX this message isn't entirely clear, to me -- cgd */ 652 log(LOG_ERR,"%s: link address 0 reserved for broadcasts. Please change it and ifconfig %s down up\n", 653 ifp->if_xname, ifp->if_xname); 654 } 655 arc_storelladdr(ifp, lla); 656 657 ifp->if_broadcastaddr = &arcbroadcastaddr; 658 659 bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN); 660} 661 662void 663arc_ifdetach(struct ifnet *ifp) 664{ 665 bpfdetach(ifp); 666 if_detach(ifp); 667} 668 669int 670arc_ioctl(struct ifnet *ifp, int command, caddr_t data) 671{ 672 struct ifaddr *ifa = (struct ifaddr *) data; 673 struct ifreq *ifr = (struct ifreq *) data; 674 int error = 0; 675 676 switch (command) { 677 case SIOCSIFADDR: 678 ifp->if_flags |= IFF_UP; 679 switch (ifa->ifa_addr->sa_family) { 680#ifdef INET 681 case AF_INET: 682 ifp->if_init(ifp->if_softc); /* before arpwhohas */ 683 arp_ifinit(ifp, ifa); 684 break; 685#endif 686#ifdef IPX 687 /* 688 * XXX This code is probably wrong 689 */ 690 case AF_IPX: 691 { 692 struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 693 694 if (ipx_nullhost(*ina)) 695 ina->x_host.c_host[5] = ARC_LLADDR(ifp); 696 else 697 arc_storelladdr(ifp, ina->x_host.c_host[5]); 698 699 /* 700 * Set new address 701 */ 702 ifp->if_init(ifp->if_softc); 703 break; 704 } 705#endif 706 default: 707 ifp->if_init(ifp->if_softc); 708 break; 709 } 710 break; 711 712 case SIOCGIFADDR: 713 { 714 struct sockaddr *sa; 715 716 sa = (struct sockaddr *) &ifr->ifr_data; 717 *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp); 718 } 719 break; 720 721 case SIOCADDMULTI: 722 case SIOCDELMULTI: 723 if (ifr == NULL) 724 error = EAFNOSUPPORT; 725 else { 726 switch (ifr->ifr_addr.sa_family) { 727 case AF_INET: 728 case AF_INET6: 729 error = 0; 730 break; 731 default: 732 error = EAFNOSUPPORT; 733 break; 734 } 735 } 736 break; 737 738 case SIOCSIFMTU: 739 /* 740 * Set the interface MTU. 741 * mtu can't be larger than ARCMTU for RFC1051 742 * and can't be larger than ARC_PHDS_MTU 743 */ 744 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) || 745 ifr->ifr_mtu > ARC_PHDS_MAXMTU) 746 error = EINVAL; 747 else 748 ifp->if_mtu = ifr->ifr_mtu; 749 break; 750 } 751 752 return (error); 753} 754 755/* based on ether_resolvemulti() */ 756int 757arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 758 struct sockaddr *sa) 759{ 760 struct sockaddr_dl *sdl; 761#ifdef INET 762 struct sockaddr_in *sin; 763#endif 764#ifdef INET6 765 struct sockaddr_in6 *sin6; 766#endif 767 768 switch(sa->sa_family) { 769 case AF_LINK: 770 /* 771 * No mapping needed. Just check that it's a valid MC address. 772 */ 773 sdl = (struct sockaddr_dl *)sa; 774 if (*LLADDR(sdl) != arcbroadcastaddr) 775 return EADDRNOTAVAIL; 776 *llsa = 0; 777 return 0; 778#ifdef INET 779 case AF_INET: 780 sin = (struct sockaddr_in *)sa; 781 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 782 return EADDRNOTAVAIL; 783 sdl = malloc(sizeof *sdl, M_IFMADDR, 784 M_NOWAIT | M_ZERO); 785 if (sdl == NULL) 786 return ENOMEM; 787 sdl->sdl_len = sizeof *sdl; 788 sdl->sdl_family = AF_LINK; 789 sdl->sdl_index = ifp->if_index; 790 sdl->sdl_type = IFT_ARCNET; 791 sdl->sdl_alen = ARC_ADDR_LEN; 792 *LLADDR(sdl) = 0; 793 *llsa = (struct sockaddr *)sdl; 794 return 0; 795#endif 796#ifdef INET6 797 case AF_INET6: 798 sin6 = (struct sockaddr_in6 *)sa; 799 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 800 /* 801 * An IP6 address of 0 means listen to all 802 * of the Ethernet multicast address used for IP6. 803 * (This is used for multicast routers.) 804 */ 805 ifp->if_flags |= IFF_ALLMULTI; 806 *llsa = 0; 807 return 0; 808 } 809 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 810 return EADDRNOTAVAIL; 811 sdl = malloc(sizeof *sdl, M_IFMADDR, 812 M_NOWAIT | M_ZERO); 813 if (sdl == NULL) 814 return ENOMEM; 815 sdl->sdl_len = sizeof *sdl; 816 sdl->sdl_family = AF_LINK; 817 sdl->sdl_index = ifp->if_index; 818 sdl->sdl_type = IFT_ARCNET; 819 sdl->sdl_alen = ARC_ADDR_LEN; 820 *LLADDR(sdl) = 0; 821 *llsa = (struct sockaddr *)sdl; 822 return 0; 823#endif 824 825 default: 826 /* 827 * Well, the text isn't quite right, but it's the name 828 * that counts... 829 */ 830 return EAFNOSUPPORT; 831 } 832} 833 834MALLOC_DEFINE(M_ARCCOM, "arccom", "ARCNET interface internals"); 835 836static void* 837arc_alloc(u_char type, struct ifnet *ifp) 838{ 839 struct arccom *ac; 840 841 ac = malloc(sizeof(struct arccom), M_ARCCOM, M_WAITOK | M_ZERO); 842 ac->ac_ifp = ifp; 843 844 return (ac); 845} 846 847static void 848arc_free(void *com, u_char type) 849{ 850 851 free(com, M_ARCCOM); 852} 853 854static int 855arc_modevent(module_t mod, int type, void *data) 856{ 857 858 switch (type) { 859 case MOD_LOAD: 860 if_register_com_alloc(IFT_ARCNET, arc_alloc, arc_free); 861 break; 862 case MOD_UNLOAD: 863 if_deregister_com_alloc(IFT_ARCNET); 864 break; 865 default: 866 return EOPNOTSUPP; 867 } 868 869 return (0); 870} 871 872static moduledata_t arc_mod = { 873 "arcnet", 874 arc_modevent, 875 0 876}; 877 878DECLARE_MODULE(arcnet, arc_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 879MODULE_VERSION(arcnet, 1); 880