1
2 /*
3 * ng_iface.c
4 *
5 * Copyright (c) 1996-1999 Whistle Communications, Inc.
6 * All rights reserved.
7 *
8 * Subject to the following obligations and disclaimer of warranty, use and
9 * redistribution of this software, in source or object code forms, with or
10 * without modifications are expressly permitted by Whistle Communications;
11 * provided, however, that:
12 * 1. Any and all reproductions of the source or object code must include the
13 * copyright notice above and the following disclaimer of warranties; and
14 * 2. No rights are granted, in any manner or form, to use Whistle
15 * Communications, Inc. trademarks, including the mark "WHISTLE
16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17 * such appears in the above copyright notice or in the software.
18 *
19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 *
37 * Author: Archie Cobbs <archie@freebsd.org>
38 *
39 * $FreeBSD$
40 * $Whistle: ng_iface.c,v 1.33 1999/11/01 09:24:51 julian Exp $
41 */
42
43 /*
44 * This node is also a system networking interface. It has
45 * a hook for each protocol (IP, AppleTalk, IPX, etc). Packets
46 * are simply relayed between the interface and the hooks.
47 *
48 * Interfaces are named ng0, ng1, .... FreeBSD does not support
49 * the removal of interfaces, so iface nodes are persistent.
50 *
51 * This node also includes Berkeley packet filter support.
52 */
53
54 #include "opt_inet.h"
55 #include "opt_atalk.h"
56 #include "opt_ipx.h"
57
58 #include <sys/param.h>
59 #include <sys/systm.h>
60 #include <sys/errno.h>
61 #include <sys/kernel.h>
62 #include <sys/malloc.h>
63 #include <sys/mbuf.h>
64 #include <sys/errno.h>
65 #include <sys/sockio.h>
66 #include <sys/socket.h>
67 #include <sys/syslog.h>
68
69 #include <net/if.h>
70 #include <net/if_types.h>
71 #include <net/netisr.h>
72
73 #include <netinet/in.h>
74
75 #include <netgraph/ng_message.h>
76 #include <netgraph/netgraph.h>
77 #include <netgraph/ng_iface.h>
78 #include <netgraph/ng_cisco.h>
79
80 #ifdef INET
81 #include <netinet/in_systm.h>
82 #include <netinet/in_var.h>
83 #include <netinet/in_var.h>
84 #endif
85
86 #ifdef NETATALK
87 #include <netatalk/at.h>
88 #include <netatalk/at_var.h>
89 #endif
90
91 #ifdef IPX
92 #include <netipx/ipx.h>
93 #include <netipx/ipx_if.h>
94 #endif
95
96 #ifdef NS
97 #include <netns/ns.h>
98 #include <netns/ns_if.h>
99 #endif
100
101 #include "bpfilter.h"
102
103 #if NBPFILTER > 0
104 #include <net/bpf.h>
105 #include <net/bpfdesc.h>
106 #endif
107
108 /* This struct describes one address family */
109 struct iffam {
110 char *hookname; /* Name for hook */
111 u_char af; /* Family number */
112 u_char netisr; /* or NETISR_NONE */
113 union {
114 void *_dummy; /* avoid warning */
115 struct ifqueue *inq; /* if netisr */
116 void (*input)(struct mbuf *m); /* if direct input */
117 } u;
118 };
119 typedef const struct iffam *iffam_p;
120
121 #define NETISR_NONE 0xff
122
123 /* List of address families supported by our interface. Each address
124 family has a way to input packets to it, either by calling a function
125 directly (such as ip_input()) or by adding the packet to a queue and
126 setting a NETISR bit. */
127 const static struct iffam gFamilies[] = {
128 #ifdef INET
129 {
130 NG_IFACE_HOOK_INET,
131 AF_INET,
132 NETISR_NONE,
133 { ip_input }
134 },
135 #endif
136 #ifdef NETATALK
137 {
138 NG_IFACE_HOOK_ATALK,
139 AF_APPLETALK,
140 NETISR_ATALK,
141 { &atintrq2 }
142 },
143 #endif
144 #ifdef IPX
145 {
146 NG_IFACE_HOOK_IPX,
147 AF_IPX,
148 NETISR_IPX,
149 { &ipxintrq }
150 },
151 #endif
152 #ifdef NS
153 {
154 NG_IFACE_HOOK_NS,
155 AF_NS,
156 NETISR_NS,
157 { &nsintrq }
158 },
159 #endif
160 };
161 #define NUM_FAMILIES (sizeof(gFamilies) / sizeof(*gFamilies))
162
163 /* Node private data */
164 struct ng_iface_private {
165 struct ifnet *ifp; /* This interface */
166 node_p node; /* Our netgraph node */
167 hook_p hooks[NUM_FAMILIES]; /* Hook for each address family */
168 struct private *next; /* When hung on the free list */
169 };
170 typedef struct ng_iface_private *priv_p;
171
172 /* Interface methods */
173 static void ng_iface_start(struct ifnet *ifp);
174 static int ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
175 static int ng_iface_output(struct ifnet *ifp, struct mbuf *m0,
176 struct sockaddr *dst, struct rtentry *rt0);
177 #if NBPFILTER > 0
178 static void ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, u_int af);
179 #endif
180 #ifdef DEBUG
181 static void ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
182 #endif
183
184 /* Netgraph methods */
185 static ng_constructor_t ng_iface_constructor;
186 static ng_rcvmsg_t ng_iface_rcvmsg;
187 static ng_shutdown_t ng_iface_rmnode;
188 static ng_newhook_t ng_iface_newhook;
189 static ng_rcvdata_t ng_iface_rcvdata;
190 static ng_disconnect_t ng_iface_disconnect;
191
192 /* Helper stuff */
193 static iffam_p get_iffam_from_af(int af);
194 static iffam_p get_iffam_from_hook(priv_p priv, hook_p hook);
195 static iffam_p get_iffam_from_name(const char *name);
196 static hook_p *get_hook_from_iffam(priv_p priv, iffam_p iffam);
197
198 /* Node type descriptor */
199 static struct ng_type typestruct = {
200 NG_VERSION,
201 NG_IFACE_NODE_TYPE,
202 NULL,
203 ng_iface_constructor,
204 ng_iface_rcvmsg,
205 ng_iface_rmnode,
206 ng_iface_newhook,
207 NULL,
208 NULL,
209 ng_iface_rcvdata,
210 ng_iface_rcvdata,
211 ng_iface_disconnect,
212 NULL
213 };
214 NETGRAPH_INIT(iface, &typestruct);
215
216 static char ng_iface_ifname[] = NG_IFACE_IFACE_NAME;
217 static int ng_iface_next_unit;
218
219 /************************************************************************
220 HELPER STUFF
221 ************************************************************************/
222
223 /*
224 * Get the family descriptor from the family ID
225 */
226 static __inline__ iffam_p
227 get_iffam_from_af(int af)
228 {
229 iffam_p iffam;
230 int k;
231
232 for (k = 0; k < NUM_FAMILIES; k++) {
233 iffam = &gFamilies[k];
234 if (iffam->af == af)
235 return (iffam);
236 }
237 return (NULL);
238 }
239
240 /*
241 * Get the family descriptor from the hook
242 */
243 static __inline__ iffam_p
244 get_iffam_from_hook(priv_p priv, hook_p hook)
245 {
246 int k;
247
248 for (k = 0; k < NUM_FAMILIES; k++)
249 if (priv->hooks[k] == hook)
250 return (&gFamilies[k]);
251 return (NULL);
252 }
253
254 /*
255 * Get the hook from the iffam descriptor
256 */
257
258 static __inline__ hook_p *
259 get_hook_from_iffam(priv_p priv, iffam_p iffam)
260 {
261 return (&priv->hooks[iffam - gFamilies]);
262 }
263
264 /*
265 * Get the iffam descriptor from the name
266 */
267 static __inline__ iffam_p
268 get_iffam_from_name(const char *name)
269 {
270 iffam_p iffam;
271 int k;
272
273 for (k = 0; k < NUM_FAMILIES; k++) {
274 iffam = &gFamilies[k];
275 if (!strcmp(iffam->hookname, name))
276 return (iffam);
277 }
278 return (NULL);
279 }
280
281 /************************************************************************
282 INTERFACE STUFF
283 ************************************************************************/
284
285 /*
286 * Process an ioctl for the virtual interface
287 */
288 static int
289 ng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
290 {
291 struct ifreq *const ifr = (struct ifreq *) data;
292 int s, error = 0;
293
294 #ifdef DEBUG
295 ng_iface_print_ioctl(ifp, command, data);
296 #endif
297 s = splimp();
298 switch (command) {
299
300 /* These two are mostly handled at a higher layer */
301 case SIOCSIFADDR:
302 ifp->if_flags |= (IFF_UP | IFF_RUNNING);
303 ifp->if_flags &= ~(IFF_OACTIVE);
304 break;
305 case SIOCGIFADDR:
306 break;
307
308 /* Set flags */
309 case SIOCSIFFLAGS:
310 /*
311 * If the interface is marked up and stopped, then start it.
312 * If it is marked down and running, then stop it.
313 */
314 if (ifr->ifr_flags & IFF_UP) {
315 if (!(ifp->if_flags & IFF_RUNNING)) {
316 ifp->if_flags &= ~(IFF_OACTIVE);
317 ifp->if_flags |= IFF_RUNNING;
318 }
319 } else {
320 if (ifp->if_flags & IFF_RUNNING)
321 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
322 }
323 break;
324
325 /* Set the interface MTU */
326 case SIOCSIFMTU:
327 if (ifr->ifr_mtu > NG_IFACE_MTU_MAX
328 || ifr->ifr_mtu < NG_IFACE_MTU_MIN)
329 error = EINVAL;
330 else
331 ifp->if_mtu = ifr->ifr_mtu;
332 break;
333
334 /* Stuff that's not supported */
335 case SIOCADDMULTI:
336 case SIOCDELMULTI:
337 error = 0;
338 break;
339 case SIOCSIFPHYS:
340 error = EOPNOTSUPP;
341 break;
342
343 default:
344 error = EINVAL;
345 break;
346 }
347 (void) splx(s);
348 return (error);
349 }
350
351 /*
352 * This routine is called to deliver a packet out the interface.
353 * We simply look at the address family and relay the packet to
354 * the corresponding hook, if it exists and is connected.
355 */
356
357 static int
358 ng_iface_output(struct ifnet *ifp, struct mbuf *m,
359 struct sockaddr *dst, struct rtentry *rt0)
360 {
361 const priv_p priv = (priv_p) ifp->if_softc;
362 const iffam_p iffam = get_iffam_from_af(dst->sa_family);
363 meta_p meta = NULL;
364 int len, error = 0;
365
366 /* Check interface flags */
367 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
368 m_freem(m);
369 return (ENETDOWN);
370 }
371
372 /* Berkeley packet filter */
373 #if NBPFILTER > 0
374 ng_iface_bpftap(ifp, m, dst->sa_family);
375 #endif
376
377 /* Check address family to determine hook (if known) */
378 if (iffam == NULL) {
379 m_freem(m);
380 log(LOG_WARNING, "%s%d: can't handle af%d\n",
381 ifp->if_name, ifp->if_unit, dst->sa_family);
382 return (EAFNOSUPPORT);
383 }
384
385 /* Copy length before the mbuf gets invalidated */
386 len = m->m_pkthdr.len;
387
388 /* Send packet; if hook is not connected, mbuf will get freed. */
389 NG_SEND_DATA(error, *get_hook_from_iffam(priv, iffam), m, meta);
390
391 /* Update stats */
392 if (error == 0) {
393 ifp->if_obytes += len;
394 ifp->if_opackets++;
395 }
396 return (error);
397 }
398
399 /*
400 * This routine should never be called
401 */
402
403 static void
404 ng_iface_start(struct ifnet *ifp)
405 {
406 printf("%s%d: %s called?", ifp->if_name, ifp->if_unit, __FUNCTION__);
407 }
408
409 #if NBPFILTER > 0
410 /*
411 * Flash a packet by the BPF (requires prepending 4 byte AF header)
412 * Note the phoney mbuf; this is OK because BPF treats it read-only.
413 */
414 static void
415 ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, u_int af)
416 {
417 struct mbuf m2;
418
419 if (af == AF_UNSPEC) {
420 af = *(mtod(m, int *));
421 m->m_len -= sizeof(int);
422 m->m_pkthdr.len -= sizeof(int);
423 m->m_data += sizeof(int);
424 }
425 if (!ifp->if_bpf)
426 return;
427 m2.m_next = m;
428 m2.m_len = 4;
429 m2.m_data = (char *) ⁡
430 bpf_mtap(ifp, &m2);
431 }
432 #endif /* NBPFILTER > 0 */
433
434 #ifdef DEBUG
435 /*
436 * Display an ioctl to the virtual interface
437 */
438
439 static void
440 ng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
441 {
442 char *str;
443
444 switch (command & IOC_DIRMASK) {
445 case IOC_VOID:
446 str = "IO";
447 break;
448 case IOC_OUT:
449 str = "IOR";
450 break;
451 case IOC_IN:
452 str = "IOW";
453 break;
454 case IOC_INOUT:
455 str = "IORW";
456 break;
457 default:
458 str = "IO??";
459 }
460 log(LOG_DEBUG, "%s%d: %s('%c', %d, char[%d])\n",
461 ifp->if_name, ifp->if_unit,
462 str,
463 IOCGROUP(command),
464 command & 0xff,
465 IOCPARM_LEN(command));
466 }
467 #endif /* DEBUG */
468
469 /************************************************************************
470 NETGRAPH NODE STUFF
471 ************************************************************************/
472
473 /*
474 * Constructor for a node
475 */
476 static int
477 ng_iface_constructor(node_p *nodep)
478 {
479 char ifname[NG_IFACE_IFACE_NAME_MAX + 1];
480 struct ifnet *ifp;
481 node_p node;
482 priv_p priv;
483 int error = 0;
484
485 /* Allocate node and interface private structures */
486 MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH, M_WAITOK);
487 if (priv == NULL)
488 return (ENOMEM);
489 bzero(priv, sizeof(*priv));
490 MALLOC(ifp, struct ifnet *, sizeof(*ifp), M_NETGRAPH, M_WAITOK);
491 if (ifp == NULL) {
492 FREE(priv, M_NETGRAPH);
493 return (ENOMEM);
494 }
495 bzero(ifp, sizeof(*ifp));
496
497 /* Link them together */
498 ifp->if_softc = priv;
499 priv->ifp = ifp;
500
501 /* Call generic node constructor */
502 if ((error = ng_make_node_common(&typestruct, nodep))) {
503 FREE(priv, M_NETGRAPH);
504 FREE(ifp, M_NETGRAPH);
505 return (error);
506 }
507 node = *nodep;
508
509 /* Link together node and private info */
510 node->private = priv;
511 priv->node = node;
512
513 /* Initialize interface structure */
514 ifp->if_name = ng_iface_ifname;
515 ifp->if_unit = ng_iface_next_unit++;
516 ifp->if_output = ng_iface_output;
517 ifp->if_start = ng_iface_start;
518 ifp->if_ioctl = ng_iface_ioctl;
519 ifp->if_watchdog = NULL;
520 ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
521 ifp->if_mtu = NG_IFACE_MTU_DEFAULT;
522 ifp->if_flags = (IFF_SIMPLEX | IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST);
523 ifp->if_type = IFT_PROPVIRTUAL; /* XXX */
524 ifp->if_addrlen = 0; /* XXX */
525 ifp->if_hdrlen = 0; /* XXX */
526 ifp->if_baudrate = 64000; /* XXX */
527 TAILQ_INIT(&ifp->if_addrhead);
528
529 /* Give this node the same name as the interface (if possible) */
530 bzero(ifname, sizeof(ifname));
531 sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit);
532 (void) ng_name_node(node, ifname);
533
534 /* Attach the interface */
535 if_attach(ifp);
536 #if NBPFILTER > 0
537 bpfattach(ifp, DLT_NULL, sizeof(u_int));
538 #endif
539
540 /* Done */
541 return (0);
542 }
543
544 /*
545 * Give our ok for a hook to be added
546 */
547 static int
548 ng_iface_newhook(node_p node, hook_p hook, const char *name)
549 {
550 const iffam_p iffam = get_iffam_from_name(name);
551 hook_p *hookptr;
552
553 if (iffam == NULL)
554 return (EPFNOSUPPORT);
555 hookptr = get_hook_from_iffam((priv_p) node->private, iffam);
556 if (*hookptr != NULL)
557 return (EISCONN);
558 *hookptr = hook;
559 return (0);
560 }
561
562 /*
563 * Receive a control message
564 */
565 static int
566 ng_iface_rcvmsg(node_p node, struct ng_mesg *msg,
567 const char *retaddr, struct ng_mesg **rptr)
568 {
569 const priv_p priv = node->private;
570 struct ifnet *const ifp = priv->ifp;
571 struct ng_mesg *resp = NULL;
572 int error = 0;
573
574 switch (msg->header.typecookie) {
575 case NGM_IFACE_COOKIE:
576 switch (msg->header.cmd) {
577 case NGM_IFACE_GET_IFNAME:
578 {
579 struct ng_iface_ifname *arg;
580
581 NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
582 if (resp == NULL) {
583 error = ENOMEM;
584 break;
585 }
586 arg = (struct ng_iface_ifname *) resp->data;
587 sprintf(arg->ngif_name,
588 "%s%d", ifp->if_name, ifp->if_unit);
589 break;
590 }
591
592 case NGM_IFACE_GET_IFADDRS:
593 {
594 struct ifaddr *ifa;
595 caddr_t ptr;
596 int buflen;
597
598 #define SA_SIZE(s) ((s)->sa_len<sizeof(*(s))? sizeof(*(s)):(s)->sa_len)
599
600 /* Determine size of response and allocate it */
601 buflen = 0;
602 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
603 buflen += SA_SIZE(ifa->ifa_addr);
604 NG_MKRESPONSE(resp, msg, buflen, M_NOWAIT);
605 if (resp == NULL) {
606 error = ENOMEM;
607 break;
608 }
609
610 /* Add addresses */
611 ptr = resp->data;
612 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
613 const int len = SA_SIZE(ifa->ifa_addr);
614
615 if (buflen < len) {
616 log(LOG_ERR, "%s%d: len changed?\n",
617 ifp->if_name, ifp->if_unit);
618 break;
619 }
620 bcopy(ifa->ifa_addr, ptr, len);
621 ptr += len;
622 buflen -= len;
623 }
624 break;
625 #undef SA_SIZE
626 }
627
628 default:
629 error = EINVAL;
630 break;
631 }
632 break;
633 case NGM_CISCO_COOKIE:
634 switch (msg->header.cmd) {
635 case NGM_CISCO_GET_IPADDR: /* we understand this too */
636 {
637 struct ifaddr *ifa;
638
639 /* Return the first configured IP address */
640 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
641 struct in_addr *ips;
642
643 if (ifa->ifa_addr->sa_family != AF_INET)
644 continue;
645 NG_MKRESPONSE(resp, msg,
646 2 * sizeof(*ips), M_NOWAIT);
647 if (resp == NULL) {
648 error = ENOMEM;
649 break;
650 }
651 ips = (struct in_addr *) resp->data;
652 ips[0] = ((struct sockaddr_in *)
653 ifa->ifa_addr)->sin_addr;
654 ips[1] = ((struct sockaddr_in *)
655 ifa->ifa_netmask)->sin_addr;
656 break;
657 }
658
659 /* No IP addresses on this interface? */
660 if (ifa == NULL)
661 error = EADDRNOTAVAIL;
662 break;
663 }
664 default:
665 error = EINVAL;
666 break;
667 }
668 break;
669 default:
670 error = EINVAL;
671 break;
672 }
673 if (rptr)
674 *rptr = resp;
675 else if (resp)
676 FREE(resp, M_NETGRAPH);
677 FREE(msg, M_NETGRAPH);
678 return (error);
679 }
680
681 /*
682 * Recive data from a hook. Pass the packet to the correct input routine.
683 */
684 static int
685 ng_iface_rcvdata(hook_p hook, struct mbuf *m, meta_p meta)
686 {
687 const priv_p priv = hook->node->private;
688 const iffam_p iffam = get_iffam_from_hook(priv, hook);
689 struct ifnet *const ifp = priv->ifp;
690 int s, error = 0;
691
692 /* Sanity checks */
693 KASSERT(iffam != NULL, ("%s: iffam", __FUNCTION__));
694 KASSERT(m->m_flags & M_PKTHDR, ("%s: not pkthdr", __FUNCTION__));
695 if (m == NULL)
696 return (EINVAL);
697 if ((ifp->if_flags & IFF_UP) == 0) {
698 NG_FREE_DATA(m, meta);
699 return (ENETDOWN);
700 }
701
702 /* Update interface stats */
703 ifp->if_ipackets++;
704 ifp->if_ibytes += m->m_pkthdr.len;
705
706 /* Note receiving interface */
707 m->m_pkthdr.rcvif = ifp;
708
709 #if NBPFILTER > 0
710 /* Berkeley packet filter */
711 ng_iface_bpftap(ifp, m, iffam->af);
712 #endif
713
714 /* Ignore any meta-data */
715 NG_FREE_META(meta);
716
717 /* Send packet, either by NETISR or use a direct input function */
718 switch (iffam->netisr) {
719 case NETISR_NONE:
720 (*iffam->u.input)(m);
721 break;
722 default:
723 s = splimp();
724 schednetisr(iffam->netisr);
725 if (IF_QFULL(iffam->u.inq)) {
726 IF_DROP(iffam->u.inq);
727 m_freem(m);
728 error = ENOBUFS;
729 } else
730 IF_ENQUEUE(iffam->u.inq, m);
731 splx(s);
732 break;
733 }
734
735 /* Done */
736 return (error);
737 }
738
739 /*
740 * Because the BSD networking code doesn't support the removal of
741 * networking interfaces, iface nodes (once created) are persistent.
742 * So this method breaks all connections and marks the interface
743 * down, but does not remove the node.
744 */
745 static int
746 ng_iface_rmnode(node_p node)
747 {
748 const priv_p priv = node->private;
749 struct ifnet *const ifp = priv->ifp;
750
751 ng_cutlinks(node);
752 node->flags &= ~NG_INVALID;
753 ifp->if_flags &= ~(IFF_UP | IFF_RUNNING | IFF_OACTIVE);
754 return (0);
755 }
756
757 /*
758 * Hook disconnection
759 */
760 static int
761 ng_iface_disconnect(hook_p hook)
762 {
763 const priv_p priv = hook->node->private;
764 const iffam_p iffam = get_iffam_from_hook(priv, hook);
765
766 if (iffam == NULL)
767 panic(__FUNCTION__);
768 *get_hook_from_iffam(priv, iffam) = NULL;
769 return (0);
770 }
771
Cache object: 51c9a1d244a39766128ccd5ee07bfa23
|