OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / lib / Libnet / support / bpf-lkm / OpenBSD / ether_mod-2.6.c
1 /*
2  *  $Id: ether_mod-2.6.c,v 1.1.1.1 2000/05/25 00:28:49 route Exp $
3  *
4  *  libnet
5  *  OpenBSD 2.6 ether_mod.c - lkm replacement for ether_output
6  *  UNTESTED as of Thu Mar  9 21:52:03 PST 2000.
7  *
8  *  Copyright (c) 1999, 2000 Trevor Scheroeder <tschroed@zweknu.org>
9  *  Copyright (c) 1998, 1999, 2000 Mike D. Schiffman <mike@infonexus.com>
10  *  Original code and idea 1997 Thomas Ptacek <tqbf@pobox.com
11  *
12  *  Copyright (c) 1982, 1989, 1993
13  *      The Regents of the University of California.  All rights reserved.
14  *      
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright   
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  * 3. All advertising materials mentioning features or use of this software
24  *    must display the following acknowledgement:
25  *      This product includes software developed by the University of
26  *      California, Berkeley and its contributors.
27  * 4. Neither the name of the University nor the names of its contributors
28  *    may be used to endorse or promote products derived from this software
29  *    without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
32  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
35  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
39  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
40  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41  * SUCH DAMAGE.
42  *
43  *      @(#)if_ethersubr.c      8.1 (Berkeley) 6/10/93
44  */
45
46
47
48 /*
49 %%% portions-copyright-nrl-95
50 Portions of this software are Copyright 1995-1998 by Randall Atkinson,
51 Ronald Lee, Daniel McDonald, Bao Phan, and Chris Winters. All Rights
52 Reserved. All rights under this copyright have been assigned to the US
53 Naval Research Laboratory (NRL). The NRL Copyright Notice and License
54 Agreement Version 1.1 (January 17, 1995) applies to these portions of the
55 software.
56 You should have received a copy of the license with this software. If you
57 didn't get a copy, you may request one from <license@ipv6.nrl.navy.mil>.
58 */
59
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/kernel.h>
63 #include <sys/malloc.h>
64 #include <sys/mbuf.h>
65 #include <sys/protosw.h>
66 #include <sys/socket.h>
67 #include <sys/ioctl.h>
68 #include <sys/errno.h>
69 #include <sys/syslog.h>
70
71 #include <machine/cpu.h>
72
73 #include <net/if.h>
74 #include <net/netisr.h>
75 #include <net/route.h>
76 #include <net/if_llc.h>
77 #include <net/if_dl.h>
78 #include <net/if_types.h>
79
80 #include <netinet/in.h>
81 #ifdef INET
82 #include <netinet/in_var.h>
83 #endif
84 #include <netinet/if_ether.h>
85
86 /*#include "bridge.h"*/
87 #if NBRIDGE > 0
88 #include <net/if_bridge.h>
89 #endif
90
91 #ifdef NS
92 #include <netns/ns.h>
93 #include <netns/ns_if.h>
94 #endif
95
96 #ifdef IPX
97 #include <netipx/ipx.h>
98 #include <netipx/ipx_if.h>
99 #endif
100
101 #ifdef ISO
102 #include <netiso/argo_debug.h>
103 #include <netiso/iso.h>
104 #include <netiso/iso_var.h>
105 #include <netiso/iso_snpac.h>
106 #endif
107
108 #include <netccitt/x25.h>
109 #include <netccitt/pk.h>
110 #include <netccitt/pk_extern.h>
111 #include <netccitt/dll.h>
112 #include <netccitt/llc_var.h>
113
114 #ifdef NETATALK
115 #include <netatalk/at.h>
116 #include <netatalk/at_var.h>
117 #include <netatalk/at_extern.h>
118
119 #define llc_snap_org_code llc_un.type_snap.org_code
120 #define llc_snap_ether_type llc_un.type_snap.ether_type
121
122 extern u_char   at_org_code[ 3 ];
123 extern u_char   aarp_org_code[ 3 ];
124 #endif /* NETATALK */
125
126 #if defined(CCITT)
127 #include <sys/socketvar.h>
128 #endif
129
130 #ifdef INET6
131 #include <netinet6/in6.h>
132 #include <netinet6/in6_var.h>
133 #endif /* INET6 */
134
135 #define senderr(e) { error = (e); goto bad;}
136
137
138 /*
139  * Ethernet output routine.
140  * Encapsulate a packet of type family for the local net.
141  * Assumes that ifp is actually pointer to arpcom structure.
142  */
143 int
144 ether_output_spoof(ifp, m0, dst, rt0)
145         register struct ifnet *ifp;
146         struct mbuf *m0;
147         struct sockaddr *dst;
148         struct rtentry *rt0;
149 {
150         u_int16_t etype;
151         int s, error = 0;
152         u_char edst[6], esrc[6];
153         register struct mbuf *m = m0;
154         register struct rtentry *rt;
155         struct mbuf *mcopy = (struct mbuf *)0;
156         register struct ether_header *eh;
157         struct arpcom *ac = (struct arpcom *)ifp;
158
159         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
160                 senderr(ENETDOWN);
161         ifp->if_lastchange = time;
162         if ((rt = rt0) != NULL) {
163                 if ((rt->rt_flags & RTF_UP) == 0) {
164                         if ((rt0 = rt = rtalloc1(dst, 1)) != NULL)
165                                 rt->rt_refcnt--;
166                         else
167                                 senderr(EHOSTUNREACH);
168                 }
169                 if (rt->rt_flags & RTF_GATEWAY) {
170                         if (rt->rt_gwroute == 0)
171                                 goto lookup;
172                         if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
173                                 rtfree(rt); rt = rt0;
174                         lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
175                                 if ((rt = rt->rt_gwroute) == 0)
176                                         senderr(EHOSTUNREACH);
177                         }
178                 }
179                 if (rt->rt_flags & RTF_REJECT)
180                         if (rt->rt_rmx.rmx_expire == 0 ||
181                             time.tv_sec < rt->rt_rmx.rmx_expire)
182                                 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
183         }
184         switch (dst->sa_family) {
185
186 #ifdef INET
187         case AF_INET:
188                 if (!arpresolve(ac, rt, m, dst, edst))
189                         return (0);     /* if not yet resolved */
190                 /* If broadcasting on a simplex interface, loopback a copy */
191                 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
192                         mcopy = m_copy(m, 0, (int)M_COPYALL);
193                 etype = htons(ETHERTYPE_IP);
194                 bcopy(ac->ac_enaddr, esrc, sizeof (edst));
195                 break;
196 #endif
197 #ifdef NS
198         case AF_NS:
199                 etype = htons(ETHERTYPE_NS);
200                 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
201                     (caddr_t)edst, sizeof (edst));
202                 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
203                         return (looutput(ifp, m, dst, rt));
204                 /* If broadcasting on a simplex interface, loopback a copy */
205                 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
206                         mcopy = m_copy(m, 0, (int)M_COPYALL);
207                 break;
208 #endif
209 #ifdef IPX
210         case AF_IPX:
211                 etype = htons(ETHERTYPE_IPX);
212                 bcopy((caddr_t)&satosipx(dst)->sipx_addr.ipx_host,
213                     (caddr_t)edst, sizeof (edst));
214                 if (!bcmp((caddr_t)edst, (caddr_t)&ipx_thishost, sizeof(edst)))
215                         return (looutput(ifp, m, dst, rt));
216                 /* If broadcasting on a simplex interface, loopback a copy */
217                 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
218                         mcopy = m_copy(m, 0, (int)M_COPYALL);
219                 break;
220 #endif
221 #ifdef INET6
222         case AF_INET6:
223                 /*
224                  * The bottom line here is to either queue the outgoing packet
225                  * in the discovery engine, or fill in edst with something
226                  * that'll work.
227                  */
228                 if (m->m_flags & M_MCAST) {
229                         /*
230                          * If multicast dest., then use IPv6 -> Ethernet
231                          * mcast mapping.  Really simple.
232                          */
233                         ETHER_MAP_IN6_MULTICAST(((struct sockaddr_in6 *)dst)->sin6_addr,
234                             edst);
235                 } else {
236                         /* Do unicast neighbor discovery stuff. */
237                         if (!ipv6_discov_resolve(ifp, rt, m, dst, edst))
238                                 return 0;
239                 }
240                 etype = htons(ETHERTYPE_IPV6);
241                 break;
242 #endif /* INET6 */
243 #ifdef NETATALK
244         case AF_APPLETALK: {
245                 struct at_ifaddr *aa;
246
247                 if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) {
248 #ifdef NETATALKDEBUG
249                         extern char *prsockaddr(struct sockaddr *);
250                         printf("aarpresolv: failed for %s\n", prsockaddr(dst));
251 #endif /* NETATALKDEBUG */
252                         return (0);
253                 }
254
255                 /*
256                  * ifaddr is the first thing in at_ifaddr
257                  */
258                 aa = (struct at_ifaddr *)at_ifawithnet(
259                         (struct sockaddr_at *)dst,
260                         ifp->if_addrlist.tqh_first);
261                 if (aa == 0)
262                         goto bad;
263
264                 /*
265                  * In the phase 2 case, we need to prepend an mbuf for the llc
266                  * header. Since we must preserve the value of m, which is
267                  * passed to us by value, we m_copy() the first mbuf,
268                  * and use it for our llc header.
269                  */
270                 if ( aa->aa_flags & AFA_PHASE2 ) {
271                         struct llc llc;
272
273                         /* XXX Really this should use netisr too */
274                         M_PREPEND(m, AT_LLC_SIZE, M_WAIT);
275                         /*
276                          * FreeBSD doesn't count the LLC len in
277                          * ifp->obytes, so they increment a length
278                          * field here. We don't do this.
279                          */
280                         llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
281                         llc.llc_control = LLC_UI;
282                         bcopy(at_org_code, llc.llc_snap_org_code,
283                                 sizeof(at_org_code));
284                         llc.llc_snap_ether_type = htons( ETHERTYPE_AT );
285                         bcopy(&llc, mtod(m, caddr_t), AT_LLC_SIZE);
286                         etype = htons(m->m_pkthdr.len);
287                 } else {
288                         etype = htons(ETHERTYPE_AT);
289                 }
290                 } break;
291 #endif /* NETATALK */
292 #ifdef  ISO
293         case AF_ISO: {
294                 int     snpalen;
295                 struct  llc *l;
296                 register struct sockaddr_dl *sdl;
297
298                 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) &&
299                     sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) {
300                         bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst));
301                 } else {
302                         error = iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
303                                                 (char *)edst, &snpalen);
304                         if (error)
305                                 goto bad; /* Not Resolved */
306                 }
307                 /* If broadcasting on a simplex interface, loopback a copy */
308                 if (*edst & 1)
309                         m->m_flags |= (M_BCAST|M_MCAST);
310                 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
311                     (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
312                         M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
313                         if (mcopy) {
314                                 eh = mtod(mcopy, struct ether_header *);
315                                 bcopy(edst, eh->ether_dhost, sizeof (edst));
316                                 bcopy(ac->ac_enaddr, eh->ether_shost,
317                                     sizeof (edst));
318                         }
319                 }
320                 M_PREPEND(m, 3, M_DONTWAIT);
321                 if (m == NULL)
322                         return (0);
323                 etype = htons(m->m_pkthdr.len);
324                 l = mtod(m, struct llc *);
325                 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
326                 l->llc_control = LLC_UI;
327 #ifdef ARGO_DEBUG
328                 if (argo_debug[D_ETHER]) {
329                         int i;
330                         printf("unoutput: sending pkt to: ");
331                         for (i=0; i<6; i++)
332                                 printf("%x ", edst[i] & 0xff);
333                         printf("\n");
334                 }
335 #endif
336                 } break;
337 #endif /* ISO */
338 /*      case AF_NSAP: */
339         case AF_CCITT: {
340                 register struct sockaddr_dl *sdl =
341                         (struct sockaddr_dl *) rt -> rt_gateway;
342
343                 if (sdl && sdl->sdl_family == AF_LINK
344                     && sdl->sdl_alen > 0) {
345                         bcopy(LLADDR(sdl), (char *)edst,
346                                 sizeof(edst));
347                 } else goto bad; /* Not a link interface ? Funny ... */
348                 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
349                     (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
350                         M_PREPEND(mcopy, sizeof (*eh), M_DONTWAIT);
351                         if (mcopy) {
352                                 eh = mtod(mcopy, struct ether_header *);
353                                 bcopy(edst, eh->ether_dhost, sizeof (edst));
354                                 bcopy(esrc,eh->ether_shost,
355                                     sizeof (edst));
356                         }
357                 }
358                 etype = htons(m->m_pkthdr.len);
359 #ifdef LLC_DEBUG
360                 {
361                         int i;
362                         register struct llc *l = mtod(m, struct llc *);
363
364                         printf("ether_output: sending LLC2 pkt to: ");
365                         for (i=0; i<6; i++)
366                                 printf("%x ", edst[i] & 0xff);
367                         printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n",
368                             m->m_pkthdr.len, l->llc_dsap & 0xff, l->llc_ssap &0xff,
369                             l->llc_control & 0xff);
370
371                 }
372 #endif /* LLC_DEBUG */
373                 } break;
374
375         case AF_UNSPEC:
376                 eh = (struct ether_header *)dst->sa_data;
377                 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
378                 bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, sizeof (edst));
379                 /* AF_UNSPEC doesn't swap the byte order of the ether_type. */
380                 etype = eh->ether_type;
381                 break;
382
383         default:
384                 printf("%s: can't handle af%d\n", ifp->if_xname,
385                         dst->sa_family);
386                 senderr(EAFNOSUPPORT);
387         }
388
389         if (mcopy)
390                 (void) looutput(ifp, mcopy, dst, rt);
391
392         /*
393          * Add local net header.  If no space in first mbuf,
394          * allocate another.
395          */
396         M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
397         if (m == 0)
398                 senderr(ENOBUFS);
399         eh = mtod(m, struct ether_header *);
400         bcopy((caddr_t)&etype,(caddr_t)&eh->ether_type,
401                 sizeof(eh->ether_type));
402         bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
403         bcopy((caddr_t)esrc, (caddr_t)eh->ether_shost,
404                 sizeof(eh->ether_shost));
405 /*      bcopy((caddr_t)ac->ac_enaddr, (caddr_t)eh->ether_shost,
406             sizeof(eh->ether_shost)); */
407
408 #if NBRIDGE > 0
409         /*
410          * Interfaces that are bridge members need special handling
411          * for output.
412          */
413         if (ifp->if_bridge) {
414                 bridge_output(ifp, m, NULL, NULL);
415                 return (error);
416         }
417 #endif
418
419         s = splimp();
420         /*
421          * Queue message on interface, and start output if interface
422          * not yet active.
423          */
424         if (IF_QFULL(&ifp->if_snd)) {
425                 IF_DROP(&ifp->if_snd);
426                 splx(s);
427                 senderr(ENOBUFS);
428         }
429         ifp->if_obytes += m->m_pkthdr.len;
430         IF_ENQUEUE(&ifp->if_snd, m);
431         if (m->m_flags & M_MCAST)
432                 ifp->if_omcasts++;
433         if ((ifp->if_flags & IFF_OACTIVE) == 0)
434                 (*ifp->if_start)(ifp);
435         splx(s);
436         return (error);
437
438 bad:
439         if (m)
440                 m_freem(m);
441         return (error);
442 }