OSDN Git Service

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