]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/tcpip/v2_0/src/sys/net/if_ethersubr.c
Initial revision
[karo-tx-redboot.git] / packages / net / tcpip / v2_0 / src / sys / net / if_ethersubr.c
1 //==========================================================================
2 //
3 //      sys/net/if_ethersubr.c
4 //
5 //     
6 //
7 //==========================================================================
8 //####BSDCOPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 //
12 // Portions of this software may have been derived from OpenBSD or other sources,
13 // and are covered by the appropriate copyright disclaimers included herein.
14 //
15 // -------------------------------------------
16 //
17 //####BSDCOPYRIGHTEND####
18 //==========================================================================
19 //#####DESCRIPTIONBEGIN####
20 //
21 // Author(s):    gthomas
22 // Contributors: gthomas
23 // Date:         2000-01-10
24 // Purpose:      
25 // Description:  
26 //              
27 //
28 //####DESCRIPTIONEND####
29 //
30 //==========================================================================
31
32
33 /*      $OpenBSD: if_ethersubr.c,v 1.32 1999/12/08 06:50:17 itojun Exp $        */
34 /*      $NetBSD: if_ethersubr.c,v 1.19 1996/05/07 02:40:30 thorpej Exp $        */
35
36 /*
37  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
38  * All rights reserved.
39  * 
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  * 3. Neither the name of the project nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  * 
52  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  */
64
65 /*
66  * Copyright (c) 1982, 1989, 1993
67  *      The Regents of the University of California.  All rights reserved.
68  *
69  * Redistribution and use in source and binary forms, with or without
70  * modification, are permitted provided that the following conditions
71  * are met:
72  * 1. Redistributions of source code must retain the above copyright
73  *    notice, this list of conditions and the following disclaimer.
74  * 2. Redistributions in binary form must reproduce the above copyright
75  *    notice, this list of conditions and the following disclaimer in the
76  *    documentation and/or other materials provided with the distribution.
77  * 3. All advertising materials mentioning features or use of this software
78  *    must display the following acknowledgement:
79  *      This product includes software developed by the University of
80  *      California, Berkeley and its contributors.
81  * 4. Neither the name of the University nor the names of its contributors
82  *    may be used to endorse or promote products derived from this software
83  *    without specific prior written permission.
84  *
85  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
86  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
87  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
88  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
89  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
90  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
91  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
92  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
93  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
94  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95  * SUCH DAMAGE.
96  *
97  *      @(#)if_ethersubr.c      8.1 (Berkeley) 6/10/93
98  */
99
100 /*
101 %%% portions-copyright-nrl-95
102 Portions of this software are Copyright 1995-1998 by Randall Atkinson,
103 Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights
104 Reserved. All rights under this copyright have been assigned to the US
105 Naval Research Laboratory (NRL). The NRL Copyright Notice and License
106 Agreement Version 1.1 (January 17, 1995) applies to these portions of the
107 software.
108 You should have received a copy of the license with this software. If you
109 didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
110 */
111
112 #include <sys/param.h>
113 #ifndef __ECOS
114 #include <sys/systm.h>
115 #endif
116 #include <sys/kernel.h>
117 #include <sys/malloc.h>
118 #include <sys/mbuf.h>
119 #include <sys/protosw.h>
120 #include <sys/socket.h>
121 #include <sys/ioctl.h>
122 #include <sys/errno.h>
123 #ifndef __ECOS
124 #include <sys/syslog.h>
125 #endif
126
127 #include <machine/cpu.h>
128
129 #include <net/if.h>
130 #include <net/netisr.h>
131 #include <net/route.h>
132 #include <net/if_llc.h>
133 #include <net/if_dl.h>
134 #include <net/if_types.h>
135
136 #include <netinet/in.h>
137 #ifdef INET
138 #include <netinet/in_var.h>
139 #endif
140 #include <netinet/if_ether.h>
141
142 #ifndef __ECOS
143 #include "bridge.h"
144 #endif
145 #if NBRIDGE > 0
146 #include <net/if_bridge.h>
147 #endif
148
149 #ifdef INET6
150 #ifndef INET
151 #include <netinet/in.h>
152 #endif
153 #include <netinet6/in6_var.h>
154 #include <netinet6/nd6.h>
155 #endif
156
157 #ifdef NS
158 #include <netns/ns.h>
159 #include <netns/ns_if.h>
160 #endif
161
162 #ifdef IPX
163 #include <netipx/ipx.h>
164 #include <netipx/ipx_if.h>
165 #endif
166
167 #ifdef ISO
168 #include <netiso/argo_debug.h>
169 #include <netiso/iso.h>
170 #include <netiso/iso_var.h>
171 #include <netiso/iso_snpac.h>
172 #endif
173
174 #ifdef CCITT
175 #include <netccitt/x25.h>
176 #include <netccitt/pk.h>
177 #include <netccitt/pk_extern.h>
178 #include <netccitt/dll.h>
179 #include <netccitt/llc_var.h>
180 #endif
181
182 #ifdef NETATALK
183 #include <netatalk/at.h>
184 #include <netatalk/at_var.h>
185 #include <netatalk/at_extern.h>
186
187 #define llc_snap_org_code llc_un.type_snap.org_code
188 #define llc_snap_ether_type llc_un.type_snap.ether_type
189
190 extern u_char   at_org_code[ 3 ];
191 extern u_char   aarp_org_code[ 3 ];
192 #endif /* NETATALK */
193
194 #if defined(CCITT)
195 #include <sys/socketvar.h>
196 #endif
197
198 #if 0   /*NRL INET6*/
199 #include <netinet6/in6.h>
200 #include <netinet6/in6_var.h>
201 #endif /* INET6 */
202
203 u_char  etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
204 #define senderr(e) { error = (e); goto bad;}
205
206
207 int
208 ether_ioctl(ifp, arp, cmd, data)
209         register struct ifnet *ifp;
210         struct arpcom *arp;
211         u_long cmd;
212         caddr_t data;
213 {
214         struct ifaddr *ifa = (struct ifaddr *)data;
215         int     error = 0;
216
217         switch (cmd) {
218
219 #if defined(CCITT)
220         case SIOCSIFCONF_X25:
221                 ifp->if_flags |= IFF_UP;
222                 ifa->ifa_rtrequest = cons_rtrequest;
223                 error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
224                 break;
225 #endif /* CCITT */
226         case SIOCSIFADDR:
227                 switch (ifa->ifa_addr->sa_family) {
228 #ifdef IPX
229                 case AF_IPX:
230                     {
231                         struct ipx_addr *ina = &IA_SIPX(ifa)->sipx_addr;
232
233                         if (ipx_nullhost(*ina))
234                                 ina->ipx_host =
235                                     *(union ipx_host *)(arp->ac_enaddr);
236                         else
237                                 bcopy(ina->ipx_host.c_host,
238                                     arp->ac_enaddr, sizeof(arp->ac_enaddr));
239                         break;
240                     }
241 #endif /* IPX */
242 #ifdef NETATALK
243                 case AF_APPLETALK:
244                         /* Nothing to do. */
245                         break;
246 #endif /* NETATALK */
247 #ifdef NS
248                 /* XXX - This code is probably wrong. */
249                 case AF_NS:
250                     {
251                         struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
252
253                         if (ns_nullhost(*ina))
254                                 ina->x_host =
255                                     *(union ns_host *)(arp->ac_enaddr);
256                         else
257                                 bcopy(ina->x_host.c_host,
258                                     arp->ac_enaddr, sizeof(arp->ac_enaddr));
259                         break;
260                     }
261 #endif /* NS */
262                 }
263                 break;
264         default:
265                 break;
266         }
267
268         return error;
269 }
270
271 /*
272  * Ethernet output routine.
273  * Encapsulate a packet of type family for the local net.
274  * Assumes that ifp is actually pointer to arpcom structure.
275  */
276 int
277 ether_output(ifp, m0, dst, rt0)
278         register struct ifnet *ifp;
279         struct mbuf *m0;
280         struct sockaddr *dst;
281         struct rtentry *rt0;
282 {
283         u_int16_t etype;
284         int s, error = 0;
285         u_char edst[6];
286         register struct mbuf *m = m0;
287         register struct rtentry *rt;
288         struct mbuf *mcopy = (struct mbuf *)0;
289         register struct ether_header *eh;
290         struct arpcom *ac = (struct arpcom *)ifp;
291
292         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
293                 senderr(ENETDOWN);
294         ifp->if_lastchange = time;
295         if ((rt = rt0) != NULL) {
296                 if ((rt->rt_flags & RTF_UP) == 0) {
297                         if ((rt0 = rt = rtalloc1(dst, 1)) != NULL)
298                                 rt->rt_refcnt--;
299                         else
300                                 senderr(EHOSTUNREACH);
301                 }
302                 if (rt->rt_flags & RTF_GATEWAY) {
303                         if (rt->rt_gwroute == 0)
304                                 goto lookup;
305                         if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
306                                 rtfree(rt); rt = rt0;
307                         lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
308                                 if ((rt = rt->rt_gwroute) == 0)
309                                         senderr(EHOSTUNREACH);
310                         }
311                 }
312                 if (rt->rt_flags & RTF_REJECT)
313                         if (rt->rt_rmx.rmx_expire == 0 ||
314                             time.tv_sec < rt->rt_rmx.rmx_expire)
315                                 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
316         }
317         switch (dst->sa_family) {
318
319 #ifdef INET
320         case AF_INET:
321                 if (!arpresolve(ac, rt, m, dst, edst))
322                         return (0);     /* if not yet resolved */
323                 /* If broadcasting on a simplex interface, loopback a copy */
324                 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
325                         mcopy = m_copy(m, 0, (int)M_COPYALL);
326                 etype = htons(ETHERTYPE_IP);
327                 break;
328 #endif
329 #ifdef INET6
330         case AF_INET6:
331 #ifndef OLDIP6OUTPUT
332                 if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst))
333                         return(0); /* it must be impossible, but... */
334 #else
335                 if (!nd6_resolve(ifp, rt, m, dst, (u_char *)edst))
336                         return(0);      /* if not yet resolves */
337 #endif
338                 etype = htons(ETHERTYPE_IPV6);
339                 break;
340 #endif
341 #ifdef NS
342         case AF_NS:
343                 etype = htons(ETHERTYPE_NS);
344                 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
345                     (caddr_t)edst, sizeof (edst));
346                 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
347                         return (looutput(ifp, m, dst, rt));
348                 /* If broadcasting on a simplex interface, loopback a copy */
349                 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
350                         mcopy = m_copy(m, 0, (int)M_COPYALL);
351                 break;
352 #endif
353 #ifdef IPX
354         case AF_IPX:
355                 etype = htons(ETHERTYPE_IPX);
356                 bcopy((caddr_t)&satosipx(dst)->sipx_addr.ipx_host,
357                     (caddr_t)edst, sizeof (edst));
358                 if (!bcmp((caddr_t)edst, (caddr_t)&ipx_thishost, sizeof(edst)))
359                         return (looutput(ifp, m, dst, rt));
360                 /* If broadcasting on a simplex interface, loopback a copy */
361                 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
362                         mcopy = m_copy(m, 0, (int)M_COPYALL);
363                 break;
364 #endif
365 #if 0   /*NRL INET6*/
366         case AF_INET6:
367                 /*
368                  * The bottom line here is to either queue the outgoing packet
369                  * in the discovery engine, or fill in edst with something
370                  * that'll work.
371                  */
372                 if (m->m_flags & M_MCAST) {
373                         /*
374                          * If multicast dest., then use IPv6 -> Ethernet
375                          * mcast mapping.  Really simple.
376                          */
377                         ETHER_MAP_IPV6_MULTICAST(&((struct sockaddr_in6 *)dst)->sin6_addr,
378                             edst);
379                 } else {
380                         /* Do unicast neighbor discovery stuff. */
381                         if (!ipv6_discov_resolve(ifp, rt, m, dst, edst))
382                                 return 0;
383                 }
384                 etype = htons(ETHERTYPE_IPV6);
385                 break;
386 #endif /* INET6 */
387 #ifdef NETATALK
388         case AF_APPLETALK: {
389                 struct at_ifaddr *aa;
390
391                 if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) {
392 #ifdef NETATALKDEBUG
393                         extern char *prsockaddr(struct sockaddr *);
394                         printf("aarpresolv: failed for %s\n", prsockaddr(dst));
395 #endif /* NETATALKDEBUG */
396                         return (0);
397                 }
398
399                 /*
400                  * ifaddr is the first thing in at_ifaddr
401                  */
402                 aa = (struct at_ifaddr *)at_ifawithnet(
403                         (struct sockaddr_at *)dst,
404                         ifp->if_addrlist.tqh_first);
405                 if (aa == 0)
406                         goto bad;
407
408                 /*
409                  * In the phase 2 case, we need to prepend an mbuf for the llc
410                  * header. Since we must preserve the value of m, which is
411                  * passed to us by value, we m_copy() the first mbuf,
412                  * and use it for our llc header.
413                  */
414                 if ( aa->aa_flags & AFA_PHASE2 ) {
415                         struct llc llc;
416
417                         /* XXX Really this should use netisr too */
418                         M_PREPEND(m, AT_LLC_SIZE, M_WAIT);
419                         /*
420                          * FreeBSD doesn't count the LLC len in
421                          * ifp->obytes, so they increment a length
422                          * field here. We don't do this.
423                          */
424                         llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
425                         llc.llc_control = LLC_UI;
426                         bcopy(at_org_code, llc.llc_snap_org_code,
427                                 sizeof(at_org_code));
428                         llc.llc_snap_ether_type = htons( ETHERTYPE_AT );
429                         bcopy(&llc, mtod(m, caddr_t), AT_LLC_SIZE);
430                         etype = htons(m->m_pkthdr.len);
431                 } else {
432                         etype = htons(ETHERTYPE_AT);
433                 }
434                 } break;
435 #endif /* NETATALK */
436 #ifdef  ISO
437         case AF_ISO: {
438                 int     snpalen;
439                 struct  llc *l;
440                 register struct sockaddr_dl *sdl;
441
442                 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) &&
443                     sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) {
444                         bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst));
445                 } else {
446                         error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
447                                                 (char *)edst, &snpalen);
448                         if (error)
449                                 goto bad; /* Not Resolved */
450                 }
451                 /* If broadcasting on a simplex interface, loopback a copy */
452                 if (*edst & 1)
453                         m->m_flags |= (M_BCAST|M_MCAST);
454                 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
455                     (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
456                         M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
457                         if (mcopy) {
458                                 eh = mtod(mcopy, struct ether_header *);
459                                 bcopy(edst, eh->ether_dhost, sizeof (edst));
460                                 bcopy(ac->ac_enaddr, eh->ether_shost,
461                                     sizeof (edst));
462                         }
463                 }
464                 M_PREPEND(m, 3, M_DONTWAIT);
465                 if (m == NULL)
466                         return (0);
467                 etype = htons(m->m_pkthdr.len);
468                 l = mtod(m, struct llc *);
469                 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
470                 l->llc_control = LLC_UI;
471 #ifdef ARGO_DEBUG
472                 if (argo_debug[D_ETHER]) {
473                         int i;
474                         printf("unoutput: sending pkt to: ");
475                         for (i=0; i<6; i++)
476                                 printf("%x ", edst[i] & 0xff);
477                         printf("\n");
478                 }
479 #endif
480                 } break;
481 #endif /* ISO */
482 /*      case AF_NSAP: */
483         case AF_CCITT: {
484                 register struct sockaddr_dl *sdl =
485                         (struct sockaddr_dl *) rt -> rt_gateway;
486
487                 if (sdl && sdl->sdl_family == AF_LINK
488                     && sdl->sdl_alen > 0) {
489                         bcopy(LLADDR(sdl), (char *)edst,
490                                 sizeof(edst));
491                 } else goto bad; /* Not a link interface ? Funny ... */
492                 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
493                     (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
494                         M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
495                         if (mcopy) {
496                                 eh = mtod(mcopy, struct ether_header *);
497                                 bcopy(edst, eh->ether_dhost, sizeof (edst));
498                                 bcopy(ac->ac_enaddr, eh->ether_shost,
499                                     sizeof (edst));
500                         }
501                 }
502                 etype = htons(m->m_pkthdr.len);
503 #ifdef LLC_DEBUG
504                 {
505                         int i;
506                         register struct llc *l = mtod(m, struct llc *);
507
508                         printf("ether_output: sending LLC2 pkt to: ");
509                         for (i=0; i<6; i++)
510                                 printf("%x ", edst[i] & 0xff);
511                         printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n",
512                             m->m_pkthdr.len, l->llc_dsap & 0xff, l->llc_ssap &0xff,
513                             l->llc_control & 0xff);
514
515                 }
516 #endif /* LLC_DEBUG */
517                 } break;
518
519         case AF_UNSPEC:
520                 eh = (struct ether_header *)dst->sa_data;
521                 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
522                 /* AF_UNSPEC doesn't swap the byte order of the ether_type. */
523                 etype = eh->ether_type;
524                 break;
525
526         default:
527 #ifdef __ECOS
528 //              diag_printf("%s: can't handle af%d\n", ifp->if_xname,
529 //                            dst->sa_family);
530 #else
531                 printf("%s: can't handle af%d\n", ifp->if_xname,
532                         dst->sa_family);
533 #endif
534                 senderr(EAFNOSUPPORT);
535         }
536
537         if (mcopy)
538                 (void) looutput(ifp, mcopy, dst, rt);
539
540         /*
541          * Add local net header.  If no space in first mbuf,
542          * allocate another.
543          */
544         M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
545         if (m == 0)
546                 senderr(ENOBUFS);
547         eh = mtod(m, struct ether_header *);
548         bcopy((caddr_t)&etype,(caddr_t)&eh->ether_type,
549                 sizeof(eh->ether_type));
550         bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
551         bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
552             sizeof(eh->ether_shost));
553
554 #if NBRIDGE > 0
555         /*
556          * Interfaces that are bridge members need special handling
557          * for output.
558          */
559         if (ifp->if_bridge) {
560                 bridge_output(ifp, m, NULL, NULL);
561                 return (error);
562         }
563 #endif
564
565         s = splimp();
566         /*
567          * Queue message on interface, and start output if interface
568          * not yet active.
569          */
570         if (IF_QFULL(&ifp->if_snd)) {
571                 // Let the interface try a dequeue anyway, in case the
572                 // interface has "got better" from whatever made the queue
573                 // fill up - being unplugged for example.
574                 if ((ifp->if_flags & IFF_OACTIVE) == 0)
575                     (*ifp->if_start)(ifp);
576                 IF_DROP(&ifp->if_snd);
577                 splx(s);
578                 senderr(ENOBUFS);
579         }
580         ifp->if_obytes += m->m_pkthdr.len;
581         IF_ENQUEUE(&ifp->if_snd, m);
582         if (m->m_flags & M_MCAST)
583                 ifp->if_omcasts++;
584         if ((ifp->if_flags & IFF_OACTIVE) == 0)
585                 (*ifp->if_start)(ifp);
586         splx(s);
587         return (error);
588
589 bad:
590         if (m)
591                 m_freem(m);
592         return (error);
593 }
594
595 /*
596  * Process a received Ethernet packet;
597  * the packet is in the mbuf chain m without
598  * the ether header, which is provided separately.
599  */
600 void
601 ether_input(ifp, eh, m)
602         struct ifnet *ifp;
603         register struct ether_header *eh;
604         struct mbuf *m;
605 {
606         register struct ifqueue *inq;
607         u_int16_t etype;
608         int s, llcfound = 0;
609         register struct llc *l;
610         struct arpcom *ac = (struct arpcom *)ifp;
611 #ifdef __ECOS
612         unsigned int sched_what;
613 #endif
614
615         if ((ifp->if_flags & IFF_UP) == 0) {
616                 m_freem(m);
617                 return;
618         }
619         ifp->if_lastchange = time;
620         ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
621         if (eh->ether_dhost[0] & 1) {
622                 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
623                     sizeof(etherbroadcastaddr)) == 0)
624                         m->m_flags |= M_BCAST;
625                 else
626                         m->m_flags |= M_MCAST;
627         }
628         if (m->m_flags & (M_BCAST|M_MCAST))
629                 ifp->if_imcasts++;
630
631 #if NBRIDGE > 0
632         /*
633          * Tap the packet off here for a bridge, if configured and
634          * active for this interface.  bridge_input returns
635          * NULL if it has consumed the packet, otherwise, it
636          * gets processed as normal.
637          */
638         if (ifp->if_bridge) {
639                 m = bridge_input(ifp, eh, m);
640                 if (m == NULL)
641                         return;
642                 /* The bridge has determined it's for us. */
643                 goto decapsulate;
644         }
645 #endif
646         /*
647          * If packet is unicast and we're in promiscuous mode, make sure it
648          * is for us.  Drop otherwise.
649          */
650         if ((m->m_flags & (M_BCAST|M_MCAST)) == 0 &&
651             (ifp->if_flags & IFF_PROMISC)) {
652                 if (bcmp(ac->ac_enaddr, (caddr_t)eh->ether_dhost,
653                     ETHER_ADDR_LEN)) {
654                         m_freem(m);
655                         return;
656                 }
657         }
658
659 decapsulate:
660         etype = ntohs(eh->ether_type);
661         switch (etype) {
662 #ifdef INET
663         case ETHERTYPE_IP:
664 #ifdef __ECOS
665                 sched_what = NETISR_IP;
666 #else
667                 schednetisr(NETISR_IP);
668 #endif
669                 inq = &ipintrq;
670                 break;
671
672         case ETHERTYPE_ARP:
673                 if (ifp->if_flags & IFF_NOARP)
674                         goto dropanyway;
675 #ifdef __ECOS
676                 sched_what = NETISR_ARP;
677 #else
678                 schednetisr(NETISR_ARP);
679 #endif
680                 inq = &arpintrq;
681                 break;
682
683         case ETHERTYPE_REVARP:
684                 if (ifp->if_flags & IFF_NOARP)
685                         goto dropanyway;
686                 revarpinput(m); /* XXX queue? */
687                 return;
688
689 #endif
690 #ifdef INET6
691         /*
692          * Schedule IPv6 software interrupt for incoming IPv6 packet.
693          */
694         case ETHERTYPE_IPV6:
695 #ifdef __ECOS
696                 sched_what = NETISR_IPV6;
697 #else
698                 schednetisr(NETISR_IPV6);
699 #endif
700                 inq = &ip6intrq;
701                 break;
702 #endif /* INET6 */
703 #ifdef IPX
704         case ETHERTYPE_IPX:
705 #ifdef __ECOS
706                 sched_what = NETISR_IPX;
707 #else
708                 schednetisr(NETISR_IPX);
709 #endif
710                 inq = &ipxintrq;
711                 break;
712 #endif
713 #ifdef NS
714         case ETHERTYPE_NS:
715 #ifdef __ECOS
716                 sched_what = NETISR_NS;
717 #else
718                 schednetisr(NETISR_NS);
719 #endif
720                 inq = &nsintrq;
721                 break;
722 #endif
723 #ifdef NETATALK
724         case ETHERTYPE_AT:
725 #ifdef __ECOS
726                 sched_what = NETISR_ATALK;
727 #else
728                 schednetisr(NETISR_ATALK);
729 #endif
730                 inq = &atintrq1;
731                 break;
732         case ETHERTYPE_AARP:
733                 /* probably this should be done with a NETISR as well */
734                 /* XXX queue this */
735                 aarpinput((struct arpcom *)ifp, m);
736                 return;
737 #endif
738         default:
739                 if (llcfound || etype > ETHERMTU)
740                         goto dropanyway;
741                 llcfound = 1;
742                 l = mtod(m, struct llc *);
743                 switch (l->llc_dsap) {
744                 case LLC_SNAP_LSAP:
745 #ifdef NETATALK
746                         /*
747                          * Some protocols (like Appletalk) need special
748                          * handling depending on if they are type II
749                          * or SNAP encapsulated. Everything else
750                          * gets handled by stripping off the SNAP header
751                          * and going back up to decapsulate.
752                          */
753                         if (l->llc_control == LLC_UI &&
754                             l->llc_ssap == LLC_SNAP_LSAP &&
755                             Bcmp(&(l->llc_snap_org_code)[0],
756                             at_org_code, sizeof(at_org_code)) == 0 &&
757                             ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) {
758                                 inq = &atintrq2;
759                                 m_adj(m, AT_LLC_SIZE);
760 #ifdef __ECOS
761                                 sched_what = NETISR_ATALK;
762 #else
763                                 schednetisr(NETISR_ATALK);
764 #endif
765                                 break;
766                         }
767
768                         if (l->llc_control == LLC_UI &&
769                             l->llc_ssap == LLC_SNAP_LSAP &&
770                             Bcmp(&(l->llc_snap_org_code)[0],
771                             aarp_org_code, sizeof(aarp_org_code)) == 0 &&
772                             ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) {
773                                 m_adj(m, AT_LLC_SIZE);
774                                 /* XXX Really this should use netisr too */
775                                 aarpinput((struct arpcom *)ifp, m);
776                                 return;
777                         }
778 #endif /* NETATALK */
779                         if (l->llc_control == LLC_UI &&
780                             l->llc_dsap == LLC_SNAP_LSAP &&
781                             l->llc_ssap == LLC_SNAP_LSAP) {
782                                 /* SNAP */
783                                 if (m->m_pkthdr.len > etype)
784                                         m_adj(m, etype - m->m_pkthdr.len);
785                                 m->m_data += 6;         /* XXX */
786                                 m->m_len -= 6;          /* XXX */
787                                 m->m_pkthdr.len -= 6;   /* XXX */
788                                 M_PREPEND(m, sizeof *eh, M_DONTWAIT);
789                                 if (m == 0)
790                                         return;
791                                 *mtod(m, struct ether_header *) = *eh;
792                                 goto decapsulate;
793                         }
794                         goto dropanyway;
795 #ifdef  ISO
796                 case LLC_ISO_LSAP:
797                         switch (l->llc_control) {
798                         case LLC_UI:
799                                 /* LLC_UI_P forbidden in class 1 service */
800                                 if ((l->llc_dsap == LLC_ISO_LSAP) &&
801                                     (l->llc_ssap == LLC_ISO_LSAP)) {
802                                         /* LSAP for ISO */
803                                         if (m->m_pkthdr.len > etype)
804                                                 m_adj(m, etype - m->m_pkthdr.len);
805                                         m->m_data += 3;         /* XXX */
806                                         m->m_len -= 3;          /* XXX */
807                                         m->m_pkthdr.len -= 3;   /* XXX */
808                                         M_PREPEND(m, sizeof *eh, M_DONTWAIT);
809                                         if (m == 0)
810                                                 return;
811                                         *mtod(m, struct ether_header *) = *eh;
812 #ifdef ARGO_DEBUG
813                                         if (argo_debug[D_ETHER])
814                                                 printf("clnp packet");
815 #endif
816 #ifdef __ECOS
817                                         sched_what = NETISR_ISO;
818 #else
819                                         schednetisr(NETISR_ISO);
820 #endif
821                                         inq = &clnlintrq;
822                                         break;
823                                 }
824                                 goto dropanyway;
825
826                         case LLC_XID:
827                         case LLC_XID_P:
828                                 if(m->m_len < 6)
829                                         goto dropanyway;
830                                 l->llc_window = 0;
831                                 l->llc_fid = 9;
832                                 l->llc_class = 1;
833                                 l->llc_dsap = l->llc_ssap = 0;
834                                 /* Fall through to */
835                         case LLC_TEST:
836                         case LLC_TEST_P:
837                         {
838                                 struct sockaddr sa;
839                                 register struct ether_header *eh2;
840                                 int i;
841                                 u_char c = l->llc_dsap;
842
843                                 l->llc_dsap = l->llc_ssap;
844                                 l->llc_ssap = c;
845                                 if (m->m_flags & (M_BCAST | M_MCAST))
846                                         bcopy(ac->ac_enaddr,
847                                             eh->ether_dhost, 6);
848                                 sa.sa_family = AF_UNSPEC;
849                                 sa.sa_len = sizeof(sa);
850                                 eh2 = (struct ether_header *)sa.sa_data;
851                                 for (i = 0; i < 6; i++) {
852                                         eh2->ether_shost[i] = c = eh->ether_dhost[i];
853                                         eh2->ether_dhost[i] =
854                                                 eh->ether_dhost[i] = eh->ether_shost[i];
855                                         eh->ether_shost[i] = c;
856                                 }
857                                 ifp->if_output(ifp, m, &sa, NULL);
858                                 return;
859                         }
860                         break;
861                         }
862 #endif /* ISO */
863 #ifdef CCITT
864                 case LLC_X25_LSAP:
865                         if (m->m_pkthdr.len > etype)
866                                 m_adj(m, etype - m->m_pkthdr.len);
867                         M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT);
868                         if (m == 0)
869                                 return;
870                         if (!sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP,
871                             eh->ether_dhost, LLC_X25_LSAP, 6,
872                             mtod(m, struct sdl_hdr *)))
873                                 panic("ETHER cons addr failure");
874                         mtod(m, struct sdl_hdr *)->sdlhdr_len = etype;
875 #ifdef LLC_DEBUG
876                         printf("llc packet\n");
877 #endif /* LLC_DEBUG */
878 #ifdef __ECOS
879                         sched_what = NETISR_CCITT;
880 #else
881                         schednetisr(NETISR_CCITT);
882 #endif
883                         inq = &llcintrq;
884                         break;
885 #endif /* CCITT */
886                 dropanyway:
887                 default:
888                         m_freem(m);
889                         return;
890                 }
891         }
892
893         s = splimp();
894         if (IF_QFULL(inq)) {
895                 IF_DROP(inq);
896                 m_freem(m);
897         } else
898                 IF_ENQUEUE(inq, m);
899         splx(s);
900 #ifdef __ECOS
901         schednetisr(sched_what);
902 #endif
903 }
904
905 /*
906  * Convert Ethernet address to printable (loggable) representation.
907  */
908 static char digits[] = "0123456789abcdef";
909 char *
910 ether_sprintf(ap)
911         register u_char *ap;
912 {
913         register int i;
914         static char etherbuf[18];
915         register char *cp = etherbuf;
916
917         for (i = 0; i < 6; i++) {
918                 *cp++ = digits[*ap >> 4];
919                 *cp++ = digits[*ap++ & 0xf];
920                 *cp++ = ':';
921         }
922         *--cp = 0;
923         return (etherbuf);
924 }
925
926 /*
927  * Perform common duties while attaching to interface list
928  */
929 void
930 ether_ifattach(ifp)
931         register struct ifnet *ifp;
932 {
933         register struct ifaddr *ifa;
934         register struct sockaddr_dl *sdl;
935
936         ifp->if_type = IFT_ETHER;
937         ifp->if_addrlen = 6;
938         ifp->if_hdrlen = 14;
939         ifp->if_mtu = ETHERMTU;
940         ifp->if_output = ether_output;
941         for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
942             ifa = ifa->ifa_list.tqe_next)
943                 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
944                     sdl->sdl_family == AF_LINK) {
945                         sdl->sdl_type = IFT_ETHER;
946                         sdl->sdl_alen = ifp->if_addrlen;
947                         bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
948                             LLADDR(sdl), ifp->if_addrlen);
949                         break;
950                 }
951         LIST_INIT(&((struct arpcom *)ifp)->ac_multiaddrs);
952 }
953
954 void
955 ether_ifdetach(ifp)
956         struct ifnet *ifp;
957 {
958         struct arpcom *ac = (struct arpcom *)ifp;
959         struct ether_multi *enm;
960
961         for (enm = LIST_FIRST(&ac->ac_multiaddrs); enm;
962             enm = LIST_FIRST(&ac->ac_multiaddrs)) {
963                 LIST_REMOVE(enm, enm_list);
964                 free(enm, M_IFMADDR);
965         }
966 }
967
968 u_char  ether_ipmulticast_min[6] = { 0x01, 0x00, 0x5e, 0x00, 0x00, 0x00 };
969 u_char  ether_ipmulticast_max[6] = { 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xff };
970
971 #ifdef INET6
972 u_char  ether_ip6multicast_min[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 };
973 u_char  ether_ip6multicast_max[6] = { 0x33, 0x33, 0xff, 0xff, 0xff, 0xff };
974 #endif
975
976 /*
977  * Add an Ethernet multicast address or range of addresses to the list for a
978  * given interface.
979  */
980 int
981 ether_addmulti(ifr, ac)
982         struct ifreq *ifr;
983         register struct arpcom *ac;
984 {
985         register struct ether_multi *enm;
986         struct sockaddr_in *sin;
987 #ifdef INET6
988         struct sockaddr_in6 *sin6;
989 #endif /* INET6 */
990         u_char addrlo[6];
991         u_char addrhi[6];
992         int s = splimp();
993
994         switch (ifr->ifr_addr.sa_family) {
995
996         case AF_UNSPEC:
997                 bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
998                 bcopy(addrlo, addrhi, 6);
999                 break;
1000
1001 #ifdef INET
1002         case AF_INET:
1003                 sin = (struct sockaddr_in *)&(ifr->ifr_addr);
1004                 if (sin->sin_addr.s_addr == INADDR_ANY) {
1005                         /*
1006                          * An IP address of INADDR_ANY means listen to all
1007                          * of the Ethernet multicast addresses used for IP.
1008                          * (This is for the sake of IP multicast routers.)
1009                          */
1010                         bcopy(ether_ipmulticast_min, addrlo, 6);
1011                         bcopy(ether_ipmulticast_max, addrhi, 6);
1012                 }
1013                 else {
1014                         ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
1015                         bcopy(addrlo, addrhi, 6);
1016                 }
1017                 break;
1018 #endif
1019 #ifdef INET6
1020         case AF_INET6:
1021                 sin6 = (struct sockaddr_in6 *)
1022                         &(((struct in6_ifreq *)ifr)->ifr_addr);
1023                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1024                         /*
1025                          * An unspecified IPv6 address means listen to all
1026                          * of the IPv6 multicast addresses on this Ethernet.
1027                          * (Multicast routers like this.)
1028                          */
1029                         bcopy(ether_ip6multicast_min, addrlo, ETHER_ADDR_LEN);
1030                         bcopy(ether_ip6multicast_max, addrhi, ETHER_ADDR_LEN);
1031                 } else {
1032                         ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, addrlo);
1033                         bcopy(addrlo, addrhi, ETHER_ADDR_LEN);
1034                 }
1035                 break;
1036 #endif /* INET6 */
1037
1038         default:
1039                 splx(s);
1040                 return (EAFNOSUPPORT);
1041         }
1042
1043         /*
1044          * Verify that we have valid Ethernet multicast addresses.
1045          */
1046         if ((addrlo[0] & 0x01) != 1 || (addrhi[0] & 0x01) != 1) {
1047                 splx(s);
1048                 return (EINVAL);
1049         }
1050         /*
1051          * See if the address range is already in the list.
1052          */
1053         ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
1054         if (enm != NULL) {
1055                 /*
1056                  * Found it; just increment the reference count.
1057                  */
1058                 ++enm->enm_refcount;
1059                 splx(s);
1060                 return (0);
1061         }
1062         /*
1063          * New address or range; malloc a new multicast record
1064          * and link it into the interface's multicast list.
1065          */
1066         enm = (struct ether_multi *)malloc(sizeof(*enm), M_IFMADDR, M_NOWAIT);
1067         if (enm == NULL) {
1068                 splx(s);
1069                 return (ENOBUFS);
1070         }
1071         bcopy(addrlo, enm->enm_addrlo, 6);
1072         bcopy(addrhi, enm->enm_addrhi, 6);
1073         enm->enm_ac = ac;
1074         enm->enm_refcount = 1;
1075         LIST_INSERT_HEAD(&ac->ac_multiaddrs, enm, enm_list);
1076         ac->ac_multicnt++;
1077         splx(s);
1078         /*
1079          * Return ENETRESET to inform the driver that the list has changed
1080          * and its reception filter should be adjusted accordingly.
1081          */
1082         return (ENETRESET);
1083 }
1084
1085 /*
1086  * Delete a multicast address record.
1087  */
1088 int
1089 ether_delmulti(ifr, ac)
1090         struct ifreq *ifr;
1091         register struct arpcom *ac;
1092 {
1093         register struct ether_multi *enm;
1094         struct sockaddr_in *sin;
1095 #ifdef INET6
1096         struct sockaddr_in6 *sin6;
1097 #endif /* INET6 */
1098         u_char addrlo[6];
1099         u_char addrhi[6];
1100         int s = splimp();
1101
1102         switch (ifr->ifr_addr.sa_family) {
1103
1104         case AF_UNSPEC:
1105                 bcopy(ifr->ifr_addr.sa_data, addrlo, 6);
1106                 bcopy(addrlo, addrhi, 6);
1107                 break;
1108
1109 #ifdef INET
1110         case AF_INET:
1111                 sin = (struct sockaddr_in *)&(ifr->ifr_addr);
1112                 if (sin->sin_addr.s_addr == INADDR_ANY) {
1113                         /*
1114                          * An IP address of INADDR_ANY means stop listening
1115                          * to the range of Ethernet multicast addresses used
1116                          * for IP.
1117                          */
1118                         bcopy(ether_ipmulticast_min, addrlo, 6);
1119                         bcopy(ether_ipmulticast_max, addrhi, 6);
1120                 }
1121                 else {
1122                         ETHER_MAP_IP_MULTICAST(&sin->sin_addr, addrlo);
1123                         bcopy(addrlo, addrhi, 6);
1124                 }
1125                 break;
1126 #endif
1127 #ifdef INET6
1128         case AF_INET6:
1129                 sin6 = (struct sockaddr_in6 *)&(ifr->ifr_addr);
1130                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
1131                         /*
1132                          * An unspecified IPv6 address means stop listening to
1133                          * all IPv6 multicast addresses on this Ethernet.'
1134                          *
1135                          * (This might not be healthy, given IPv6's reliance on
1136                          * multicast for things like neighbor discovery.
1137                          * Perhaps initializing all-nodes, solicited nodes, and
1138                          * possibly all-routers for this interface afterwards
1139                          * is not a bad idea.)
1140                          */
1141                         bcopy(ether_ip6multicast_min, addrlo, ETHER_ADDR_LEN);
1142                         bcopy(ether_ip6multicast_max, addrhi, ETHER_ADDR_LEN);
1143                 } else {
1144                         ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, addrlo);
1145                         bcopy(addrlo, addrhi, ETHER_ADDR_LEN);
1146                 }
1147                 break;
1148 #endif /* INET6 */
1149
1150         default:
1151                 splx(s);
1152                 return (EAFNOSUPPORT);
1153         }
1154
1155         /*
1156          * Look up the address in our list.
1157          */
1158         ETHER_LOOKUP_MULTI(addrlo, addrhi, ac, enm);
1159         if (enm == NULL) {
1160                 splx(s);
1161                 return (ENXIO);
1162         }
1163         if (--enm->enm_refcount != 0) {
1164                 /*
1165                  * Still some claims to this record.
1166                  */
1167                 splx(s);
1168                 return (0);
1169         }
1170         /*
1171          * No remaining claims to this record; unlink and free it.
1172          */
1173         LIST_REMOVE(enm, enm_list);
1174         free(enm, M_IFMADDR);
1175         ac->ac_multicnt--;
1176         splx(s);
1177         /*
1178          * Return ENETRESET to inform the driver that the list has changed
1179          * and its reception filter should be adjusted accordingly.
1180          */
1181         return (ENETRESET);
1182 }