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