Deleted Added
sdiff udiff text old ( 53913 ) new ( 54263 )
full compact
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 * $FreeBSD: head/sys/net/if_ethersubr.c 53913 1999-11-30 02:45:32Z archie $
35 */
36
37#include "opt_atalk.h"
38#include "opt_inet.h"
39#include "opt_ipx.h"
40#include "opt_bdg.h"
41#include "opt_netgraph.h"
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/kernel.h>
46#include <sys/malloc.h>
47#include <sys/mbuf.h>
48#include <sys/socket.h>
49#include <sys/sockio.h>
50#include <sys/sysctl.h>
51
52#include <net/if.h>
53#include <net/netisr.h>
54#include <net/route.h>
55#include <net/if_llc.h>
56#include <net/if_dl.h>
57#include <net/if_types.h>
58
59#if defined(INET) || defined(INET6)
60#include <netinet/in.h>
61#include <netinet/in_var.h>
62#include <netinet/if_ether.h>
63#endif
64#ifdef INET6
65#include <netinet6/nd6.h>
66#include <netinet6/in6_ifattach.h>
67#endif
68
69#ifdef IPX
70#include <netipx/ipx.h>
71#include <netipx/ipx_if.h>
72#endif
73
74#ifdef NS
75#include <netns/ns.h>
76#include <netns/ns_if.h>
77ushort ns_nettype;
78int ether_outputdebug = 0;
79int ether_inputdebug = 0;
80#endif
81
82#ifdef ISO
83#include <netiso/argo_debug.h>
84#include <netiso/iso.h>
85#include <netiso/iso_var.h>
86#include <netiso/iso_snpac.h>
87#endif
88
89/*#ifdef LLC
90#include <netccitt/dll.h>
91#include <netccitt/llc_var.h>
92#endif*/
93
94#if defined(LLC) && defined(CCITT)
95extern struct ifqueue pkintrq;
96#endif
97
98#ifdef NETATALK
99#include <netatalk/at.h>
100#include <netatalk/at_var.h>
101#include <netatalk/at_extern.h>
102
103#define llc_snap_org_code llc_un.type_snap.org_code
104#define llc_snap_ether_type llc_un.type_snap.ether_type
105
106extern u_char at_org_code[3];
107extern u_char aarp_org_code[3];
108#endif /* NETATALK */
109
110#ifdef BRIDGE
111#include <net/bridge.h>
112#endif
113
114#include "vlan.h"
115#if NVLAN > 0
116#include <net/if_vlan_var.h>
117#endif /* NVLAN > 0 */
118
119static int ether_resolvemulti __P((struct ifnet *, struct sockaddr **,
120 struct sockaddr *));
121u_char etherbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
122#define senderr(e) do { error = (e); goto bad;} while (0)
123#define IFP2AC(IFP) ((struct arpcom *)IFP)
124
125#ifdef NETGRAPH
126#include <netgraph/ng_ether.h>
127#include <netgraph/ng_message.h>
128#include <netgraph/netgraph.h>
129
130static void ngether_init(void* ignored);
131static void ngether_send(struct arpcom *ac,
132 struct ether_header *eh, struct mbuf *m);
133static ng_constructor_t ngether_constructor;
134static ng_rcvmsg_t ngether_rcvmsg;
135static ng_shutdown_t ngether_rmnode;
136static ng_newhook_t ngether_newhook;
137static ng_connect_t ngether_connect;
138static ng_rcvdata_t ngether_rcvdata;
139static ng_disconnect_t ngether_disconnect;
140
141static struct ng_type typestruct = {
142 NG_VERSION,
143 NG_ETHER_NODE_TYPE,
144 NULL,
145 ngether_constructor,
146 ngether_rcvmsg,
147 ngether_rmnode,
148 ngether_newhook,
149 NULL,
150 ngether_connect,
151 ngether_rcvdata,
152 ngether_rcvdata,
153 ngether_disconnect,
154 NULL
155};
156
157#define AC2NG(AC) ((node_p)((AC)->ac_ng))
158#define NGEF_DIVERT NGF_TYPE1 /* all packets sent to netgraph */
159#endif /* NETGRAPH */
160
161/*
162 * Ethernet output routine.
163 * Encapsulate a packet of type family for the local net.
164 * Use trailer local net encapsulation if enough data in first
165 * packet leaves a multiple of 512 bytes of data in remainder.
166 * Assumes that ifp is actually pointer to arpcom structure.
167 */
168int
169ether_output(ifp, m0, dst, rt0)
170 register struct ifnet *ifp;
171 struct mbuf *m0;
172 struct sockaddr *dst;
173 struct rtentry *rt0;
174{
175 short type;
176 int s, error = 0, hdrcmplt = 0;
177 u_char esrc[6], edst[6];
178 register struct mbuf *m = m0;
179 register struct rtentry *rt;
180 register struct ether_header *eh;
181 int off, len = m->m_pkthdr.len, loop_copy = 0;
182 int hlen; /* link layer header lenght */
183 struct arpcom *ac = IFP2AC(ifp);
184
185 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
186 senderr(ENETDOWN);
187 rt = rt0;
188 if (rt) {
189 if ((rt->rt_flags & RTF_UP) == 0) {
190 rt0 = rt = rtalloc1(dst, 1, 0UL);
191 if (rt0)
192 rt->rt_refcnt--;
193 else
194 senderr(EHOSTUNREACH);
195 }
196 if (rt->rt_flags & RTF_GATEWAY) {
197 if (rt->rt_gwroute == 0)
198 goto lookup;
199 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
200 rtfree(rt); rt = rt0;
201 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1,
202 0UL);
203 if ((rt = rt->rt_gwroute) == 0)
204 senderr(EHOSTUNREACH);
205 }
206 }
207 if (rt->rt_flags & RTF_REJECT)
208 if (rt->rt_rmx.rmx_expire == 0 ||
209 time_second < rt->rt_rmx.rmx_expire)
210 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
211 }
212 hlen = ETHER_HDR_LEN;
213 switch (dst->sa_family) {
214#ifdef INET
215 case AF_INET:
216 if (!arpresolve(ac, rt, m, dst, edst, rt0))
217 return (0); /* if not yet resolved */
218 off = m->m_pkthdr.len - m->m_len;
219 type = htons(ETHERTYPE_IP);
220 break;
221#endif
222#ifdef INET6
223 case AF_INET6:
224 if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) {
225 /* this must be impossible, so we bark */
226 printf("nd6_storelladdr failed\n");
227 return(0);
228 }
229 off = m->m_pkthdr.len - m->m_len;
230 type = htons(ETHERTYPE_IPV6);
231 break;
232#endif
233#ifdef IPX
234 case AF_IPX:
235 type = htons(ETHERTYPE_IPX);
236 bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
237 (caddr_t)edst, sizeof (edst));
238 break;
239#endif
240#ifdef NETATALK
241 case AF_APPLETALK:
242 {
243 struct at_ifaddr *aa;
244
245 if ((aa = at_ifawithnet((struct sockaddr_at *)dst)) == NULL) {
246 goto bad;
247 }
248 if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst))
249 return (0);
250 /*
251 * In the phase 2 case, need to prepend an mbuf for the llc header.
252 * Since we must preserve the value of m, which is passed to us by
253 * value, we m_copy() the first mbuf, and use it for our llc header.
254 */
255 if ( aa->aa_flags & AFA_PHASE2 ) {
256 struct llc llc;
257
258 M_PREPEND(m, sizeof(struct llc), M_WAIT);
259 len += sizeof(struct llc);
260 llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
261 llc.llc_control = LLC_UI;
262 bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code));
263 llc.llc_snap_ether_type = htons( ETHERTYPE_AT );
264 bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc));
265 type = htons(m->m_pkthdr.len);
266 hlen = sizeof(struct llc) + ETHER_HDR_LEN;
267 } else {
268 type = htons(ETHERTYPE_AT);
269 }
270 break;
271 }
272#endif NETATALK
273#ifdef NS
274 case AF_NS:
275 switch(ns_nettype){
276 default:
277 case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */
278 type = 0x8137;
279 break;
280 case 0x0: /* Novell 802.3 */
281 type = htons( m->m_pkthdr.len);
282 break;
283 case 0xe0e0: /* Novell 802.2 and Token-Ring */
284 M_PREPEND(m, 3, M_WAIT);
285 type = htons( m->m_pkthdr.len);
286 cp = mtod(m, u_char *);
287 *cp++ = 0xE0;
288 *cp++ = 0xE0;
289 *cp++ = 0x03;
290 break;
291 }
292 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
293 (caddr_t)edst, sizeof (edst));
294 /*
295 * XXX if ns_thishost is the same as the node's ethernet
296 * address then just the default code will catch this anyhow.
297 * So I'm not sure if this next clause should be here at all?
298 * [JRE]
299 */
300 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst))){
301 m->m_pkthdr.rcvif = ifp;
302 schednetisr(NETISR_NS);
303 inq = &nsintrq;
304 s = splimp();
305 if (IF_QFULL(inq)) {
306 IF_DROP(inq);
307 m_freem(m);
308 } else
309 IF_ENQUEUE(inq, m);
310 splx(s);
311 return (error);
312 }
313 if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof(edst))){
314 m->m_flags |= M_BCAST;
315 }
316 break;
317#endif /* NS */
318#ifdef ISO
319 case AF_ISO: {
320 int snpalen;
321 struct llc *l;
322 register struct sockaddr_dl *sdl;
323
324 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) &&
325 sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) {
326 bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst));
327 } else if (error =
328 iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
329 (char *)edst, &snpalen))
330 goto bad; /* Not Resolved */
331 /* If broadcasting on a simplex interface, loopback a copy */
332 if (*edst & 1)
333 m->m_flags |= (M_BCAST|M_MCAST);
334 M_PREPEND(m, 3, M_DONTWAIT);
335 if (m == NULL)
336 return (0);
337 type = htons(m->m_pkthdr.len);
338 l = mtod(m, struct llc *);
339 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
340 l->llc_control = LLC_UI;
341 len += 3;
342 IFDEBUG(D_ETHER)
343 int i;
344 printf("unoutput: sending pkt to: ");
345 for (i=0; i<6; i++)
346 printf("%x ", edst[i] & 0xff);
347 printf("\n");
348 ENDDEBUG
349 } break;
350#endif /* ISO */
351#ifdef LLC
352/* case AF_NSAP: */
353 case AF_CCITT: {
354 register struct sockaddr_dl *sdl =
355 (struct sockaddr_dl *) rt -> rt_gateway;
356
357 if (sdl && sdl->sdl_family == AF_LINK
358 && sdl->sdl_alen > 0) {
359 bcopy(LLADDR(sdl), (char *)edst, sizeof(edst));
360 } else goto bad; /* Not a link interface ? Funny ... */
361 if (*edst & 1)
362 loop_copy = 1;
363 type = htons(m->m_pkthdr.len);
364#ifdef LLC_DEBUG
365 {
366 int i;
367 register struct llc *l = mtod(m, struct llc *);
368
369 printf("ether_output: sending LLC2 pkt to: ");
370 for (i=0; i<6; i++)
371 printf("%x ", edst[i] & 0xff);
372 printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n",
373 type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff,
374 l->llc_control & 0xff);
375
376 }
377#endif /* LLC_DEBUG */
378 } break;
379#endif /* LLC */
380
381 case pseudo_AF_HDRCMPLT:
382 hdrcmplt = 1;
383 eh = (struct ether_header *)dst->sa_data;
384 (void)memcpy(esrc, eh->ether_shost, sizeof (esrc));
385 /* FALLTHROUGH */
386
387 case AF_UNSPEC:
388 loop_copy = -1; /* if this is for us, don't do it */
389 eh = (struct ether_header *)dst->sa_data;
390 (void)memcpy(edst, eh->ether_dhost, sizeof (edst));
391 type = eh->ether_type;
392 break;
393
394 default:
395 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
396 dst->sa_family);
397 senderr(EAFNOSUPPORT);
398 }
399
400 /*
401 * Add local net header. If no space in first mbuf,
402 * allocate another.
403 */
404 M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
405 if (m == 0)
406 senderr(ENOBUFS);
407 eh = mtod(m, struct ether_header *);
408 (void)memcpy(&eh->ether_type, &type,
409 sizeof(eh->ether_type));
410 (void)memcpy(eh->ether_dhost, edst, sizeof (edst));
411 if (hdrcmplt)
412 (void)memcpy(eh->ether_shost, esrc,
413 sizeof(eh->ether_shost));
414 else
415 (void)memcpy(eh->ether_shost, ac->ac_enaddr,
416 sizeof(eh->ether_shost));
417
418 /*
419 * If a simplex interface, and the packet is being sent to our
420 * Ethernet address or a broadcast address, loopback a copy.
421 * XXX To make a simplex device behave exactly like a duplex
422 * device, we should copy in the case of sending to our own
423 * ethernet address (thus letting the original actually appear
424 * on the wire). However, we don't do that here for security
425 * reasons and compatibility with the original behavior.
426 */
427 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
428 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
429 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
430
431 (void) if_simloop(ifp, n, dst, hlen);
432 } else if (bcmp(eh->ether_dhost,
433 eh->ether_shost, ETHER_ADDR_LEN) == 0) {
434 (void) if_simloop(ifp, m, dst, hlen);
435 return (0); /* XXX */
436 }
437 }
438#ifdef BRIDGE
439 if (do_bridge) {
440 struct mbuf *m0 = m ;
441
442 if (m->m_pkthdr.rcvif)
443 m->m_pkthdr.rcvif = NULL ;
444 ifp = bridge_dst_lookup(m);
445 bdg_forward(&m0, ifp);
446 if (m0)
447 m_freem(m0);
448 return (0);
449 }
450#endif
451 s = splimp();
452 /*
453 * Queue message on interface, and start output if interface
454 * not yet active.
455 */
456 if (IF_QFULL(&ifp->if_snd)) {
457 IF_DROP(&ifp->if_snd);
458 splx(s);
459 senderr(ENOBUFS);
460 }
461 IF_ENQUEUE(&ifp->if_snd, m);
462 if ((ifp->if_flags & IFF_OACTIVE) == 0)
463 (*ifp->if_start)(ifp);
464 splx(s);
465 ifp->if_obytes += len + sizeof (struct ether_header);
466 if (m->m_flags & M_MCAST)
467 ifp->if_omcasts++;
468 return (error);
469
470bad:
471 if (m)
472 m_freem(m);
473 return (error);
474}
475
476/*
477 * Process a received Ethernet packet;
478 * the packet is in the mbuf chain m without
479 * the ether header, which is provided separately.
480 */
481void
482ether_input(ifp, eh, m)
483 struct ifnet *ifp;
484 register struct ether_header *eh;
485 struct mbuf *m;
486{
487 register struct ifqueue *inq;
488 u_short ether_type;
489 int s;
490#if defined (ISO) || defined (LLC) || defined(NETATALK)
491 register struct llc *l;
492#endif
493
494 if ((ifp->if_flags & IFF_UP) == 0) {
495 m_freem(m);
496 return;
497 }
498 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*eh);
499 if (eh->ether_dhost[0] & 1) {
500 if (bcmp((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
501 sizeof(etherbroadcastaddr)) == 0)
502 m->m_flags |= M_BCAST;
503 else
504 m->m_flags |= M_MCAST;
505 }
506 if (m->m_flags & (M_BCAST|M_MCAST))
507 ifp->if_imcasts++;
508
509 ether_type = ntohs(eh->ether_type);
510
511#ifdef NETGRAPH
512 {
513 struct arpcom *ac = IFP2AC(ifp);
514 if (AC2NG(ac) && (AC2NG(ac)->flags & NGEF_DIVERT)) {
515 ngether_send(ac, eh, m);
516 return;
517 }
518 }
519#endif /* NETGRAPH */
520
521#if NVLAN > 0
522 if (ether_type == vlan_proto) {
523 if (vlan_input(eh, m) < 0)
524 ifp->if_data.ifi_noproto++;
525 return;
526 }
527#endif /* NVLAN > 0 */
528
529 switch (ether_type) {
530#ifdef INET
531 case ETHERTYPE_IP:
532 if (ipflow_fastforward(m))
533 return;
534 schednetisr(NETISR_IP);
535 inq = &ipintrq;
536 break;
537
538 case ETHERTYPE_ARP:
539 schednetisr(NETISR_ARP);
540 inq = &arpintrq;
541 break;
542#endif
543#ifdef IPX
544 case ETHERTYPE_IPX:
545 schednetisr(NETISR_IPX);
546 inq = &ipxintrq;
547 break;
548#endif
549#ifdef INET6
550 case ETHERTYPE_IPV6:
551 schednetisr(NETISR_IPV6);
552 inq = &ip6intrq;
553 break;
554#endif
555#ifdef NS
556 case 0x8137: /* Novell Ethernet_II Ethernet TYPE II */
557 schednetisr(NETISR_NS);
558 inq = &nsintrq;
559 break;
560
561#endif /* NS */
562#ifdef NETATALK
563 case ETHERTYPE_AT:
564 schednetisr(NETISR_ATALK);
565 inq = &atintrq1;
566 break;
567 case ETHERTYPE_AARP:
568 /* probably this should be done with a NETISR as well */
569 aarpinput(IFP2AC(ifp), m); /* XXX */
570 return;
571#endif NETATALK
572 default:
573#ifdef NS
574 checksum = mtod(m, ushort *);
575 /* Novell 802.3 */
576 if ((ether_type <= ETHERMTU) &&
577 ((*checksum == 0xffff) || (*checksum == 0xE0E0))){
578 if(*checksum == 0xE0E0) {
579 m->m_pkthdr.len -= 3;
580 m->m_len -= 3;
581 m->m_data += 3;
582 }
583 schednetisr(NETISR_NS);
584 inq = &nsintrq;
585 break;
586 }
587#endif /* NS */
588#if defined (ISO) || defined (LLC) || defined(NETATALK)
589 if (ether_type > ETHERMTU)
590 goto dropanyway;
591 l = mtod(m, struct llc *);
592 switch (l->llc_dsap) {
593#ifdef NETATALK
594 case LLC_SNAP_LSAP:
595 switch (l->llc_control) {
596 case LLC_UI:
597 if (l->llc_ssap != LLC_SNAP_LSAP)
598 goto dropanyway;
599
600 if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code,
601 sizeof(at_org_code)) == 0 &&
602 ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) {
603 inq = &atintrq2;
604 m_adj( m, sizeof( struct llc ));
605 schednetisr(NETISR_ATALK);
606 break;
607 }
608
609 if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code,
610 sizeof(aarp_org_code)) == 0 &&
611 ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) {
612 m_adj( m, sizeof( struct llc ));
613 aarpinput(IFP2AC(ifp), m); /* XXX */
614 return;
615 }
616
617 default:
618 goto dropanyway;
619 }
620 break;
621#endif NETATALK
622#ifdef ISO
623 case LLC_ISO_LSAP:
624 switch (l->llc_control) {
625 case LLC_UI:
626 /* LLC_UI_P forbidden in class 1 service */
627 if ((l->llc_dsap == LLC_ISO_LSAP) &&
628 (l->llc_ssap == LLC_ISO_LSAP)) {
629 /* LSAP for ISO */
630 if (m->m_pkthdr.len > ether_type)
631 m_adj(m, ether_type - m->m_pkthdr.len);
632 m->m_data += 3; /* XXX */
633 m->m_len -= 3; /* XXX */
634 m->m_pkthdr.len -= 3; /* XXX */
635 M_PREPEND(m, sizeof *eh, M_DONTWAIT);
636 if (m == 0)
637 return;
638 *mtod(m, struct ether_header *) = *eh;
639 IFDEBUG(D_ETHER)
640 printf("clnp packet");
641 ENDDEBUG
642 schednetisr(NETISR_ISO);
643 inq = &clnlintrq;
644 break;
645 }
646 goto dropanyway;
647
648 case LLC_XID:
649 case LLC_XID_P:
650 if(m->m_len < 6)
651 goto dropanyway;
652 l->llc_window = 0;
653 l->llc_fid = 9;
654 l->llc_class = 1;
655 l->llc_dsap = l->llc_ssap = 0;
656 /* Fall through to */
657 case LLC_TEST:
658 case LLC_TEST_P:
659 {
660 struct sockaddr sa;
661 register struct ether_header *eh2;
662 int i;
663 u_char c = l->llc_dsap;
664
665 l->llc_dsap = l->llc_ssap;
666 l->llc_ssap = c;
667 if (m->m_flags & (M_BCAST | M_MCAST))
668 bcopy((caddr_t)ac->ac_enaddr,
669 (caddr_t)eh->ether_dhost, 6);
670 sa.sa_family = AF_UNSPEC;
671 sa.sa_len = sizeof(sa);
672 eh2 = (struct ether_header *)sa.sa_data;
673 for (i = 0; i < 6; i++) {
674 eh2->ether_shost[i] = c = eh->ether_dhost[i];
675 eh2->ether_dhost[i] =
676 eh->ether_dhost[i] = eh->ether_shost[i];
677 eh->ether_shost[i] = c;
678 }
679 ifp->if_output(ifp, m, &sa, NULL);
680 return;
681 }
682 default:
683 m_freem(m);
684 return;
685 }
686 break;
687#endif /* ISO */
688#ifdef LLC
689 case LLC_X25_LSAP:
690 {
691 if (m->m_pkthdr.len > ether_type)
692 m_adj(m, ether_type - m->m_pkthdr.len);
693 M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT);
694 if (m == 0)
695 return;
696 if ( !sdl_sethdrif(ifp, eh->ether_shost, LLC_X25_LSAP,
697 eh->ether_dhost, LLC_X25_LSAP, 6,
698 mtod(m, struct sdl_hdr *)))
699 panic("ETHER cons addr failure");
700 mtod(m, struct sdl_hdr *)->sdlhdr_len = ether_type;
701#ifdef LLC_DEBUG
702 printf("llc packet\n");
703#endif /* LLC_DEBUG */
704 schednetisr(NETISR_CCITT);
705 inq = &llcintrq;
706 break;
707 }
708#endif /* LLC */
709 dropanyway:
710 default:
711#ifdef NETGRAPH
712 ngether_send(IFP2AC(ifp), eh, m);
713#else /* NETGRAPH */
714 m_freem(m);
715#endif /* NETGRAPH */
716 return;
717 }
718#else /* ISO || LLC || NETATALK */
719#ifdef NETGRAPH
720 ngether_send(IFP2AC(ifp), eh, m);
721#else /* NETGRAPH */
722 m_freem(m);
723#endif /* NETGRAPH */
724 return;
725#endif /* ISO || LLC || NETATALK */
726 }
727
728 s = splimp();
729 if (IF_QFULL(inq)) {
730 IF_DROP(inq);
731 m_freem(m);
732 } else
733 IF_ENQUEUE(inq, m);
734 splx(s);
735}
736
737/*
738 * Perform common duties while attaching to interface list
739 */
740void
741ether_ifattach(ifp)
742 register struct ifnet *ifp;
743{
744 register struct ifaddr *ifa;
745 register struct sockaddr_dl *sdl;
746
747 ifp->if_type = IFT_ETHER;
748 ifp->if_addrlen = 6;
749 ifp->if_hdrlen = 14;
750 ifp->if_mtu = ETHERMTU;
751 ifp->if_resolvemulti = ether_resolvemulti;
752 if (ifp->if_baudrate == 0)
753 ifp->if_baudrate = 10000000;
754 ifa = ifnet_addrs[ifp->if_index - 1];
755 if (ifa == 0) {
756 printf("ether_ifattach: no lladdr!\n");
757 return;
758 }
759 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
760 sdl->sdl_type = IFT_ETHER;
761 sdl->sdl_alen = ifp->if_addrlen;
762 bcopy((IFP2AC(ifp))->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
763#ifdef NETGRAPH
764 ngether_init(ifp);
765#endif /* NETGRAPH */
766#ifdef INET6
767 in6_ifattach_getifid(ifp);
768#endif
769}
770
771SYSCTL_DECL(_net_link);
772SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet");
773
774int
775ether_ioctl(ifp, command, data)
776 struct ifnet *ifp;
777 int command;
778 caddr_t data;
779{
780 struct ifaddr *ifa = (struct ifaddr *) data;
781 struct ifreq *ifr = (struct ifreq *) data;
782 int error = 0;
783
784 switch (command) {
785 case SIOCSIFADDR:
786 ifp->if_flags |= IFF_UP;
787
788 switch (ifa->ifa_addr->sa_family) {
789#ifdef INET
790 case AF_INET:
791 ifp->if_init(ifp->if_softc); /* before arpwhohas */
792 arp_ifinit(IFP2AC(ifp), ifa);
793 break;
794#endif
795#ifdef IPX
796 /*
797 * XXX - This code is probably wrong
798 */
799 case AF_IPX:
800 {
801 register struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
802 struct arpcom *ac = IFP2AC(ifp);
803
804 if (ipx_nullhost(*ina))
805 ina->x_host =
806 *(union ipx_host *)
807 ac->ac_enaddr;
808 else {
809 bcopy((caddr_t) ina->x_host.c_host,
810 (caddr_t) ac->ac_enaddr,
811 sizeof(ac->ac_enaddr));
812 }
813
814 /*
815 * Set new address
816 */
817 ifp->if_init(ifp->if_softc);
818 break;
819 }
820#endif
821#ifdef NS
822 /*
823 * XXX - This code is probably wrong
824 */
825 case AF_NS:
826 {
827 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
828 struct arpcom *ac = IFP2AC(ifp);
829
830 if (ns_nullhost(*ina))
831 ina->x_host =
832 *(union ns_host *) (ac->ac_enaddr);
833 else {
834 bcopy((caddr_t) ina->x_host.c_host,
835 (caddr_t) ac->ac_enaddr,
836 sizeof(ac->ac_enaddr));
837 }
838
839 /*
840 * Set new address
841 */
842 ifp->if_init(ifp->if_softc);
843 break;
844 }
845#endif
846 default:
847 ifp->if_init(ifp->if_softc);
848 break;
849 }
850 break;
851
852 case SIOCGIFADDR:
853 {
854 struct sockaddr *sa;
855
856 sa = (struct sockaddr *) & ifr->ifr_data;
857 bcopy(IFP2AC(ifp)->ac_enaddr,
858 (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
859 }
860 break;
861
862 case SIOCSIFMTU:
863 /*
864 * Set the interface MTU.
865 */
866 if (ifr->ifr_mtu > ETHERMTU) {
867 error = EINVAL;
868 } else {
869 ifp->if_mtu = ifr->ifr_mtu;
870 }
871 break;
872 }
873 return (error);
874}
875
876int
877ether_resolvemulti(ifp, llsa, sa)
878 struct ifnet *ifp;
879 struct sockaddr **llsa;
880 struct sockaddr *sa;
881{
882 struct sockaddr_dl *sdl;
883 struct sockaddr_in *sin;
884#ifdef INET6
885 struct sockaddr_in6 *sin6;
886#endif
887 u_char *e_addr;
888
889 switch(sa->sa_family) {
890 case AF_LINK:
891 /*
892 * No mapping needed. Just check that it's a valid MC address.
893 */
894 sdl = (struct sockaddr_dl *)sa;
895 e_addr = LLADDR(sdl);
896 if ((e_addr[0] & 1) != 1)
897 return EADDRNOTAVAIL;
898 *llsa = 0;
899 return 0;
900
901#ifdef INET
902 case AF_INET:
903 sin = (struct sockaddr_in *)sa;
904 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
905 return EADDRNOTAVAIL;
906 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
907 M_WAITOK);
908 sdl->sdl_len = sizeof *sdl;
909 sdl->sdl_family = AF_LINK;
910 sdl->sdl_index = ifp->if_index;
911 sdl->sdl_type = IFT_ETHER;
912 sdl->sdl_nlen = 0;
913 sdl->sdl_alen = ETHER_ADDR_LEN;
914 sdl->sdl_slen = 0;
915 e_addr = LLADDR(sdl);
916 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
917 *llsa = (struct sockaddr *)sdl;
918 return 0;
919#endif
920#ifdef INET6
921 case AF_INET6:
922 sin6 = (struct sockaddr_in6 *)sa;
923 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
924 return EADDRNOTAVAIL;
925 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
926 M_WAITOK);
927 sdl->sdl_len = sizeof *sdl;
928 sdl->sdl_family = AF_LINK;
929 sdl->sdl_index = ifp->if_index;
930 sdl->sdl_type = IFT_ETHER;
931 sdl->sdl_nlen = 0;
932 sdl->sdl_alen = ETHER_ADDR_LEN;
933 sdl->sdl_slen = 0;
934 e_addr = LLADDR(sdl);
935 ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
936 *llsa = (struct sockaddr *)sdl;
937 return 0;
938#endif
939
940 default:
941 /*
942 * Well, the text isn't quite right, but it's the name
943 * that counts...
944 */
945 return EAFNOSUPPORT;
946 }
947}
948
949#ifdef NETGRAPH
950
951/***********************************************************************
952 * This section contains the methods for the Netgraph interface
953 ***********************************************************************/
954/* It's Ascii-art time!
955 * The ifnet is the first part of the arpcom which must be
956 * the first part of the device's softc.. yuk.
957 *
958 * +--------------------------+-----+---------+
959 * | struct ifnet (*ifp) | | |
960 * | | | |
961 * +--------------------------+ | |
962 * +--|[ac_ng] struct arpcom (*ac) | |
963 * | +--------------------------------+ |
964 * | | struct softc (*ifp->if_softc) (device) |
965 * | +------------------------------------------+
966 * | ^
967 * AC2NG() |
968 * | v
969 * | +----------------------+
970 * | | [private] [flags] |
971 * +------>| struct ng_node |
972 * | [hooks] | ** we only allow one hook
973 * +----------------------+
974 * ^
975 * |
976 * v
977 * +-------------+
978 * | [node] |
979 * | hook |
980 * | [private]|-- *unused*
981 * +-------------+
982 */
983
984/*
985 * called during interface attaching
986 */
987static void
988ngether_init(void *ifpvoid)
989{
990 struct ifnet *ifp = ifpvoid;
991 struct arpcom *ac = IFP2AC(ifp);
992 static int ngether_done_init;
993 char namebuf[32];
994 node_p node;
995
996 /*
997 * we have found a node, make sure our 'type' is availabe.
998 */
999 if (ngether_done_init == 0) {
1000 if (ng_newtype(&typestruct)) {
1001 printf("ngether install failed\n");
1002 return;
1003 }
1004 ngether_done_init = 1;
1005 }
1006 if (ng_make_node_common(&typestruct, &node) != 0)
1007 return;
1008 ac->ac_ng = node;
1009 node->private = ifp;
1010 sprintf(namebuf, "%s%d", ifp->if_name, ifp->if_unit);
1011 ng_name_node(AC2NG(ac), namebuf);
1012}
1013
1014/*
1015 * It is not possible or allowable to create a node of this type.
1016 * If the hardware exists, it will already have created it.
1017 */
1018static int
1019ngether_constructor(node_p *nodep)
1020{
1021 return (EINVAL);
1022}
1023
1024/*
1025 * Give our ok for a hook to be added...
1026 *
1027 * Allow one hook at a time (rawdata).
1028 * It can eiteh rdivert everything or only unclaimed packets.
1029 */
1030static int
1031ngether_newhook(node_p node, hook_p hook, const char *name)
1032{
1033
1034 /* check if there is already a hook */
1035 if (LIST_FIRST(&(node->hooks)))
1036 return(EISCONN);
1037 /*
1038 * Check for which mode hook we want.
1039 */
1040 if (strcmp(name, NG_ETHER_HOOK_ORPHAN) != 0) {
1041 if (strcmp(name, NG_ETHER_HOOK_DIVERT) != 0) {
1042 return (EINVAL);
1043 }
1044 node->flags |= NGEF_DIVERT;
1045 } else {
1046 node->flags &= ~NGEF_DIVERT;
1047 }
1048 return (0);
1049}
1050
1051/*
1052 * incoming messages.
1053 * Just respond to the generic TEXT_STATUS message
1054 */
1055static int
1056ngether_rcvmsg(node_p node,
1057 struct ng_mesg *msg, const char *retaddr, struct ng_mesg **resp)
1058{
1059 struct ifnet *ifp;
1060 int error = 0;
1061
1062 ifp = node->private;
1063 switch (msg->header.typecookie) {
1064 case NGM_ETHER_COOKIE:
1065 error = EINVAL;
1066 break;
1067 case NGM_GENERIC_COOKIE:
1068 switch(msg->header.cmd) {
1069 case NGM_TEXT_STATUS: {
1070 char *arg;
1071 int pos = 0;
1072 int resplen = sizeof(struct ng_mesg) + 512;
1073 MALLOC(*resp, struct ng_mesg *, resplen,
1074 M_NETGRAPH, M_NOWAIT);
1075 if (*resp == NULL) {
1076 error = ENOMEM;
1077 break;
1078 }
1079 bzero(*resp, resplen);
1080 arg = (*resp)->data;
1081
1082 /*
1083 * Put in the throughput information.
1084 */
1085 pos = sprintf(arg, "%ld bytes in, %ld bytes out\n",
1086 ifp->if_ibytes, ifp->if_obytes);
1087 pos += sprintf(arg + pos,
1088 "%ld output errors\n",
1089 ifp->if_oerrors);
1090 pos += sprintf(arg + pos,
1091 "ierrors = %ld\n",
1092 ifp->if_ierrors);
1093
1094 (*resp)->header.version = NG_VERSION;
1095 (*resp)->header.arglen = strlen(arg) + 1;
1096 (*resp)->header.token = msg->header.token;
1097 (*resp)->header.typecookie = NGM_ETHER_COOKIE;
1098 (*resp)->header.cmd = msg->header.cmd;
1099 strncpy((*resp)->header.cmdstr, "status",
1100 NG_CMDSTRLEN);
1101 }
1102 break;
1103 default:
1104 error = EINVAL;
1105 break;
1106 }
1107 break;
1108 default:
1109 error = EINVAL;
1110 break;
1111 }
1112 free(msg, M_NETGRAPH);
1113 return (error);
1114}
1115
1116/*
1117 * Receive a completed ethernet packet.
1118 * Queue it for output.
1119 */
1120static int
1121ngether_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
1122{
1123 struct ifnet *ifp;
1124 int error = 0;
1125 int s;
1126 struct ether_header *eh;
1127
1128 ifp = hook->node->private;
1129
1130 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
1131 senderr(ENETDOWN);
1132 /* drop in the MAC address */
1133 eh = mtod(m, struct ether_header *);
1134 bcopy(IFP2AC(ifp)->ac_enaddr, eh->ether_shost, 6);
1135 /*
1136 * If a simplex interface, and the packet is being sent to our
1137 * Ethernet address or a broadcast address, loopback a copy.
1138 * XXX To make a simplex device behave exactly like a duplex
1139 * device, we should copy in the case of sending to our own
1140 * ethernet address (thus letting the original actually appear
1141 * on the wire). However, we don't do that here for security
1142 * reasons and compatibility with the original behavior.
1143 */
1144 if (ifp->if_flags & IFF_SIMPLEX) {
1145 if (m->m_flags & M_BCAST) {
1146 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
1147
1148 ng_queue_data(hook, n, meta);
1149 } else if (bcmp(eh->ether_dhost,
1150 eh->ether_shost, ETHER_ADDR_LEN) == 0) {
1151 ng_queue_data(hook, m, meta);
1152 return (0); /* XXX */
1153 }
1154 }
1155 s = splimp();
1156 /*
1157 * Queue message on interface, and start output if interface
1158 * not yet active.
1159 * XXX if we lookead at the priority in the meta data we could
1160 * queue high priority items at the head.
1161 */
1162 if (IF_QFULL(&ifp->if_snd)) {
1163 IF_DROP(&ifp->if_snd);
1164 splx(s);
1165 senderr(ENOBUFS);
1166 }
1167 IF_ENQUEUE(&ifp->if_snd, m);
1168 if ((ifp->if_flags & IFF_OACTIVE) == 0)
1169 (*ifp->if_start)(ifp);
1170 splx(s);
1171 ifp->if_obytes += m->m_pkthdr.len;
1172 if (m->m_flags & M_MCAST)
1173 ifp->if_omcasts++;
1174 return (error);
1175
1176bad:
1177 NG_FREE_DATA(m, meta);
1178 return (error);
1179}
1180
1181/*
1182 * pass an mbuf out to the connected hook
1183 * More complicated than just an m_prepend, as it tries to save later nodes
1184 * from needing to do lots of m_pullups.
1185 */
1186static void
1187ngether_send(struct arpcom *ac, struct ether_header *eh, struct mbuf *m)
1188{
1189 int room;
1190 node_p node = AC2NG(ac);
1191 struct ether_header *eh2;
1192
1193 if (node && LIST_FIRST(&(node->hooks))) {
1194 /*
1195 * Possibly the header is already on the front,
1196 */
1197 eh2 = mtod(m, struct ether_header *) - 1;
1198 if ( eh == eh2) {
1199 /*
1200 * This is the case so just move the markers back to
1201 * re-include it. We lucked out.
1202 * This allows us to avoid a yucky m_pullup
1203 * in later nodes if it works.
1204 */
1205 m->m_len += sizeof(*eh);
1206 m->m_data -= sizeof(*eh);
1207 m->m_pkthdr.len += sizeof(*eh);
1208 } else {
1209 /*
1210 * Alternatively there may be room even though
1211 * it is stored somewhere else. If so, copy it in.
1212 * This only safe because we KNOW that this packet has
1213 * just been generated by an ethernet card, so there
1214 * are no aliases to the buffer. (unlike in outgoing
1215 * packets).
1216 * Nearly all ethernet cards will end up producing mbufs
1217 * that fall into these cases. So we are not optimising
1218 * contorted cases.
1219 */
1220
1221 if (m->m_flags & M_EXT) {
1222 room = (mtod(m, caddr_t) - m->m_ext.ext_buf);
1223 if (room > m->m_ext.ext_size) /* garbage */
1224 room = 0; /* fail immediatly */
1225 } else {
1226 room = (mtod(m, caddr_t) - m->m_pktdat);
1227 }
1228 if (room > sizeof (*eh)) {
1229 /* we have room, just copy it and adjust */
1230 m->m_len += sizeof(*eh);
1231 m->m_data -= sizeof(*eh);
1232 m->m_pkthdr.len += sizeof(*eh);
1233 } else {
1234 /*
1235 * Doing anything more is likely to get more
1236 * expensive than it's worth..
1237 * it's probable that everything else is in one
1238 * big lump. The next node will do an m_pullup()
1239 * for exactly the amount of data it needs and
1240 * hopefully everything after that will not
1241 * need one. So let's just use M_PREPEND.
1242 */
1243 M_PREPEND(m, sizeof (*eh), M_DONTWAIT);
1244 if (m == NULL)
1245 return;
1246 }
1247 bcopy ((caddr_t)eh, mtod(m, struct ether_header *),
1248 sizeof(*eh));
1249 }
1250 ng_queue_data(LIST_FIRST(&(node->hooks)), m, NULL);
1251 } else {
1252 m_freem(m);
1253 }
1254}
1255
1256/*
1257 * do local shutdown processing..
1258 * This node will refuse to go away, unless the hardware says to..
1259 * don't unref the node, or remove our name. just clear our links up.
1260 */
1261static int
1262ngether_rmnode(node_p node)
1263{
1264 ng_cutlinks(node);
1265 node->flags &= ~NG_INVALID; /* bounce back to life */
1266 return (0);
1267}
1268
1269/* already linked */
1270static int
1271ngether_connect(hook_p hook)
1272{
1273 /* be really amiable and just say "YUP that's OK by me! " */
1274 return (0);
1275}
1276
1277/*
1278 * notify on hook disconnection (destruction)
1279 *
1280 * For this type, removal of the last lins no effect. The interface can run
1281 * independently.
1282 * Since we have no per-hook information, this is rather simple.
1283 */
1284static int
1285ngether_disconnect(hook_p hook)
1286{
1287 hook->node->flags &= ~NGEF_DIVERT;
1288 return (0);
1289}
1290#endif /* NETGRAPH */
1291
1292/********************************** END *************************************/