]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netgraph/ng_iface.c
Disable the EC GPE in the shutdown path. This is correct but is not known
[FreeBSD/FreeBSD.git] / sys / netgraph / ng_iface.c
1 /*
2  * ng_iface.c
3  *
4  * Copyright (c) 1996-1999 Whistle Communications, Inc.
5  * All rights reserved.
6  * 
7  * Subject to the following obligations and disclaimer of warranty, use and
8  * redistribution of this software, in source or object code forms, with or
9  * without modifications are expressly permitted by Whistle Communications;
10  * provided, however, that:
11  * 1. Any and all reproductions of the source or object code must include the
12  *    copyright notice above and the following disclaimer of warranties; and
13  * 2. No rights are granted, in any manner or form, to use Whistle
14  *    Communications, Inc. trademarks, including the mark "WHISTLE
15  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
16  *    such appears in the above copyright notice or in the software.
17  * 
18  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
19  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
20  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
21  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
23  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
24  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
25  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
26  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
27  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
28  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
29  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
30  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
34  * OF SUCH DAMAGE.
35  *
36  * Author: Archie Cobbs <archie@freebsd.org>
37  *
38  * $FreeBSD$
39  * $Whistle: ng_iface.c,v 1.33 1999/11/01 09:24:51 julian Exp $
40  */
41
42 /*
43  * This node is also a system networking interface. It has
44  * a hook for each protocol (IP, AppleTalk, IPX, etc). Packets
45  * are simply relayed between the interface and the hooks.
46  *
47  * Interfaces are named ng0, ng1, etc.  New nodes take the
48  * first available interface name.
49  *
50  * This node also includes Berkeley packet filter support.
51  */
52
53 #include "opt_atalk.h"
54 #include "opt_inet.h"
55 #include "opt_inet6.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/random.h>
66 #include <sys/sockio.h>
67 #include <sys/socket.h>
68 #include <sys/syslog.h>
69 #include <sys/libkern.h>
70
71 #include <net/if.h>
72 #include <net/if_types.h>
73 #include <net/bpf.h>
74 #include <net/netisr.h>
75
76 #include <netinet/in.h>
77
78 #include <netgraph/ng_message.h>
79 #include <netgraph/netgraph.h>
80 #include <netgraph/ng_parse.h>
81 #include <netgraph/ng_iface.h>
82 #include <netgraph/ng_cisco.h>
83
84 #ifdef NG_SEPARATE_MALLOC
85 MALLOC_DEFINE(M_NETGRAPH_IFACE, "netgraph_iface", "netgraph iface node ");
86 #else
87 #define M_NETGRAPH_IFACE M_NETGRAPH
88 #endif
89
90 /* This struct describes one address family */
91 struct iffam {
92         sa_family_t     family;         /* Address family */
93         const char      *hookname;      /* Name for hook */
94 };
95 typedef const struct iffam *iffam_p;
96
97 /* List of address families supported by our interface */
98 const static struct iffam gFamilies[] = {
99         { AF_INET,      NG_IFACE_HOOK_INET      },
100         { AF_INET6,     NG_IFACE_HOOK_INET6     },
101         { AF_APPLETALK, NG_IFACE_HOOK_ATALK     },
102         { AF_IPX,       NG_IFACE_HOOK_IPX       },
103         { AF_ATM,       NG_IFACE_HOOK_ATM       },
104         { AF_NATM,      NG_IFACE_HOOK_NATM      },
105 };
106 #define NUM_FAMILIES            (sizeof(gFamilies) / sizeof(*gFamilies))
107
108 /* Node private data */
109 struct ng_iface_private {
110         struct  ifnet *ifp;             /* Our interface */
111         int     unit;                   /* Interface unit number */
112         node_p  node;                   /* Our netgraph node */
113         hook_p  hooks[NUM_FAMILIES];    /* Hook for each address family */
114 };
115 typedef struct ng_iface_private *priv_p;
116
117 /* Interface methods */
118 static void     ng_iface_start(struct ifnet *ifp);
119 static int      ng_iface_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
120 static int      ng_iface_output(struct ifnet *ifp, struct mbuf *m0,
121                         struct sockaddr *dst, struct rtentry *rt0);
122 static void     ng_iface_bpftap(struct ifnet *ifp,
123                         struct mbuf *m, sa_family_t family);
124 #ifdef DEBUG
125 static void     ng_iface_print_ioctl(struct ifnet *ifp, int cmd, caddr_t data);
126 #endif
127
128 /* Netgraph methods */
129 static ng_constructor_t ng_iface_constructor;
130 static ng_rcvmsg_t      ng_iface_rcvmsg;
131 static ng_shutdown_t    ng_iface_shutdown;
132 static ng_newhook_t     ng_iface_newhook;
133 static ng_rcvdata_t     ng_iface_rcvdata;
134 static ng_disconnect_t  ng_iface_disconnect;
135
136 /* Helper stuff */
137 static iffam_p  get_iffam_from_af(sa_family_t family);
138 static iffam_p  get_iffam_from_hook(priv_p priv, hook_p hook);
139 static iffam_p  get_iffam_from_name(const char *name);
140 static hook_p  *get_hook_from_iffam(priv_p priv, iffam_p iffam);
141
142 /* Parse type for struct ng_iface_ifname */
143 static const struct ng_parse_fixedstring_info ng_iface_ifname_info = {
144         NG_IFACE_IFACE_NAME_MAX + 1
145 };
146 static const struct ng_parse_type ng_iface_ifname_type = {
147         &ng_parse_fixedstring_type,
148         &ng_iface_ifname_info
149 };
150
151 /* Parse type for struct ng_cisco_ipaddr */
152 static const struct ng_parse_struct_field ng_cisco_ipaddr_type_fields[]
153         = NG_CISCO_IPADDR_TYPE_INFO;
154 static const struct ng_parse_type ng_cisco_ipaddr_type = {
155         &ng_parse_struct_type,
156         &ng_cisco_ipaddr_type_fields
157 };
158
159 /* List of commands and how to convert arguments to/from ASCII */
160 static const struct ng_cmdlist ng_iface_cmds[] = {
161         {
162           NGM_IFACE_COOKIE,
163           NGM_IFACE_GET_IFNAME,
164           "getifname",
165           NULL,
166           &ng_iface_ifname_type
167         },
168         {
169           NGM_IFACE_COOKIE,
170           NGM_IFACE_POINT2POINT,
171           "point2point",
172           NULL,
173           NULL
174         },
175         {
176           NGM_IFACE_COOKIE,
177           NGM_IFACE_BROADCAST,
178           "broadcast",
179           NULL,
180           NULL
181         },
182         {
183           NGM_CISCO_COOKIE,
184           NGM_CISCO_GET_IPADDR,
185           "getipaddr",
186           NULL,
187           &ng_cisco_ipaddr_type
188         },
189         {
190           NGM_IFACE_COOKIE,
191           NGM_IFACE_GET_IFINDEX,
192           "getifindex",
193           NULL,
194           &ng_parse_uint32_type
195         },
196         { 0 }
197 };
198
199 /* Node type descriptor */
200 static struct ng_type typestruct = {
201         .version =      NG_ABI_VERSION,
202         .name =         NG_IFACE_NODE_TYPE,
203         .constructor =  ng_iface_constructor,
204         .rcvmsg =       ng_iface_rcvmsg,
205         .shutdown =     ng_iface_shutdown,
206         .newhook =      ng_iface_newhook,
207         .rcvdata =      ng_iface_rcvdata,
208         .disconnect =   ng_iface_disconnect,
209         .cmdlist =      ng_iface_cmds,
210 };
211 NETGRAPH_INIT(iface, &typestruct);
212
213 /* We keep a bitmap indicating which unit numbers are free.
214    One means the unit number is free, zero means it's taken. */
215 static int      *ng_iface_units = NULL;
216 static int      ng_iface_units_len = 0;
217 static int      ng_units_in_use = 0;
218
219 #define UNITS_BITSPERWORD       (sizeof(*ng_iface_units) * NBBY)
220
221 /************************************************************************
222                         HELPER STUFF
223  ************************************************************************/
224
225 /*
226  * Get the family descriptor from the family ID
227  */
228 static __inline__ iffam_p
229 get_iffam_from_af(sa_family_t family)
230 {
231         iffam_p iffam;
232         int k;
233
234         for (k = 0; k < NUM_FAMILIES; k++) {
235                 iffam = &gFamilies[k];
236                 if (iffam->family == family)
237                         return (iffam);
238         }
239         return (NULL);
240 }
241
242 /*
243  * Get the family descriptor from the hook
244  */
245 static __inline__ iffam_p
246 get_iffam_from_hook(priv_p priv, hook_p hook)
247 {
248         int k;
249
250         for (k = 0; k < NUM_FAMILIES; k++)
251                 if (priv->hooks[k] == hook)
252                         return (&gFamilies[k]);
253         return (NULL);
254 }
255
256 /*
257  * Get the hook from the iffam descriptor
258  */
259
260 static __inline__ hook_p *
261 get_hook_from_iffam(priv_p priv, iffam_p iffam)
262 {
263         return (&priv->hooks[iffam - gFamilies]);
264 }
265
266 /*
267  * Get the iffam descriptor from the name
268  */
269 static __inline__ iffam_p
270 get_iffam_from_name(const char *name)
271 {
272         iffam_p iffam;
273         int k;
274
275         for (k = 0; k < NUM_FAMILIES; k++) {
276                 iffam = &gFamilies[k];
277                 if (!strcmp(iffam->hookname, name))
278                         return (iffam);
279         }
280         return (NULL);
281 }
282
283 /*
284  * Find the first free unit number for a new interface.
285  * Increase the size of the unit bitmap as necessary.
286  */
287 static __inline__ int
288 ng_iface_get_unit(int *unit)
289 {
290         int index, bit;
291
292         for (index = 0; index < ng_iface_units_len
293             && ng_iface_units[index] == 0; index++);
294         if (index == ng_iface_units_len) {              /* extend array */
295                 int i, *newarray, newlen;
296
297                 newlen = (2 * ng_iface_units_len) + 4;
298                 MALLOC(newarray, int *, newlen * sizeof(*ng_iface_units),
299                     M_NETGRAPH_IFACE, M_NOWAIT);
300                 if (newarray == NULL)
301                         return (ENOMEM);
302                 bcopy(ng_iface_units, newarray,
303                     ng_iface_units_len * sizeof(*ng_iface_units));
304                 for (i = ng_iface_units_len; i < newlen; i++)
305                         newarray[i] = ~0;
306                 if (ng_iface_units != NULL)
307                         FREE(ng_iface_units, M_NETGRAPH_IFACE);
308                 ng_iface_units = newarray;
309                 ng_iface_units_len = newlen;
310         }
311         bit = ffs(ng_iface_units[index]) - 1;
312         KASSERT(bit >= 0 && bit <= UNITS_BITSPERWORD - 1,
313             ("%s: word=%d bit=%d", __func__, ng_iface_units[index], bit));
314         ng_iface_units[index] &= ~(1 << bit);
315         *unit = (index * UNITS_BITSPERWORD) + bit;
316         ng_units_in_use++;
317         return (0);
318 }
319
320 /*
321  * Free a no longer needed unit number.
322  */
323 static __inline__ void
324 ng_iface_free_unit(int unit)
325 {
326         int index, bit;
327
328         index = unit / UNITS_BITSPERWORD;
329         bit = unit % UNITS_BITSPERWORD;
330         KASSERT(index < ng_iface_units_len,
331             ("%s: unit=%d len=%d", __func__, unit, ng_iface_units_len));
332         KASSERT((ng_iface_units[index] & (1 << bit)) == 0,
333             ("%s: unit=%d is free", __func__, unit));
334         ng_iface_units[index] |= (1 << bit);
335         /*
336          * XXX We could think about reducing the size of ng_iface_units[]
337          * XXX here if the last portion is all ones
338          * XXX At least free it if no more units.
339          * Needed if we are to eventually be able to unload.
340          */
341         ng_units_in_use--;
342         if (ng_units_in_use == 0) { /* XXX make SMP safe */
343                 FREE(ng_iface_units, M_NETGRAPH_IFACE);
344                 ng_iface_units_len = 0;
345                 ng_iface_units = NULL;
346         }
347 }
348
349 /************************************************************************
350                         INTERFACE STUFF
351  ************************************************************************/
352
353 /*
354  * Process an ioctl for the virtual interface
355  */
356 static int
357 ng_iface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
358 {
359         struct ifreq *const ifr = (struct ifreq *) data;
360         int s, error = 0;
361
362 #ifdef DEBUG
363         ng_iface_print_ioctl(ifp, command, data);
364 #endif
365         s = splimp();
366         switch (command) {
367
368         /* These two are mostly handled at a higher layer */
369         case SIOCSIFADDR:
370                 ifp->if_flags |= (IFF_UP | IFF_RUNNING);
371                 ifp->if_flags &= ~(IFF_OACTIVE);
372                 break;
373         case SIOCGIFADDR:
374                 break;
375
376         /* Set flags */
377         case SIOCSIFFLAGS:
378                 /*
379                  * If the interface is marked up and stopped, then start it.
380                  * If it is marked down and running, then stop it.
381                  */
382                 if (ifr->ifr_flags & IFF_UP) {
383                         if (!(ifp->if_flags & IFF_RUNNING)) {
384                                 ifp->if_flags &= ~(IFF_OACTIVE);
385                                 ifp->if_flags |= IFF_RUNNING;
386                         }
387                 } else {
388                         if (ifp->if_flags & IFF_RUNNING)
389                                 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
390                 }
391                 break;
392
393         /* Set the interface MTU */
394         case SIOCSIFMTU:
395                 if (ifr->ifr_mtu > NG_IFACE_MTU_MAX
396                     || ifr->ifr_mtu < NG_IFACE_MTU_MIN)
397                         error = EINVAL;
398                 else
399                         ifp->if_mtu = ifr->ifr_mtu;
400                 break;
401
402         /* Stuff that's not supported */
403         case SIOCADDMULTI:
404         case SIOCDELMULTI:
405                 error = 0;
406                 break;
407         case SIOCSIFPHYS:
408                 error = EOPNOTSUPP;
409                 break;
410
411         default:
412                 error = EINVAL;
413                 break;
414         }
415         (void) splx(s);
416         return (error);
417 }
418
419 /*
420  * This routine is called to deliver a packet out the interface.
421  * We simply look at the address family and relay the packet to
422  * the corresponding hook, if it exists and is connected.
423  */
424
425 static int
426 ng_iface_output(struct ifnet *ifp, struct mbuf *m,
427                 struct sockaddr *dst, struct rtentry *rt0)
428 {
429         const priv_p priv = (priv_p) ifp->if_softc;
430         const iffam_p iffam = get_iffam_from_af(dst->sa_family);
431         int len, error = 0;
432
433         /* Check interface flags */
434         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
435                 m_freem(m);
436                 return (ENETDOWN);
437         }
438
439         /* BPF writes need to be handled specially */
440         if (dst->sa_family == AF_UNSPEC) {
441                 if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL)
442                         return (ENOBUFS);
443                 dst->sa_family = (sa_family_t)*mtod(m, int32_t *);
444                 m->m_data += 4;
445                 m->m_len -= 4;
446                 m->m_pkthdr.len -= 4;
447         }
448
449         /* Berkeley packet filter */
450         ng_iface_bpftap(ifp, m, dst->sa_family);
451
452         /* Check address family to determine hook (if known) */
453         if (iffam == NULL) {
454                 m_freem(m);
455                 log(LOG_WARNING, "%s: can't handle af%d\n",
456                        ifp->if_xname, (int)dst->sa_family);
457                 return (EAFNOSUPPORT);
458         }
459
460         /* Copy length before the mbuf gets invalidated */
461         len = m->m_pkthdr.len;
462
463         /* Send packet; if hook is not connected, mbuf will get freed. */
464         NG_SEND_DATA_ONLY(error, *get_hook_from_iffam(priv, iffam), m);
465
466         /* Update stats */
467         if (error == 0) {
468                 ifp->if_obytes += len;
469                 ifp->if_opackets++;
470         }
471         return (error);
472 }
473
474 /*
475  * This routine should never be called
476  */
477
478 static void
479 ng_iface_start(struct ifnet *ifp)
480 {
481         if_printf(ifp, "%s called?", __func__);
482 }
483
484 /*
485  * Flash a packet by the BPF (requires prepending 4 byte AF header)
486  * Note the phoney mbuf; this is OK because BPF treats it read-only.
487  */
488 static void
489 ng_iface_bpftap(struct ifnet *ifp, struct mbuf *m, sa_family_t family)
490 {
491         KASSERT(family != AF_UNSPEC, ("%s: family=AF_UNSPEC", __func__));
492         if (ifp->if_bpf != NULL) {
493                 int32_t family4 = (int32_t)family;
494                 bpf_mtap2(ifp->if_bpf, &family4, sizeof(family4), m);
495         }
496 }
497
498 #ifdef DEBUG
499 /*
500  * Display an ioctl to the virtual interface
501  */
502
503 static void
504 ng_iface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
505 {
506         char   *str;
507
508         switch (command & IOC_DIRMASK) {
509         case IOC_VOID:
510                 str = "IO";
511                 break;
512         case IOC_OUT:
513                 str = "IOR";
514                 break;
515         case IOC_IN:
516                 str = "IOW";
517                 break;
518         case IOC_INOUT:
519                 str = "IORW";
520                 break;
521         default:
522                 str = "IO??";
523         }
524         log(LOG_DEBUG, "%s: %s('%c', %d, char[%d])\n",
525                ifp->if_xname,
526                str,
527                IOCGROUP(command),
528                command & 0xff,
529                IOCPARM_LEN(command));
530 }
531 #endif /* DEBUG */
532
533 /************************************************************************
534                         NETGRAPH NODE STUFF
535  ************************************************************************/
536
537 /*
538  * Constructor for a node
539  */
540 static int
541 ng_iface_constructor(node_p node)
542 {
543         char ifname[NG_IFACE_IFACE_NAME_MAX + 1];
544         struct ifnet *ifp;
545         priv_p priv;
546         int error = 0;
547
548         /* Allocate node and interface private structures */
549         MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH_IFACE, M_NOWAIT|M_ZERO);
550         if (priv == NULL)
551                 return (ENOMEM);
552         MALLOC(ifp, struct ifnet *, sizeof(*ifp), M_NETGRAPH_IFACE, M_NOWAIT|M_ZERO);
553         if (ifp == NULL) {
554                 FREE(priv, M_NETGRAPH_IFACE);
555                 return (ENOMEM);
556         }
557
558         /* Link them together */
559         ifp->if_softc = priv;
560         priv->ifp = ifp;
561
562         /* Get an interface unit number */
563         if ((error = ng_iface_get_unit(&priv->unit)) != 0) {
564                 FREE(ifp, M_NETGRAPH_IFACE);
565                 FREE(priv, M_NETGRAPH_IFACE);
566                 return (error);
567         }
568
569         /* Link together node and private info */
570         NG_NODE_SET_PRIVATE(node, priv);
571         priv->node = node;
572
573         /* Initialize interface structure */
574         if_initname(ifp, NG_IFACE_IFACE_NAME, priv->unit);
575         ifp->if_output = ng_iface_output;
576         ifp->if_start = ng_iface_start;
577         ifp->if_ioctl = ng_iface_ioctl;
578         ifp->if_watchdog = NULL;
579         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
580         ifp->if_mtu = NG_IFACE_MTU_DEFAULT;
581         ifp->if_flags = (IFF_SIMPLEX|IFF_POINTOPOINT|IFF_NOARP|IFF_MULTICAST);
582         ifp->if_type = IFT_PROPVIRTUAL;         /* XXX */
583         ifp->if_addrlen = 0;                    /* XXX */
584         ifp->if_hdrlen = 0;                     /* XXX */
585         ifp->if_baudrate = 64000;               /* XXX */
586         TAILQ_INIT(&ifp->if_addrhead);
587
588         /* Give this node the same name as the interface (if possible) */
589         bzero(ifname, sizeof(ifname));
590         strlcpy(ifname, ifp->if_xname, sizeof(ifname));
591         if (ng_name_node(node, ifname) != 0)
592                 log(LOG_WARNING, "%s: can't acquire netgraph name\n", ifname);
593
594         /* Attach the interface */
595         if_attach(ifp);
596         bpfattach(ifp, DLT_NULL, sizeof(u_int));
597
598         /* Done */
599         return (0);
600 }
601
602 /*
603  * Give our ok for a hook to be added
604  */
605 static int
606 ng_iface_newhook(node_p node, hook_p hook, const char *name)
607 {
608         const iffam_p iffam = get_iffam_from_name(name);
609         hook_p *hookptr;
610
611         if (iffam == NULL)
612                 return (EPFNOSUPPORT);
613         hookptr = get_hook_from_iffam(NG_NODE_PRIVATE(node), iffam);
614         if (*hookptr != NULL)
615                 return (EISCONN);
616         *hookptr = hook;
617         return (0);
618 }
619
620 /*
621  * Receive a control message
622  */
623 static int
624 ng_iface_rcvmsg(node_p node, item_p item, hook_p lasthook)
625 {
626         const priv_p priv = NG_NODE_PRIVATE(node);
627         struct ifnet *const ifp = priv->ifp;
628         struct ng_mesg *resp = NULL;
629         int error = 0;
630         struct ng_mesg *msg;
631
632         NGI_GET_MSG(item, msg);
633         switch (msg->header.typecookie) {
634         case NGM_IFACE_COOKIE:
635                 switch (msg->header.cmd) {
636                 case NGM_IFACE_GET_IFNAME:
637                     {
638                         struct ng_iface_ifname *arg;
639
640                         NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
641                         if (resp == NULL) {
642                                 error = ENOMEM;
643                                 break;
644                         }
645                         arg = (struct ng_iface_ifname *)resp->data;
646                         strlcpy(arg->ngif_name, ifp->if_xname,
647                             sizeof(arg->ngif_name));
648                         break;
649                     }
650
651                 case NGM_IFACE_POINT2POINT:
652                 case NGM_IFACE_BROADCAST:
653                     {
654
655                         /* Deny request if interface is UP */
656                         if ((ifp->if_flags & IFF_UP) != 0)
657                                 return (EBUSY);
658
659                         /* Change flags */
660                         switch (msg->header.cmd) {
661                         case NGM_IFACE_POINT2POINT:
662                                 ifp->if_flags |= IFF_POINTOPOINT;
663                                 ifp->if_flags &= ~IFF_BROADCAST;
664                                 break;
665                         case NGM_IFACE_BROADCAST:
666                                 ifp->if_flags &= ~IFF_POINTOPOINT;
667                                 ifp->if_flags |= IFF_BROADCAST;
668                                 break;
669                         }
670                         break;
671                     }
672
673                 case NGM_IFACE_GET_IFINDEX:
674                         NG_MKRESPONSE(resp, msg, sizeof(uint32_t), M_NOWAIT);
675                         if (resp == NULL) {
676                                 error = ENOMEM;
677                                 break;
678                         }
679                         *((uint32_t *)resp->data) = priv->ifp->if_index;
680                         break;
681
682                 default:
683                         error = EINVAL;
684                         break;
685                 }
686                 break;
687         case NGM_CISCO_COOKIE:
688                 switch (msg->header.cmd) {
689                 case NGM_CISCO_GET_IPADDR:      /* we understand this too */
690                     {
691                         struct ifaddr *ifa;
692
693                         /* Return the first configured IP address */
694                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
695                                 struct ng_cisco_ipaddr *ips;
696
697                                 if (ifa->ifa_addr->sa_family != AF_INET)
698                                         continue;
699                                 NG_MKRESPONSE(resp, msg, sizeof(ips), M_NOWAIT);
700                                 if (resp == NULL) {
701                                         error = ENOMEM;
702                                         break;
703                                 }
704                                 ips = (struct ng_cisco_ipaddr *)resp->data;
705                                 ips->ipaddr = ((struct sockaddr_in *)
706                                                 ifa->ifa_addr)->sin_addr;
707                                 ips->netmask = ((struct sockaddr_in *)
708                                                 ifa->ifa_netmask)->sin_addr;
709                                 break;
710                         }
711
712                         /* No IP addresses on this interface? */
713                         if (ifa == NULL)
714                                 error = EADDRNOTAVAIL;
715                         break;
716                     }
717                 default:
718                         error = EINVAL;
719                         break;
720                 }
721                 break;
722         default:
723                 error = EINVAL;
724                 break;
725         }
726         NG_RESPOND_MSG(error, node, item, resp);
727         NG_FREE_MSG(msg);
728         return (error);
729 }
730
731 /*
732  * Recive data from a hook. Pass the packet to the correct input routine.
733  */
734 static int
735 ng_iface_rcvdata(hook_p hook, item_p item)
736 {
737         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
738         const iffam_p iffam = get_iffam_from_hook(priv, hook);
739         struct ifnet *const ifp = priv->ifp;
740         struct mbuf *m;
741         int isr;
742
743         NGI_GET_M(item, m);
744         NG_FREE_ITEM(item);
745         /* Sanity checks */
746         KASSERT(iffam != NULL, ("%s: iffam", __func__));
747         M_ASSERTPKTHDR(m);
748         if ((ifp->if_flags & IFF_UP) == 0) {
749                 NG_FREE_M(m);
750                 return (ENETDOWN);
751         }
752
753         /* Update interface stats */
754         ifp->if_ipackets++;
755         ifp->if_ibytes += m->m_pkthdr.len;
756
757         /* Note receiving interface */
758         m->m_pkthdr.rcvif = ifp;
759
760         /* Berkeley packet filter */
761         ng_iface_bpftap(ifp, m, iffam->family);
762
763         /* Send packet */
764         switch (iffam->family) {
765 #ifdef INET
766         case AF_INET:
767                 isr = NETISR_IP;
768                 break;
769 #endif
770 #ifdef INET6
771         case AF_INET6:
772                 isr = NETISR_IPV6;
773                 break;
774 #endif
775 #ifdef IPX
776         case AF_IPX:
777                 isr = NETISR_IPX;
778                 break;
779 #endif
780 #ifdef NETATALK
781         case AF_APPLETALK:
782                 isr = NETISR_ATALK2;
783                 break;
784 #endif
785         default:
786                 m_freem(m);
787                 return (EAFNOSUPPORT);
788         }
789         /* First chunk of an mbuf contains good junk */
790         if (harvest.point_to_point)
791                 random_harvest(m, 16, 3, 0, RANDOM_NET);
792         netisr_dispatch(isr, m);
793         return (0);
794 }
795
796 /*
797  * Shutdown and remove the node and its associated interface.
798  */
799 static int
800 ng_iface_shutdown(node_p node)
801 {
802         const priv_p priv = NG_NODE_PRIVATE(node);
803
804         bpfdetach(priv->ifp);
805         if_detach(priv->ifp);
806         FREE(priv->ifp, M_NETGRAPH_IFACE);
807         priv->ifp = NULL;
808         ng_iface_free_unit(priv->unit);
809         FREE(priv, M_NETGRAPH_IFACE);
810         NG_NODE_SET_PRIVATE(node, NULL);
811         NG_NODE_UNREF(node);
812         return (0);
813 }
814
815 /*
816  * Hook disconnection. Note that we do *not* shutdown when all
817  * hooks have been disconnected.
818  */
819 static int
820 ng_iface_disconnect(hook_p hook)
821 {
822         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
823         const iffam_p iffam = get_iffam_from_hook(priv, hook);
824
825         if (iffam == NULL)
826                 panic(__func__);
827         *get_hook_from_iffam(priv, iffam) = NULL;
828         return (0);
829 }
830