if_arcsubr.c revision 111119
1/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */ 2/* $FreeBSD: head/sys/net/if_arcsubr.c 111119 2003-02-19 05:47:46Z imp $ */ 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 if ((rt = rt0)) { 125 if ((rt->rt_flags & RTF_UP) == 0) { 126 if ((rt0 = rt = rtalloc1(dst, 1, 0UL))) 127 rt->rt_refcnt--; 128 else 129 senderr(EHOSTUNREACH); 130 } 131 if (rt->rt_flags & RTF_GATEWAY) { 132 if (rt->rt_gwroute == 0) 133 goto lookup; 134 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 135 rtfree(rt); rt = rt0; 136 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); 137 if ((rt = rt->rt_gwroute) == 0) 138 senderr(EHOSTUNREACH); 139 } 140 } 141 if (rt->rt_flags & RTF_REJECT) 142 if (rt->rt_rmx.rmx_expire == 0 || 143 time_second < rt->rt_rmx.rmx_expire) 144 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 145 } 146 147 switch (dst->sa_family) { 148#ifdef INET 149 case AF_INET: 150 151 /* 152 * For now, use the simple IP addr -> ARCnet addr mapping 153 */ 154 if (m->m_flags & (M_BCAST|M_MCAST)) 155 adst = arcbroadcastaddr; /* ARCnet broadcast address */ 156 else if (ifp->if_flags & IFF_NOARP) 157 adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF; 158 else if (!arpresolve(ifp, rt, m, dst, &adst, rt0)) 159 return 0; /* not resolved yet */ 160 161 atype = (ifp->if_flags & IFF_LINK0) ? 162 ARCTYPE_IP_OLD : ARCTYPE_IP; 163 break; 164#endif 165#ifdef INET6 166 case AF_INET6: 167#ifdef OLDIP6OUTPUT 168 if (!nd6_resolve(ifp, rt, m, dst, (u_char *)&adst)) 169 return(0); /* if not yet resolves */ 170#else 171 if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&adst)) 172 return(0); /* it must be impossible, but... */ 173#endif /* OLDIP6OUTPUT */ 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%d: got out of seq. packet: %s\n", 497 ifp->if_name, ifp->if_unit, 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 struct ifqueue *inq; 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 (ipflow_fastforward(m)) 566 return; 567 schednetisr(NETISR_IP); 568 inq = &ipintrq; 569 break; 570 571 case ARCTYPE_IP_OLD: 572 m_adj(m, ARC_HDRLEN); 573 if (ipflow_fastforward(m)) 574 return; 575 schednetisr(NETISR_IP); 576 inq = &ipintrq; 577 break; 578 579 case ARCTYPE_ARP: 580 if (ifp->if_flags & IFF_NOARP) { 581 /* Discard packet if ARP is disabled on interface */ 582 m_freem(m); 583 return; 584 } 585 m_adj(m, ARC_HDRNEWLEN); 586 schednetisr(NETISR_ARP); 587 inq = &arpintrq; 588#ifdef ARCNET_ALLOW_BROKEN_ARP 589 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 590#endif 591 break; 592 593 case ARCTYPE_ARP_OLD: 594 if (ifp->if_flags & IFF_NOARP) { 595 /* Discard packet if ARP is disabled on interface */ 596 m_freem(m); 597 return; 598 } 599 m_adj(m, ARC_HDRLEN); 600 schednetisr(NETISR_ARP); 601 inq = &arpintrq; 602#ifdef ARCNET_ALLOW_BROKEN_ARP 603 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 604#endif 605 break; 606#endif 607#ifdef INET6 608 case ARCTYPE_INET6: 609 m_adj(m, ARC_HDRNEWLEN); 610 schednetisr(NETISR_IPV6); 611 inq = &ip6intrq; 612 break; 613#endif 614#ifdef IPX 615 case ARCTYPE_IPX: 616 m_adj(m, ARC_HDRNEWLEN); 617 schednetisr(NETISR_IPX); 618 inq = &ipxintrq; 619 break; 620#endif 621 default: 622 m_freem(m); 623 return; 624 } 625 626 IF_HANDOFF(inq, m, NULL); 627} 628 629/* 630 * Register (new) link level address. 631 */ 632void 633arc_storelladdr(ifp, lla) 634 struct ifnet *ifp; 635 u_int8_t lla; 636{ 637 ARC_LLADDR(ifp) = lla; 638} 639 640/* 641 * Perform common duties while attaching to interface list 642 */ 643void 644arc_ifattach(ifp, lla) 645 struct ifnet *ifp; 646 u_int8_t lla; 647{ 648 struct ifaddr *ifa; 649 struct sockaddr_dl *sdl; 650 struct arccom *ac; 651 652 if_attach(ifp); 653 ifp->if_type = IFT_ARCNET; 654 ifp->if_addrlen = 1; 655 ifp->if_hdrlen = ARC_HDRLEN; 656 ifp->if_mtu = 1500; 657 ifp->if_resolvemulti = arc_resolvemulti; 658 if (ifp->if_baudrate == 0) 659 ifp->if_baudrate = 2500000; 660#if __FreeBSD_version < 500000 661 ifa = ifnet_addrs[ifp->if_index - 1]; 662#else 663 ifa = ifaddr_byindex(ifp->if_index); 664#endif 665 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__)); 666 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 667 sdl->sdl_type = IFT_ARCNET; 668 sdl->sdl_alen = ifp->if_addrlen; 669 670 if (ifp->if_flags & IFF_BROADCAST) 671 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI; 672 673 ac = (struct arccom *)ifp; 674 ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */ 675 if (lla == 0) { 676 /* XXX this message isn't entirely clear, to me -- cgd */ 677 log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts. Please change it and ifconfig %s%d down up\n", 678 ifp->if_name, ifp->if_unit, ifp->if_name, ifp->if_unit); 679 } 680 arc_storelladdr(ifp, lla); 681 682 ifp->if_broadcastaddr = &arcbroadcastaddr; 683 684 bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN); 685} 686 687void 688arc_ifdetach(ifp) 689 struct ifnet *ifp; 690{ 691 bpfdetach(ifp); 692 if_detach(ifp); 693} 694 695int 696arc_ioctl(ifp, command, data) 697 struct ifnet *ifp; 698 int command; 699 caddr_t data; 700{ 701 struct ifaddr *ifa = (struct ifaddr *) data; 702 struct ifreq *ifr = (struct ifreq *) data; 703 int error = 0; 704 705 switch (command) { 706 case SIOCSIFADDR: 707 ifp->if_flags |= IFF_UP; 708 switch (ifa->ifa_addr->sa_family) { 709#ifdef INET 710 case AF_INET: 711 ifp->if_init(ifp->if_softc); /* before arpwhohas */ 712 arp_ifinit(ifp, ifa); 713 break; 714#endif 715#ifdef IPX 716 /* 717 * XXX This code is probably wrong 718 */ 719 case AF_IPX: 720 { 721 struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 722 723 if (ipx_nullhost(*ina)) 724 ina->x_host.c_host[5] = ARC_LLADDR(ifp); 725 else 726 arc_storelladdr(ifp, ina->x_host.c_host[5]); 727 728 /* 729 * Set new address 730 */ 731 ifp->if_init(ifp->if_softc); 732 break; 733 } 734#endif 735 default: 736 ifp->if_init(ifp->if_softc); 737 break; 738 } 739 break; 740 741 case SIOCGIFADDR: 742 { 743 struct sockaddr *sa; 744 745 sa = (struct sockaddr *) &ifr->ifr_data; 746 *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp); 747 } 748 break; 749 750 case SIOCADDMULTI: 751 case SIOCDELMULTI: 752 if (ifr == NULL) 753 error = EAFNOSUPPORT; 754 else { 755 switch (ifr->ifr_addr.sa_family) { 756 case AF_INET: 757 case AF_INET6: 758 error = 0; 759 break; 760 default: 761 error = EAFNOSUPPORT; 762 break; 763 } 764 } 765 break; 766 767 case SIOCSIFMTU: 768 /* 769 * Set the interface MTU. 770 * mtu can't be larger than ARCMTU for RFC1051 771 * and can't be larger than ARC_PHDS_MTU 772 */ 773 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) || 774 ifr->ifr_mtu > ARC_PHDS_MAXMTU) 775 error = EINVAL; 776 else 777 ifp->if_mtu = ifr->ifr_mtu; 778 break; 779 } 780 781 return (error); 782} 783 784/* based on ether_resolvemulti() */ 785int 786arc_resolvemulti(ifp, llsa, sa) 787 struct ifnet *ifp; 788 struct sockaddr **llsa; 789 struct sockaddr *sa; 790{ 791 struct sockaddr_dl *sdl; 792 struct sockaddr_in *sin; 793#ifdef INET6 794 struct sockaddr_in6 *sin6; 795#endif 796 797 switch(sa->sa_family) { 798 case AF_LINK: 799 /* 800 * No mapping needed. Just check that it's a valid MC address. 801 */ 802 sdl = (struct sockaddr_dl *)sa; 803 if (*LLADDR(sdl) != arcbroadcastaddr) 804 return EADDRNOTAVAIL; 805 *llsa = 0; 806 return 0; 807#ifdef INET 808 case AF_INET: 809 sin = (struct sockaddr_in *)sa; 810 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 811 return EADDRNOTAVAIL; 812 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 813 M_ZERO); 814 sdl->sdl_len = sizeof *sdl; 815 sdl->sdl_family = AF_LINK; 816 sdl->sdl_index = ifp->if_index; 817 sdl->sdl_type = IFT_ARCNET; 818 sdl->sdl_alen = ARC_ADDR_LEN; 819 *LLADDR(sdl) = 0; 820 *llsa = (struct sockaddr *)sdl; 821 return 0; 822#endif 823#ifdef INET6 824 case AF_INET6: 825 sin6 = (struct sockaddr_in6 *)sa; 826 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 827 /* 828 * An IP6 address of 0 means listen to all 829 * of the Ethernet multicast address used for IP6. 830 * (This is used for multicast routers.) 831 */ 832 ifp->if_flags |= IFF_ALLMULTI; 833 *llsa = 0; 834 return 0; 835 } 836 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 837 return EADDRNOTAVAIL; 838 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 839 M_ZERO); 840 sdl->sdl_len = sizeof *sdl; 841 sdl->sdl_family = AF_LINK; 842 sdl->sdl_index = ifp->if_index; 843 sdl->sdl_type = IFT_ARCNET; 844 sdl->sdl_alen = ARC_ADDR_LEN; 845 *LLADDR(sdl) = 0; 846 *llsa = (struct sockaddr *)sdl; 847 return 0; 848#endif 849 850 default: 851 /* 852 * Well, the text isn't quite right, but it's the name 853 * that counts... 854 */ 855 return EAFNOSUPPORT; 856 } 857} 858