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