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