source: rtems/c/src/exec/libnetworking/net/if_ethersubr.c @ a3d0b8a

4.104.114.84.9
Last change on this file since a3d0b8a was a3d0b8a, checked in by Joel Sherrill <joel.sherrill@…>, on Dec 10, 1998 at 7:42:29 PM

Patch from Ian Lance Taylor <ian@…>:

From: Eric Norum <eric@…>
Date: Sat, 5 Dec 98 13:20:51 -0600

What do you think of this patch? It implements your `tap'
suggestion in a way that adds support for all ethernet devices with
no driver modifications. I also added a return value from the tap
function. If the return value is zero, the packet will be passed up
the chain as usual. If the return value is non-zero the mbuf holding
the packet will be freed and the packet will be dropped.

If you like it, please submit it to Joel.

I guess there needs to be an addition to the network documentation
describing the additional ioctl's -- and a big warning that the tap
function is called from a context that holds the network semaphore.

Here is Eric's patch. I've tested it a bit, and made a couple of
trivial changes. This is certainly better than mine: it should work
for all Ethernet drivers.
==================================================

The only concern I have about this patch is that the tap function may
want to fiddle with the mbuf, calling functions like m_pullup and the
like. If those force the networking code to rearrange the mbuf
structure, then the caller's call to m_freem may crash. I don't know
if this is a realistic concern--I don't know enough about the mbuf
layer.

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