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