source: rtems-libbsd/freebsd/sys/net/if_arcsubr.c @ 6d9d7b1

55-freebsd-126-freebsd-12
Last change on this file since 6d9d7b1 was 0237319, checked in by Sebastian Huber <sebastian.huber@…>, on 05/23/17 at 11:18:31

Update due to Newlib 2017-06-07 changes

The following files are now provided by Newlib:

  • arpa/inet.h
  • net/if.h
  • netinet/in.h
  • netinet/tcp.h
  • sys/socket.h
  • sys/uio.h
  • sys/un.h

The <sys/param.h> and <sys/cpuset.h> are now compatible enough to be
used directly.

Update #2833.

  • Property mode set to 100644
File size: 18.2 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*      $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $   */
4/*      $FreeBSD$ */
5
6/*-
7 * Copyright (c) 1994, 1995 Ignatios Souvatzis
8 * Copyright (c) 1982, 1989, 1993
9 *      The Regents of the University of California.  All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *      This product includes software developed by the University of
22 *      California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
40 *       @(#)if_ethersubr.c     8.1 (Berkeley) 6/10/93
41 *
42 */
43#include <rtems/bsd/local/opt_inet.h>
44#include <rtems/bsd/local/opt_inet6.h>
45
46#include <sys/param.h>
47#include <sys/systm.h>
48#include <sys/kernel.h>
49#include <sys/module.h>
50#include <sys/malloc.h>
51#include <sys/mbuf.h>
52#include <sys/protosw.h>
53#include <sys/socket.h>
54#include <sys/sockio.h>
55#include <sys/errno.h>
56#include <sys/syslog.h>
57
58#include <machine/cpu.h>
59
60#include <net/if.h>
61#include <net/if_var.h>
62#include <net/netisr.h>
63#include <net/route.h>
64#include <net/if_dl.h>
65#include <net/if_types.h>
66#include <net/if_arc.h>
67#include <net/if_arp.h>
68#include <net/bpf.h>
69#include <net/if_llatbl.h>
70
71#if defined(INET) || defined(INET6)
72#include <netinet/in.h>
73#include <netinet/in_var.h>
74#include <netinet/if_ether.h>
75#endif
76
77#ifdef INET6
78#include <netinet6/nd6.h>
79#endif
80
81#define ARCNET_ALLOW_BROKEN_ARP
82
83static struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
84static int arc_resolvemulti(struct ifnet *, struct sockaddr **,
85                            struct sockaddr *);
86
87u_int8_t  arcbroadcastaddr = 0;
88
89#define ARC_LLADDR(ifp) (*(u_int8_t *)IF_LLADDR(ifp))
90
91#define senderr(e) { error = (e); goto bad;}
92#define SIN(s)  ((const struct sockaddr_in *)(s))
93
94/*
95 * ARCnet output routine.
96 * Encapsulate a packet of type family for the local net.
97 * Assumes that ifp is actually pointer to arccom structure.
98 */
99int
100arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
101    struct route *ro)
102{
103        struct arc_header       *ah;
104        int                     error;
105        u_int8_t                atype, adst;
106        int                     loop_copy = 0;
107        int                     isphds;
108#if defined(INET) || defined(INET6)
109        int                     is_gw = 0;
110#endif
111
112        if (!((ifp->if_flags & IFF_UP) &&
113            (ifp->if_drv_flags & IFF_DRV_RUNNING)))
114                return(ENETDOWN); /* m, m1 aren't initialized yet */
115
116        error = 0;
117#if defined(INET) || defined(INET6)
118        if (ro != NULL)
119                is_gw = (ro->ro_flags & RT_HAS_GW) != 0;
120#endif
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, is_gw, m, dst, &adst, NULL,
135                            NULL);
136                        if (error)
137                                return (error == EWOULDBLOCK ? 0 : error);
138                }
139
140                atype = (ifp->if_flags & IFF_LINK0) ?
141                        ARCTYPE_IP_OLD : ARCTYPE_IP;
142                break;
143        case AF_ARP:
144        {
145                struct arphdr *ah;
146                ah = mtod(m, struct arphdr *);
147                ah->ar_hrd = htons(ARPHRD_ARCNET);
148
149                loop_copy = -1; /* if this is for us, don't do it */
150
151                switch(ntohs(ah->ar_op)) {
152                case ARPOP_REVREQUEST:
153                case ARPOP_REVREPLY:
154                        atype = ARCTYPE_REVARP;
155                        break;
156                case ARPOP_REQUEST:
157                case ARPOP_REPLY:
158                default:
159                        atype = ARCTYPE_ARP;
160                        break;
161                }
162
163                if (m->m_flags & M_BCAST)
164                        bcopy(ifp->if_broadcastaddr, &adst, ARC_ADDR_LEN);
165                else
166                        bcopy(ar_tha(ah), &adst, ARC_ADDR_LEN);
167       
168        }
169        break;
170#endif
171#ifdef INET6
172        case AF_INET6:
173                if ((m->m_flags & M_MCAST) != 0)
174                        adst = arcbroadcastaddr; /* ARCnet broadcast address */
175                else {
176                        error = nd6_resolve(ifp, is_gw, m, dst, &adst, NULL,
177                            NULL);
178                        if (error != 0)
179                                return (error == EWOULDBLOCK ? 0 : error);
180                }
181                atype = ARCTYPE_INET6;
182                break;
183#endif
184        case AF_UNSPEC:
185            {
186                const struct arc_header *ah;
187
188                loop_copy = -1;
189                ah = (const 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_NOWAIT);
217        if (m == NULL)
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_copym(m, 0, M_COPYALL, M_NOWAIT);
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        error = ifp->if_transmit(ifp, m);
242
243        return (error);
244
245bad:
246        if (m)
247                m_freem(m);
248        return (error);
249}
250
251void
252arc_frag_init(struct ifnet *ifp)
253{
254        struct arccom *ac;
255
256        ac = (struct arccom *)ifp->if_l2com;
257        ac->curr_frag = 0;
258}
259
260struct mbuf *
261arc_frag_next(struct ifnet *ifp)
262{
263        struct arccom *ac;
264        struct mbuf *m;
265        struct arc_header *ah;
266
267        ac = (struct arccom *)ifp->if_l2com;
268        if ((m = ac->curr_frag) == NULL) {
269                int tfrags;
270
271                /* dequeue new packet */
272                IF_DEQUEUE(&ifp->if_snd, m);
273                if (m == NULL)
274                        return 0;
275
276                ah = mtod(m, struct arc_header *);
277                if (!arc_isphds(ah->arc_type))
278                        return m;
279
280                ++ac->ac_seqid;         /* make the seqid unique */
281                tfrags = howmany(m->m_pkthdr.len, ARC_MAX_DATA);
282                ac->fsflag = 2 * tfrags - 3;
283                ac->sflag = 0;
284                ac->rsflag = ac->fsflag;
285                ac->arc_dhost = ah->arc_dhost;
286                ac->arc_shost = ah->arc_shost;
287                ac->arc_type = ah->arc_type;
288
289                m_adj(m, ARC_HDRNEWLEN);
290                ac->curr_frag = m;
291        }
292
293        /* split out next fragment and return it */
294        if (ac->sflag < ac->fsflag) {
295                /* we CAN'T have short packets here */
296                ac->curr_frag = m_split(m, ARC_MAX_DATA, M_NOWAIT);
297                if (ac->curr_frag == 0) {
298                        m_freem(m);
299                        return 0;
300                }
301
302                M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
303                if (m == NULL) {
304                        m_freem(ac->curr_frag);
305                        ac->curr_frag = 0;
306                        return 0;
307                }
308
309                ah = mtod(m, struct arc_header *);
310                ah->arc_flag = ac->rsflag;
311                ah->arc_seqid = ac->ac_seqid;
312
313                ac->sflag += 2;
314                ac->rsflag = ac->sflag;
315        } else if ((m->m_pkthdr.len >=
316            ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
317            (m->m_pkthdr.len <=
318            ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
319                ac->curr_frag = 0;
320
321                M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_NOWAIT);
322                if (m == NULL)
323                        return 0;
324
325                ah = mtod(m, struct arc_header *);
326                ah->arc_flag = 0xFF;
327                ah->arc_seqid = 0xFFFF;
328                ah->arc_type2 = ac->arc_type;
329                ah->arc_flag2 = ac->sflag;
330                ah->arc_seqid2 = ac->ac_seqid;
331        } else {
332                ac->curr_frag = 0;
333
334                M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
335                if (m == NULL)
336                        return 0;
337
338                ah = mtod(m, struct arc_header *);
339                ah->arc_flag = ac->sflag;
340                ah->arc_seqid = ac->ac_seqid;
341        }
342
343        ah->arc_dhost = ac->arc_dhost;
344        ah->arc_shost = ac->arc_shost;
345        ah->arc_type = ac->arc_type;
346
347        return m;
348}
349
350/*
351 * Defragmenter. Returns mbuf if last packet found, else
352 * NULL. frees incoming mbuf as necessary.
353 */
354
355static __inline struct mbuf *
356arc_defrag(struct ifnet *ifp, struct mbuf *m)
357{
358        struct arc_header *ah, *ah1;
359        struct arccom *ac;
360        struct ac_frag *af;
361        struct mbuf *m1;
362        char *s;
363        int newflen;
364        u_char src,dst,typ;
365
366        ac = (struct arccom *)ifp->if_l2com;
367
368        if (m->m_len < ARC_HDRNEWLEN) {
369                m = m_pullup(m, ARC_HDRNEWLEN);
370                if (m == NULL) {
371                        if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
372                        return NULL;
373                }
374        }
375
376        ah = mtod(m, struct arc_header *);
377        typ = ah->arc_type;
378
379        if (!arc_isphds(typ))
380                return m;
381
382        src = ah->arc_shost;
383        dst = ah->arc_dhost;
384
385        if (ah->arc_flag == 0xff) {
386                m_adj(m, 4);
387
388                if (m->m_len < ARC_HDRNEWLEN) {
389                        m = m_pullup(m, ARC_HDRNEWLEN);
390                        if (m == NULL) {
391                                if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
392                                return NULL;
393                        }
394                }
395
396                ah = mtod(m, struct arc_header *);
397        }
398
399        af = &ac->ac_fragtab[src];
400        m1 = af->af_packet;
401        s = "debug code error";
402
403        if (ah->arc_flag & 1) {
404                /*
405                 * first fragment. We always initialize, which is
406                 * about the right thing to do, as we only want to
407                 * accept one fragmented packet per src at a time.
408                 */
409                if (m1 != NULL)
410                        m_freem(m1);
411
412                af->af_packet = m;
413                m1 = m;
414                af->af_maxflag = ah->arc_flag;
415                af->af_lastseen = 0;
416                af->af_seqid = ah->arc_seqid;
417
418                return NULL;
419                /* notreached */
420        } else {
421                /* check for unfragmented packet */
422                if (ah->arc_flag == 0)
423                        return m;
424
425                /* do we have a first packet from that src? */
426                if (m1 == NULL) {
427                        s = "no first frag";
428                        goto outofseq;
429                }
430
431                ah1 = mtod(m1, struct arc_header *);
432
433                if (ah->arc_seqid != ah1->arc_seqid) {
434                        s = "seqid differs";
435                        goto outofseq;
436                }
437
438                if (typ != ah1->arc_type) {
439                        s = "type differs";
440                        goto outofseq;
441                }
442
443                if (dst != ah1->arc_dhost) {
444                        s = "dest host differs";
445                        goto outofseq;
446                }
447
448                /* typ, seqid and dst are ok here. */
449
450                if (ah->arc_flag == af->af_lastseen) {
451                        m_freem(m);
452                        return NULL;
453                }
454
455                if (ah->arc_flag == af->af_lastseen + 2) {
456                        /* ok, this is next fragment */
457                        af->af_lastseen = ah->arc_flag;
458                        m_adj(m,ARC_HDRNEWLEN);
459
460                        /*
461                         * m_cat might free the first mbuf (with pkthdr)
462                         * in 2nd chain; therefore:
463                         */
464
465                        newflen = m->m_pkthdr.len;
466
467                        m_cat(m1,m);
468
469                        m1->m_pkthdr.len += newflen;
470
471                        /* is it the last one? */
472                        if (af->af_lastseen > af->af_maxflag) {
473                                af->af_packet = NULL;
474                                return(m1);
475                        } else
476                                return NULL;
477                }
478                s = "other reason";
479                /* if all else fails, it is out of sequence, too */
480        }
481outofseq:
482        if (m1) {
483                m_freem(m1);
484                af->af_packet = NULL;
485        }
486
487        if (m)
488                m_freem(m);
489
490        log(LOG_INFO,"%s: got out of seq. packet: %s\n",
491            ifp->if_xname, s);
492
493        return NULL;
494}
495
496/*
497 * return 1 if Packet Header Definition Standard, else 0.
498 * For now: old IP, old ARP aren't obviously. Lacking correct information,
499 * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
500 * (Apple and Novell corporations were involved, among others, in PHDS work).
501 * Easiest is to assume that everybody else uses that, too.
502 */
503int
504arc_isphds(u_int8_t type)
505{
506        return (type != ARCTYPE_IP_OLD &&
507                type != ARCTYPE_ARP_OLD &&
508                type != ARCTYPE_DIAGNOSE);
509}
510
511/*
512 * Process a received Arcnet packet;
513 * the packet is in the mbuf chain m with
514 * the ARCnet header.
515 */
516void
517arc_input(struct ifnet *ifp, struct mbuf *m)
518{
519        struct arc_header *ah;
520        int isr;
521        u_int8_t atype;
522
523        if ((ifp->if_flags & IFF_UP) == 0) {
524                m_freem(m);
525                return;
526        }
527
528        /* possibly defragment: */
529        m = arc_defrag(ifp, m);
530        if (m == NULL)
531                return;
532
533        BPF_MTAP(ifp, m);
534
535        ah = mtod(m, struct arc_header *);
536        /* does this belong to us? */
537        if ((ifp->if_flags & IFF_PROMISC) == 0
538            && ah->arc_dhost != arcbroadcastaddr
539            && ah->arc_dhost != ARC_LLADDR(ifp)) {
540                m_freem(m);
541                return;
542        }
543
544        if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
545
546        if (ah->arc_dhost == arcbroadcastaddr) {
547                m->m_flags |= M_BCAST|M_MCAST;
548                if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1);
549        }
550
551        atype = ah->arc_type;
552        switch (atype) {
553#ifdef INET
554        case ARCTYPE_IP:
555                m_adj(m, ARC_HDRNEWLEN);
556                isr = NETISR_IP;
557                break;
558
559        case ARCTYPE_IP_OLD:
560                m_adj(m, ARC_HDRLEN);
561                isr = NETISR_IP;
562                break;
563
564        case ARCTYPE_ARP:
565                if (ifp->if_flags & IFF_NOARP) {
566                        /* Discard packet if ARP is disabled on interface */
567                        m_freem(m);
568                        return;
569                }
570                m_adj(m, ARC_HDRNEWLEN);
571                isr = NETISR_ARP;
572#ifdef ARCNET_ALLOW_BROKEN_ARP
573                mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
574#endif
575                break;
576
577        case ARCTYPE_ARP_OLD:
578                if (ifp->if_flags & IFF_NOARP) {
579                        /* Discard packet if ARP is disabled on interface */
580                        m_freem(m);
581                        return;
582                }
583                m_adj(m, ARC_HDRLEN);
584                isr = NETISR_ARP;
585#ifdef ARCNET_ALLOW_BROKEN_ARP
586                mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
587#endif
588                break;
589#endif
590#ifdef INET6
591        case ARCTYPE_INET6:
592                m_adj(m, ARC_HDRNEWLEN);
593                isr = NETISR_IPV6;
594                break;
595#endif
596        default:
597                m_freem(m);
598                return;
599        }
600        M_SETFIB(m, ifp->if_fib);
601        netisr_dispatch(isr, m);
602}
603
604/*
605 * Register (new) link level address.
606 */
607void
608arc_storelladdr(struct ifnet *ifp, u_int8_t lla)
609{
610        ARC_LLADDR(ifp) = lla;
611}
612
613/*
614 * Perform common duties while attaching to interface list
615 */
616void
617arc_ifattach(struct ifnet *ifp, u_int8_t lla)
618{
619        struct ifaddr *ifa;
620        struct sockaddr_dl *sdl;
621        struct arccom *ac;
622
623        if_attach(ifp);
624        ifp->if_addrlen = 1;
625        ifp->if_hdrlen = ARC_HDRLEN;
626        ifp->if_mtu = 1500;
627        ifp->if_resolvemulti = arc_resolvemulti;
628        if (ifp->if_baudrate == 0)
629                ifp->if_baudrate = 2500000;
630        ifa = ifp->if_addr;
631        KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
632        sdl = (struct sockaddr_dl *)ifa->ifa_addr;
633        sdl->sdl_type = IFT_ARCNET;
634        sdl->sdl_alen = ifp->if_addrlen;
635
636        if (ifp->if_flags & IFF_BROADCAST)
637                ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
638
639        ac = (struct arccom *)ifp->if_l2com;
640        ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
641        if (lla == 0) {
642                /* XXX this message isn't entirely clear, to me -- cgd */
643                log(LOG_ERR,"%s: link address 0 reserved for broadcasts.  Please change it and ifconfig %s down up\n",
644                   ifp->if_xname, ifp->if_xname);
645        }
646        arc_storelladdr(ifp, lla);
647
648        ifp->if_broadcastaddr = &arcbroadcastaddr;
649
650        bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
651}
652
653void
654arc_ifdetach(struct ifnet *ifp)
655{
656        bpfdetach(ifp);
657        if_detach(ifp);
658}
659
660int
661arc_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
662{
663        struct ifaddr *ifa = (struct ifaddr *) data;
664        struct ifreq *ifr = (struct ifreq *) data;
665        int error = 0;
666
667        switch (command) {
668        case SIOCSIFADDR:
669                ifp->if_flags |= IFF_UP;
670                switch (ifa->ifa_addr->sa_family) {
671#ifdef INET
672                case AF_INET:
673                        ifp->if_init(ifp->if_softc);    /* before arpwhohas */
674                        arp_ifinit(ifp, ifa);
675                        break;
676#endif
677                default:
678                        ifp->if_init(ifp->if_softc);
679                        break;
680                }
681                break;
682
683        case SIOCGIFADDR:
684                {
685                        struct sockaddr *sa;
686
687                        sa = (struct sockaddr *) &ifr->ifr_data;
688                        *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp);
689                }
690                break;
691
692        case SIOCADDMULTI:
693        case SIOCDELMULTI:
694                if (ifr == NULL)
695                        error = EAFNOSUPPORT;
696                else {
697                        switch (ifr->ifr_addr.sa_family) {
698                        case AF_INET:
699                        case AF_INET6:
700                                error = 0;
701                                break;
702                        default:
703                                error = EAFNOSUPPORT;
704                                break;
705                        }
706                }
707                break;
708
709        case SIOCSIFMTU:
710                /*
711                 * Set the interface MTU.
712                 * mtu can't be larger than ARCMTU for RFC1051
713                 * and can't be larger than ARC_PHDS_MTU
714                 */
715                if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
716                    ifr->ifr_mtu > ARC_PHDS_MAXMTU)
717                        error = EINVAL;
718                else
719                        ifp->if_mtu = ifr->ifr_mtu;
720                break;
721        }
722
723        return (error);
724}
725
726/* based on ether_resolvemulti() */
727int
728arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
729    struct sockaddr *sa)
730{
731        struct sockaddr_dl *sdl;
732#ifdef INET
733        struct sockaddr_in *sin;
734#endif
735#ifdef INET6
736        struct sockaddr_in6 *sin6;
737#endif
738
739        switch(sa->sa_family) {
740        case AF_LINK:
741                /*
742                * No mapping needed. Just check that it's a valid MC address.
743                */
744                sdl = (struct sockaddr_dl *)sa;
745                if (*LLADDR(sdl) != arcbroadcastaddr)
746                        return EADDRNOTAVAIL;
747                *llsa = NULL;
748                return 0;
749#ifdef INET
750        case AF_INET:
751                sin = (struct sockaddr_in *)sa;
752                if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
753                        return EADDRNOTAVAIL;
754                sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
755                sdl->sdl_alen = ARC_ADDR_LEN;
756                *LLADDR(sdl) = 0;
757                *llsa = (struct sockaddr *)sdl;
758                return 0;
759#endif
760#ifdef INET6
761        case AF_INET6:
762                sin6 = (struct sockaddr_in6 *)sa;
763                if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
764                        /*
765                         * An IP6 address of 0 means listen to all
766                         * of the Ethernet multicast address used for IP6.
767                         * (This is used for multicast routers.)
768                         */
769                        ifp->if_flags |= IFF_ALLMULTI;
770                        *llsa = NULL;
771                        return 0;
772                }
773                if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
774                        return EADDRNOTAVAIL;
775                sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
776                sdl->sdl_alen = ARC_ADDR_LEN;
777                *LLADDR(sdl) = 0;
778                *llsa = (struct sockaddr *)sdl;
779                return 0;
780#endif
781
782        default:
783                /*
784                 * Well, the text isn't quite right, but it's the name
785                 * that counts...
786                 */
787                return EAFNOSUPPORT;
788        }
789}
790
791static MALLOC_DEFINE(M_ARCCOM, "arccom", "ARCNET interface internals");
792
793static void*
794arc_alloc(u_char type, struct ifnet *ifp)
795{
796        struct arccom   *ac;
797       
798        ac = malloc(sizeof(struct arccom), M_ARCCOM, M_WAITOK | M_ZERO);
799        ac->ac_ifp = ifp;
800
801        return (ac);
802}
803
804static void
805arc_free(void *com, u_char type)
806{
807
808        free(com, M_ARCCOM);
809}
810
811static int
812arc_modevent(module_t mod, int type, void *data)
813{
814
815        switch (type) {
816        case MOD_LOAD:
817                if_register_com_alloc(IFT_ARCNET, arc_alloc, arc_free);
818                break;
819        case MOD_UNLOAD:
820                if_deregister_com_alloc(IFT_ARCNET);
821                break;
822        default:
823                return EOPNOTSUPP;
824        }
825
826        return (0);
827}
828
829static moduledata_t arc_mod = {
830        "arcnet",
831        arc_modevent,
832        0
833};
834
835DECLARE_MODULE(arcnet, arc_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
836MODULE_VERSION(arcnet, 1);
Note: See TracBrowser for help on using the repository browser.