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