source: rtems/cpukit/libnetworking/net/if_ethersubr.c @ 9356119

4.115
Last change on this file since 9356119 was 9356119, checked in by Ralf Corsepius <ralf.corsepius@…>, on Oct 20, 2011 at 1:54:45 PM

2011-10-20 Ralf Corsépius <ralf.corsepius@…>

  • libnetworking/net/if_ethersubr.c (ether_output): Remove unused vars "hlen", "off".
  • Property mode set to 100644
File size: 21.5 KB
Line 
1/*
2 * Copyright (c) 1982, 1989, 1993
3 *      The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *      @(#)if_ethersubr.c      8.1 (Berkeley) 6/10/93
30 * $FreeBSD: src/sys/net/if_ethersubr.c,v 1.189 2005/03/06 22:59:40 sobomax Exp $
31 */
32 
33/*
34 * $Id$
35 */
36
37#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40
41#include "opt_atalk.h"
42#include "opt_inet.h"
43#include "opt_inet6.h"
44#include "opt_ipx.h"
45#include "opt_bdg.h"
46#include "opt_mac.h"
47#include "opt_netgraph.h"
48
49#include <sys/param.h>
50#include <sys/systm.h>
51#include <sys/kernel.h>
52#include <sys/malloc.h>
53#include <sys/mbuf.h>
54#include <sys/protosw.h>
55#include <sys/socket.h>
56#include <sys/ioctl.h>
57#include <errno.h>
58#include <sys/syslog.h>
59#include <sys/sysctl.h>
60
61#include <net/if.h>
62#include <net/if_arp.h>
63#include <net/netisr.h>
64#include <net/route.h>
65#include <net/if_llc.h>
66#include <net/if_dl.h>
67#include <net/if_types.h>
68#include <net/ethernet.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#include <netinet/ip_fw.h>
75#ifndef __rtems__
76#include <netinet/ip_dummynet.h>
77#endif
78#endif
79#ifdef INET6
80#include <netinet6/nd6.h>
81#endif
82
83#ifdef DEV_CARP
84#include <netinet/ip_carp.h>
85#endif
86
87#ifdef IPX
88#include <netipx/ipx.h>
89#include <netipx/ipx_if.h>
90#endif
91
92#ifdef NETATALK
93#include <netatalk/at.h>
94#include <netatalk/at_var.h>
95#include <netatalk/at_extern.h>
96
97#define llc_snap_org_code llc_un.type_snap.org_code
98#define llc_snap_ether_type llc_un.type_snap.ether_type
99
100extern u_char   at_org_code[3];
101extern u_char   aarp_org_code[3];
102#endif /* NETATALK */
103
104u_char  etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
105#define senderr(e) do { error = (e); goto bad;} while (0)
106
107/*
108 * Ethernet output routine.
109 * Encapsulate a packet of type family for the local net.
110 * Use trailer local net encapsulation if enough data in first
111 * packet leaves a multiple of 512 bytes of data in remainder.
112 * Assumes that ifp is actually pointer to arpcom structure.
113 */
114int
115ether_output(struct ifnet *ifp, struct mbuf *m,
116        struct sockaddr *dst, struct rtentry *rt0)
117{
118        short type;
119        int s, error = 0;
120        u_char  edst[6];
121        register struct rtentry *rt;
122        struct mbuf *mcopy = (struct mbuf *)0;
123        register struct ether_header *eh;
124        int len = m->m_pkthdr.len;
125        struct arpcom *ac = (struct arpcom *)ifp;
126#ifdef NETATALK
127        struct at_ifaddr *aa;
128#endif /* NETATALK */
129
130        if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
131                senderr(ENETDOWN);
132        rt = rt0;
133        if (rt) {
134                if ((rt->rt_flags & RTF_UP) == 0) {
135                        rt0 = rt = rtalloc1(dst, 1, 0UL);
136                        if (rt0)
137                                rt->rt_refcnt--;
138                        else
139                                senderr(EHOSTUNREACH);
140                }
141                if (rt->rt_flags & RTF_GATEWAY) {
142                        if (rt->rt_gwroute == 0)
143                                goto lookup;
144                        if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
145                                rtfree(rt); rt = rt0;
146                        lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1,
147                                                          0UL);
148                                if ((rt = rt->rt_gwroute) == 0)
149                                        senderr(EHOSTUNREACH);
150                        }
151                }
152                if (rt->rt_flags & RTF_REJECT)
153                        if (rt->rt_rmx.rmx_expire == 0 ||
154                            rtems_bsdnet_seconds_since_boot() < rt->rt_rmx.rmx_expire)
155                                senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
156        }
157        switch (dst->sa_family) {
158
159#ifdef INET
160        case AF_INET:
161                if (!arpresolve(ac, rt, m, dst, edst, rt0))
162                        return (0);     /* if not yet resolved */
163                /* If broadcasting on a simplex interface, loopback a copy */
164                if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
165                        mcopy = m_copy(m, 0, (int)M_COPYALL);
166                type = htons(ETHERTYPE_IP);
167                break;
168#endif
169#ifdef IPX
170        case AF_IPX:
171                {
172                struct ifaddr *ia;
173
174                type = htons(ETHERTYPE_IPX);
175                bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
176                    (caddr_t)edst, sizeof (edst));
177                for (ia = ifp->if_addrlist; ia != NULL; ia = ia->ifa_next)
178                        if(ia->ifa_addr->sa_family == AF_IPX &&
179                           !bcmp((caddr_t)edst,
180                                 (caddr_t)&((struct ipx_ifaddr *)ia)->ia_addr.sipx_addr.x_host,
181                                 sizeof(edst)))
182                                return (looutput(ifp, m, dst, rt));
183                /* If broadcasting on a simplex interface, loopback a copy */
184                if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
185                        mcopy = m_copy(m, 0, (int)M_COPYALL);
186                break;
187                }
188#endif
189#ifdef NETATALK
190        case AF_APPLETALK:
191            {
192                struct sockaddr_at *sat = (struct sockaddr_at *)dst;
193
194                /*
195                 * super hack..
196                 * Most of this loopback code should move into the appletalk
197                 * code, but it's here for now.. remember to move it! [JRE]
198                 * This may not get the same interface we started with
199                 * fix asap. XXX
200                 */
201                aa = at_ifawithnet( sat );
202                if (aa == NULL) {
203                        goto bad;
204                }
205                if( aa->aa_ifa.ifa_ifp != ifp ) {
206                        (*aa->aa_ifa.ifa_ifp->if_output)(aa->aa_ifa.ifa_ifp,
207                                                        m,dst,rt);
208                }
209                if (((sat->sat_addr.s_net == ATADDR_ANYNET)
210                  && (sat->sat_addr.s_node == ATADDR_ANYNODE))
211                || ((sat->sat_addr.s_net == aa->aa_addr.sat_addr.s_net )
212                  && (sat->sat_addr.s_node == aa->aa_addr.sat_addr.s_node))) {
213                        (void) looutput(ifp, m, dst, rt);
214                        return(0);
215                }
216
217                if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) {
218#ifdef NETATALKDEBUG
219                        extern char *prsockaddr(struct sockaddr *);
220                        printf("aarpresolv: failed for %s\n", prsockaddr(dst));
221#endif /* NETATALKDEBUG */
222                        return (0);
223                }
224
225                /*
226                 * If broadcasting on a simplex interface, loopback a copy
227                 */
228                if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
229                        mcopy = m_copy(m, 0, (int)M_COPYALL);
230            }
231            /*
232             * In the phase 2 case, we need to prepend an mbuf for the llc header.
233             * Since we must preserve the value of m, which is passed to us by
234             * value, we m_copy() the first mbuf, and use it for our llc header.
235             */
236            if ( aa->aa_flags & AFA_PHASE2 ) {
237                struct llc llc;
238
239                M_PREPEND(m, sizeof(struct llc), M_WAIT);
240                len += sizeof(struct llc);
241                llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
242                llc.llc_control = LLC_UI;
243                bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code));
244                llc.llc_snap_ether_type = htons( ETHERTYPE_AT );
245                bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc));
246                type = htons(m->m_pkthdr.len);
247            } else {
248                type = htons(ETHERTYPE_AT);
249            }
250            break;
251#endif /* NETATALK */
252
253        case AF_UNSPEC:
254                eh = (struct ether_header *)dst->sa_data;
255                (void)memcpy(edst, eh->ether_dhost, sizeof (edst));
256                type = eh->ether_type;
257                break;
258
259        default:
260                printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
261                        dst->sa_family);
262                senderr(EAFNOSUPPORT);
263        }
264
265
266        if (mcopy)
267                (void) looutput(ifp, mcopy, dst, rt);
268        /*
269         * Add local net header.  If no space in first mbuf,
270         * allocate another.
271         */
272        M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
273        if (m == NULL)
274                senderr(ENOBUFS);
275        eh = mtod(m, struct ether_header *);
276        (void)memcpy(&eh->ether_type, &type,
277                sizeof(eh->ether_type));
278        (void)memcpy(eh->ether_dhost, edst, sizeof (edst));
279        (void)memcpy(eh->ether_shost, ac->ac_enaddr,
280            sizeof(eh->ether_shost));
281        s = splimp();
282        /*
283         * Queue message on interface, and start output if interface
284         * not yet active.
285         */
286        if (IF_QFULL(&ifp->if_snd)) {
287                IF_DROP(&ifp->if_snd);
288                splx(s);
289                senderr(ENOBUFS);
290        }
291        IF_ENQUEUE(&ifp->if_snd, m);
292        if ((ifp->if_flags & IFF_OACTIVE) == 0)
293                (*ifp->if_start)(ifp);
294        splx(s);
295        ifp->if_obytes += len + sizeof (struct ether_header);
296        if (m->m_flags & M_MCAST)
297                ifp->if_omcasts++;
298        return (error);
299
300bad:
301        if (m)
302                m_freem(m);
303        return (error);
304}
305
306/*
307 * Process a received Ethernet packet;
308 * the packet is in the mbuf chain m without
309 * the ether header, which is provided separately.
310 */
311void
312ether_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
313{
314        register struct ifqueue *inq;
315        u_short ether_type;
316        int s;
317#if defined(NETATALK)
318        struct llc *l;
319#endif
320
321        if ((ifp->if_flags & IFF_UP) == 0) {
322                m_freem(m);
323                return;
324        }
325        ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
326        if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
327            sizeof(etherbroadcastaddr)) == 0)
328                m->m_flags |= M_BCAST;
329        else if (eh->ether_dhost[0] & 1)
330                m->m_flags |= M_MCAST;
331        if (m->m_flags & (M_BCAST|M_MCAST))
332                ifp->if_imcasts++;
333
334        /*
335         * RTEMS addition -- allow application to `tap into'
336         * the incoming packet stream.
337         */
338        if (ifp->if_tap && (*ifp->if_tap)(ifp, eh, m)) {
339                m_freem(m);
340                return;
341        }
342
343        ether_type = ntohs(eh->ether_type);
344
345        switch (ether_type) {
346#ifdef INET
347        case ETHERTYPE_IP:
348                schednetisr(NETISR_IP);
349                inq = &ipintrq;
350                break;
351
352        case ETHERTYPE_ARP:
353                schednetisr(NETISR_ARP);
354                inq = &arpintrq;
355                break;
356#endif
357#ifdef IPX
358        case ETHERTYPE_IPX:
359                schednetisr(NETISR_IPX);
360                inq = &ipxintrq;
361                break;
362#endif
363#ifdef NETATALK
364        case ETHERTYPE_AT:
365                schednetisr(NETISR_ATALK);
366                inq = &atintrq1;
367                break;
368        case ETHERTYPE_AARP:
369                /* probably this should be done with a NETISR as well */
370                aarpinput((struct arpcom *)ifp, m); /* XXX */
371                return;
372#endif /* NETATALK */
373        default:
374#if defined (ISO) || defined (LLC) || defined(NETATALK)
375                if (ether_type > ETHERMTU)
376                        goto dropanyway;
377                l = mtod(m, struct llc *);
378                switch (l->llc_dsap) {
379#ifdef NETATALK
380                case LLC_SNAP_LSAP:
381                    switch (l->llc_control) {
382                    case LLC_UI:
383                        if (l->llc_ssap != LLC_SNAP_LSAP)
384                            goto dropanyway;
385       
386                        if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code,
387                                   sizeof(at_org_code)) == 0 &&
388                             ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) {
389                            inq = &atintrq2;
390                            m_adj( m, sizeof( struct llc ));
391                            schednetisr(NETISR_ATALK);
392                            break;
393                        }
394
395                        if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code,
396                                   sizeof(aarp_org_code)) == 0 &&
397                             ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) {
398                            m_adj( m, sizeof( struct llc ));
399                            aarpinput((struct arpcom *)ifp, m); /* XXX */
400                            return;
401                        }
402               
403                    default:
404                        goto dropanyway;
405                    }
406                    break;
407#endif /* NETATALK */
408#ifdef  ISO
409                case LLC_ISO_LSAP:
410                        switch (l->llc_control) {
411                        case LLC_UI:
412                                /* LLC_UI_P forbidden in class 1 service */
413                                if ((l->llc_dsap == LLC_ISO_LSAP) &&
414                                    (l->llc_ssap == LLC_ISO_LSAP)) {
415                                        /* LSAP for ISO */
416                                        if (m->m_pkthdr.len > ether_type)
417                                                m_adj(m, ether_type - m->m_pkthdr.len);
418                                        m->m_data += 3;         /* XXX */
419                                        m->m_len -= 3;          /* XXX */
420                                        m->m_pkthdr.len -= 3;   /* XXX */
421                                        M_PREPEND(m, sizeof *eh, M_DONTWAIT);
422                                        if (m == 0)
423                                                return;
424                                        *mtod(m, struct ether_header *) = *eh;
425                                        IFDEBUG(D_ETHER)
426                                                printf("clnp packet");
427                                        ENDDEBUG
428                                        schednetisr(NETISR_ISO);
429                                        inq = &clnlintrq;
430                                        break;
431                                }
432                                goto dropanyway;
433
434                        case LLC_XID:
435                        case LLC_XID_P:
436                                if(m->m_len < 6)
437                                        goto dropanyway;
438                                l->llc_window = 0;
439                                l->llc_fid = 9;
440                                l->llc_class = 1;
441                                l->llc_dsap = l->llc_ssap = 0;
442                                /* Fall through to */
443                        case LLC_TEST:
444                        case LLC_TEST_P:
445                        {
446                                struct sockaddr sa;
447                                register struct ether_header *eh2;
448                                int i;
449                                u_char c = l->llc_dsap;
450
451                                l->llc_dsap = l->llc_ssap;
452                                l->llc_ssap = c;
453                                if (m->m_flags & (M_BCAST | M_MCAST))
454                                        bcopy((caddr_t)ac->ac_enaddr,
455                                              (caddr_t)eh->ether_dhost, 6);
456                                sa.sa_family = AF_UNSPEC;
457                                sa.sa_len = sizeof(sa);
458                                eh2 = (struct ether_header *)sa.sa_data;
459                                for (i = 0; i < 6; i++) {
460                                        eh2->ether_shost[i] = c = eh->ether_dhost[i];
461                                        eh2->ether_dhost[i] =
462                                                eh->ether_dhost[i] = eh->ether_shost[i];
463                                        eh->ether_shost[i] = c;
464                                }
465                                ifp->if_output(ifp, m, &sa, NULL);
466                                return;
467                        }
468                        default:
469                                m_freem(m);
470                                return;
471                        }
472                        break;
473#endif /* ISO */
474#ifdef LLC
475                case LLC_X25_LSAP:
476                {
477                        if (m->m_pkthdr.len > ether_type)
478                                m_adj(m, ether_type - m->m_pkthdr.len);
479                        M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT);
480                        if (m == 0)
481                                return;
482                        if ( !sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP,
483                                            eh->ether_dhost, LLC_X25_LSAP, 6,
484                                            mtod(m, struct sdl_hdr *)))
485                                panic("ETHER cons addr failure");
486                        mtod(m, struct sdl_hdr *)->sdlhdr_len = ether_type;
487#ifdef LLC_DEBUG
488                                printf("llc packet\n");
489#endif /* LLC_DEBUG */
490                        schednetisr(NETISR_CCITT);
491                        inq = &llcintrq;
492                        break;
493                }
494#endif /* LLC */
495                dropanyway:
496                default:
497                        m_freem(m);
498                        return;
499                }
500#else /* ISO || LLC || NETATALK */
501            m_freem(m);
502            return;
503#endif /* ISO || LLC || NETATALK */
504        }
505
506        s = splimp();
507        if (IF_QFULL(inq)) {
508                IF_DROP(inq);
509                m_freem(m);
510        } else
511                IF_ENQUEUE(inq, m);
512        splx(s);
513}
514
515/*
516 * Convert Ethernet address to printable (loggable) representation.
517 * The static buffer isn't a really huge problem since this code
518 * is protected by the RTEMS network mutex.
519 */
520char *
521ether_sprintf(const u_char *ap)
522{
523        static char buf[32];
524        char *b = buf;
525        int i;
526
527        for (i = 0; i < ETHER_ADDR_LEN; i++, b+=3)
528                sprintf(b, "%02x:", *ap++);
529        *--b = '\0';
530        return buf;
531}
532
533/*
534 * Perform common duties while attaching to interface list
535 */
536void
537ether_ifattach(struct ifnet *ifp)
538{
539        struct ifaddr *ifa;
540        struct sockaddr_dl *sdl;
541
542        ifp->if_type = IFT_ETHER;
543        ifp->if_addrlen = ETHER_ADDR_LEN;
544        ifp->if_hdrlen = ETHER_HDR_LEN;
545        ifp->if_mtu = ETHERMTU;
546        if (ifp->if_baudrate == 0)
547            ifp->if_baudrate = 10000000;
548        for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
549                if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
550                    sdl->sdl_family == AF_LINK) {
551                        sdl->sdl_type = IFT_ETHER;
552                        sdl->sdl_alen = ifp->if_addrlen;
553                        bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
554                              LLADDR(sdl), ifp->if_addrlen);
555                        break;
556                }
557}
558
559#if defined(__rtems__)
560u_char ether_ipmulticast_min[6] = 
561        { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
562u_char ether_ipmulticast_max[6] =
563        { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
564#else
565static u_char ether_ipmulticast_min[6] = 
566        { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
567static u_char ether_ipmulticast_max[6] =
568        { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
569#endif
570
571/*
572 * Add an Ethernet multicast address or range of addresses to the list for a
573 * given interface.
574 */
575int
576ether_addmulti(struct ifreq *ifr, struct arpcom *ac)
577{
578        register struct ether_multi *enm;
579        struct sockaddr_in *sin;
580        u_char addrlo[6];
581        u_char addrhi[6];
582        int set_allmulti = 0;
583        int s = splimp();
584
585        switch (ifr->ifr_addr.sa_family) {
586
587        case AF_UNSPEC:
588                bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
589                bcopy(addrlo, addrhi, 6);
590                break;
591
592#ifdef INET
593        case AF_INET:
594                sin = (struct sockaddr_in *)&(ifr->ifr_addr);
595                if (sin->sin_addr.s_addr == INADDR_ANY) {
596                        /*
597                         * An IP address of INADDR_ANY means listen to all
598                         * of the Ethernet multicast addresses used for IP.
599                         * (This is for the sake of IP multicast routers.)
600                         */
601                        bcopy(ether_ipmulticast_min, addrlo, 6);
602                        bcopy(ether_ipmulticast_max, addrhi, 6);
603                      set_allmulti = 1;
604                }
605                else {
606                        ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
607                        bcopy(addrlo, addrhi, 6);
608                }
609                break;
610#endif
611
612        default:
613                splx(s);
614                return (EAFNOSUPPORT);
615        }
616
617        /*
618         * Verify that we have valid Ethernet multicast addresses.
619         */
620        if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
621                splx(s);
622                return (EINVAL);
623        }
624        /*
625         * See if the address range is already in the list.
626         */
627        ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
628        if (enm != NULL) {
629                /*
630                 * Found it; just increment the reference count.
631                 */
632                ++enm->enm_refcount;
633                splx(s);
634                return (0);
635        }
636        /*
637         * New address or range; malloc a new multicast record
638         * and link it into the interface's multicast list.
639         */
640        enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
641        if (enm == NULL) {
642                splx(s);
643                return (ENOBUFS);
644        }
645        bcopy(addrlo, enm->enm_addrlo, 6);
646        bcopy(addrhi, enm->enm_addrhi, 6);
647        enm->enm_ac = ac;
648        enm->enm_refcount = 1;
649        enm->enm_next = ac->ac_multiaddrs;
650        ac->ac_multiaddrs = enm;
651        ac->ac_multicnt++;
652        splx(s);
653        if (set_allmulti)
654                ac->ac_if.if_flags |= IFF_ALLMULTI;
655
656        /*
657         * Return ENETRESET to inform the driver that the list has changed
658         * and its reception filter should be adjusted accordingly.
659         */
660        return (ENETRESET);
661}
662
663/*
664 * Delete a multicast address record.
665 */
666int
667ether_delmulti(struct ifreq *ifr, struct arpcom *ac)
668{
669        register struct ether_multi *enm;
670        register struct ether_multi **p;
671        struct sockaddr_in *sin;
672        u_char addrlo[6];
673        u_char addrhi[6];
674      int unset_allmulti = 0;
675        int s = splimp();
676
677        switch (ifr->ifr_addr.sa_family) {
678
679        case AF_UNSPEC:
680                bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
681                bcopy(addrlo, addrhi, 6);
682                break;
683
684#ifdef INET
685        case AF_INET:
686                sin = (struct sockaddr_in *)&(ifr->ifr_addr);
687                if (sin->sin_addr.s_addr == INADDR_ANY) {
688                        /*
689                         * An IP address of INADDR_ANY means stop listening
690                         * to the range of Ethernet multicast addresses used
691                         * for IP.
692                         */
693                        bcopy(ether_ipmulticast_min, addrlo, 6);
694                        bcopy(ether_ipmulticast_max, addrhi, 6);
695                      unset_allmulti = 1;
696                }
697                else {
698                        ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
699                        bcopy(addrlo, addrhi, 6);
700                }
701                break;
702#endif
703
704        default:
705                splx(s);
706                return (EAFNOSUPPORT);
707        }
708
709        /*
710         * Look up the address in our list.
711         */
712        ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
713        if (enm == NULL) {
714                splx(s);
715                return (ENXIO);
716        }
717        if (--enm->enm_refcount != 0) {
718                /*
719                 * Still some claims to this record.
720                 */
721                splx(s);
722                return (0);
723        }
724        /*
725         * No remaining claims to this record; unlink and free it.
726         */
727        for (p = &enm->enm_ac->ac_multiaddrs;
728             *p != enm;
729             p = &(*p)->enm_next)
730                continue;
731        *p = (*p)->enm_next;
732        free(enm, M_IFMADDR);
733        ac->ac_multicnt--;
734        splx(s);
735      if (unset_allmulti)
736              ac->ac_if.if_flags &= ~IFF_ALLMULTI;
737
738        /*
739         * Return ENETRESET to inform the driver that the list has changed
740         * and its reception filter should be adjusted accordingly.
741         */
742        return (ENETRESET);
743}
744
745SYSCTL_DECL(_net_link);
746SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet");
747
748#if 0
749/*
750 * This is for reference.  We have a table-driven version
751 * of the little-endian crc32 generator, which is faster
752 * than the double-loop.
753 */
754uint32_t
755ether_crc32_le(const uint8_t *buf, size_t len)
756{
757        size_t i;
758        uint32_t crc;
759        int bit;
760        uint8_t data;
761
762        crc = 0xffffffff;       /* initial value */
763
764        for (i = 0; i < len; i++) {
765                for (data = *buf++, bit = 0; bit < 8; bit++, data >>= 1)
766                        carry = (crc ^ data) & 1;
767                        crc >>= 1;
768                        if (carry)
769                                crc = (crc ^ ETHER_CRC_POLY_LE);
770        }
771
772        return (crc);
773}
774#else
775uint32_t
776ether_crc32_le(const uint8_t *buf, size_t len)
777{
778        static const uint32_t crctab[] = {
779                0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
780                0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
781                0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
782                0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
783        };
784        size_t i;
785        uint32_t crc;
786
787        crc = 0xffffffff;       /* initial value */
788
789        for (i = 0; i < len; i++) {
790                crc ^= buf[i];
791                crc = (crc >> 4) ^ crctab[crc & 0xf];
792                crc = (crc >> 4) ^ crctab[crc & 0xf];
793        }
794
795        return (crc);
796}
797#endif
798
799uint32_t
800ether_crc32_be(const uint8_t *buf, size_t len)
801{
802        size_t i;
803        uint32_t crc, carry;
804        int bit;
805        uint8_t data;
806
807        crc = 0xffffffff;       /* initial value */
808
809        for (i = 0; i < len; i++) {
810                for (data = *buf++, bit = 0; bit < 8; bit++, data >>= 1) {
811                        carry = ((crc & 0x80000000) ? 1 : 0) ^ (data & 0x01);
812                        crc <<= 1;
813                        if (carry)
814                                crc = (crc ^ ETHER_CRC_POLY_BE) | carry;
815                }
816        }
817
818        return (crc);
819}
820
821int
822ether_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data)
823{
824        struct ifaddr *ifa = (struct ifaddr *) data;
825        struct ifreq *ifr = (struct ifreq *) data;
826        int error = 0;
827
828        switch (command) {
829        case SIOCSIFADDR:
830                ifp->if_flags |= IFF_UP;
831
832                switch (ifa->ifa_addr->sa_family) {
833#ifdef INET
834                case AF_INET:
835                        ifp->if_init(ifp->if_softc);    /* before arpwhohas */
836                        arp_ifinit((struct arpcom *)ifp, ifa);
837                        break;
838#endif
839#ifdef IPX
840                /*
841                 * XXX - This code is probably wrong
842                 */
843                case AF_IPX:
844                        {
845                        struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
846                        struct arpcom *ac = (struct arpcom *) (ifp->if_softc);
847
848                        if (ipx_nullhost(*ina))
849                                ina->x_host =
850                                    *(union ipx_host *) 
851                                    ac->ac_enaddr;
852                        else {
853                                bcopy((caddr_t) ina->x_host.c_host,
854                                      (caddr_t) ac->ac_enaddr,
855                                      sizeof(ac->ac_enaddr));
856                        }
857
858                        /*
859                         * Set new address
860                         */
861                        ifp->if_init(ifp->if_softc);
862                        break;
863                        }
864#endif
865                default:
866                        ifp->if_init(ifp->if_softc);
867                        break;
868                }
869                break;
870
871        case SIOCGIFADDR:
872                {
873                        struct sockaddr *sa;
874
875                        sa = (struct sockaddr *) & ifr->ifr_data;
876                        bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr,
877                              (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
878                }
879                break;
880
881        case SIOCSIFMTU:
882                /*
883                 * Set the interface MTU.
884                 */
885                if (ifr->ifr_mtu > ETHERMTU) {
886                        error = EINVAL;
887                } else {
888                        ifp->if_mtu = ifr->ifr_mtu;
889                }
890                break;
891        default:
892                error = EINVAL;                 /* XXX netbsd has ENOTTY??? */
893                break;
894        }
895        return (error);
896}
Note: See TracBrowser for help on using the repository browser.