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