5 * Copyright (c) 1996-1999 Whistle Communications, Inc.
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.
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
37 * Author: Archie Cobbs <archie@freebsd.org>
39 * $FreeBSD: src/sys/netgraph/ng_iface.c,v 1.7.2.5 2002/07/02 23:44:02 archie Exp $
40 * $DragonFly: src/sys/netgraph/iface/ng_iface.c,v 1.13 2006/12/23 00:44:57 swildner Exp $
41 * $Whistle: ng_iface.c,v 1.33 1999/11/01 09:24:51 julian Exp $
45 * This node is also a system networking interface. It has
46 * a hook for each protocol (IP, AppleTalk, IPX, etc). Packets
47 * are simply relayed between the interface and the hooks.
49 * Interfaces are named ng0, ng1, etc. New nodes take the
50 * first available interface name.
52 * This node also includes Berkeley packet filter support.
55 #include "opt_atalk.h"
57 #include "opt_inet6.h"
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/errno.h>
63 #include <sys/kernel.h>
64 #include <sys/malloc.h>
66 #include <sys/errno.h>
67 #include <sys/sockio.h>
68 #include <sys/socket.h>
69 #include <sys/syslog.h>
70 #include <sys/libkern.h>
71 #include <sys/thread2.h>
74 #include <net/if_types.h>
75 #include <net/netisr.h>
78 #include <netinet/in.h>
80 #include <netgraph/ng_message.h>
81 #include <netgraph/netgraph.h>
82 #include <netgraph/ng_parse.h>
84 #include <netgraph/cisco/ng_cisco.h>
86 /* This struct describes one address family */
88 sa_family_t family
; /* Address family */
89 const char *hookname
; /* Name for hook */
91 typedef const struct iffam
*iffam_p
;
93 /* List of address families supported by our interface */
94 const static struct iffam gFamilies
[] = {
95 { AF_INET
, NG_IFACE_HOOK_INET
},
96 { AF_INET6
, NG_IFACE_HOOK_INET6
},
97 { AF_APPLETALK
, NG_IFACE_HOOK_ATALK
},
98 { AF_IPX
, NG_IFACE_HOOK_IPX
},
99 { AF_ATM
, NG_IFACE_HOOK_ATM
},
100 { AF_NATM
, NG_IFACE_HOOK_NATM
},
101 { AF_NS
, NG_IFACE_HOOK_NS
},
103 #define NUM_FAMILIES (sizeof(gFamilies) / sizeof(*gFamilies))
105 /* Node private data */
106 struct ng_iface_private
{
107 struct ifnet
*ifp
; /* Our interface */
108 int unit
; /* Interface unit number */
109 node_p node
; /* Our netgraph node */
110 hook_p hooks
[NUM_FAMILIES
]; /* Hook for each address family */
112 typedef struct ng_iface_private
*priv_p
;
114 /* Interface methods */
115 static void ng_iface_start(struct ifnet
*ifp
);
116 static int ng_iface_ioctl(struct ifnet
*ifp
, u_long cmd
, caddr_t data
,
118 static int ng_iface_output(struct ifnet
*ifp
, struct mbuf
*m0
,
119 struct sockaddr
*dst
, struct rtentry
*rt0
);
120 static void ng_iface_bpftap(struct ifnet
*ifp
,
121 struct mbuf
*m
, sa_family_t family
);
123 static void ng_iface_print_ioctl(struct ifnet
*ifp
, int cmd
, caddr_t data
);
126 /* Netgraph methods */
127 static ng_constructor_t ng_iface_constructor
;
128 static ng_rcvmsg_t ng_iface_rcvmsg
;
129 static ng_shutdown_t ng_iface_rmnode
;
130 static ng_newhook_t ng_iface_newhook
;
131 static ng_rcvdata_t ng_iface_rcvdata
;
132 static ng_disconnect_t ng_iface_disconnect
;
135 static iffam_p
get_iffam_from_af(sa_family_t family
);
136 static iffam_p
get_iffam_from_hook(priv_p priv
, hook_p hook
);
137 static iffam_p
get_iffam_from_name(const char *name
);
138 static hook_p
*get_hook_from_iffam(priv_p priv
, iffam_p iffam
);
140 /* Parse type for struct ng_iface_ifname */
141 static const struct ng_parse_fixedstring_info ng_iface_ifname_info
= {
142 NG_IFACE_IFACE_NAME_MAX
+ 1
144 static const struct ng_parse_type ng_iface_ifname_type
= {
145 &ng_parse_fixedstring_type
,
146 &ng_iface_ifname_info
149 /* Parse type for struct ng_cisco_ipaddr */
150 static const struct ng_parse_struct_field ng_cisco_ipaddr_type_fields
[]
151 = NG_CISCO_IPADDR_TYPE_INFO
;
152 static const struct ng_parse_type ng_cisco_ipaddr_type
= {
153 &ng_parse_struct_type
,
154 &ng_cisco_ipaddr_type_fields
157 /* List of commands and how to convert arguments to/from ASCII */
158 static const struct ng_cmdlist ng_iface_cmds
[] = {
161 NGM_IFACE_GET_IFNAME
,
164 &ng_iface_ifname_type
168 NGM_IFACE_POINT2POINT
,
182 NGM_CISCO_GET_IPADDR
,
185 &ng_cisco_ipaddr_type
190 /* Node type descriptor */
191 static struct ng_type typestruct
= {
195 ng_iface_constructor
,
206 NETGRAPH_INIT(iface
, &typestruct
);
208 /* We keep a bitmap indicating which unit numbers are free.
209 One means the unit number is free, zero means it's taken. */
210 static int *ng_iface_units
= NULL
;
211 static int ng_iface_units_len
= 0;
213 #define UNITS_BITSPERWORD (sizeof(*ng_iface_units) * NBBY)
215 /************************************************************************
217 ************************************************************************/
220 * Get the family descriptor from the family ID
222 static __inline__ iffam_p
223 get_iffam_from_af(sa_family_t family
)
228 for (k
= 0; k
< NUM_FAMILIES
; k
++) {
229 iffam
= &gFamilies
[k
];
230 if (iffam
->family
== family
)
237 * Get the family descriptor from the hook
239 static __inline__ iffam_p
240 get_iffam_from_hook(priv_p priv
, hook_p hook
)
244 for (k
= 0; k
< NUM_FAMILIES
; k
++)
245 if (priv
->hooks
[k
] == hook
)
246 return (&gFamilies
[k
]);
251 * Get the hook from the iffam descriptor
254 static __inline__ hook_p
*
255 get_hook_from_iffam(priv_p priv
, iffam_p iffam
)
257 return (&priv
->hooks
[iffam
- gFamilies
]);
261 * Get the iffam descriptor from the name
263 static __inline__ iffam_p
264 get_iffam_from_name(const char *name
)
269 for (k
= 0; k
< NUM_FAMILIES
; k
++) {
270 iffam
= &gFamilies
[k
];
271 if (!strcmp(iffam
->hookname
, name
))
278 * Find the first free unit number for a new interface.
279 * Increase the size of the unit bitmap as necessary.
281 static __inline__
int
282 ng_iface_get_unit(int *unit
)
286 for (index
= 0; index
< ng_iface_units_len
287 && ng_iface_units
[index
] == 0; index
++);
288 if (index
== ng_iface_units_len
) { /* extend array */
289 int i
, *newarray
, newlen
;
291 newlen
= (2 * ng_iface_units_len
) + 4;
292 MALLOC(newarray
, int *, newlen
* sizeof(*ng_iface_units
),
293 M_NETGRAPH
, M_NOWAIT
);
294 if (newarray
== NULL
)
296 bcopy(ng_iface_units
, newarray
,
297 ng_iface_units_len
* sizeof(*ng_iface_units
));
298 for (i
= ng_iface_units_len
; i
< newlen
; i
++)
300 if (ng_iface_units
!= NULL
)
301 FREE(ng_iface_units
, M_NETGRAPH
);
302 ng_iface_units
= newarray
;
303 ng_iface_units_len
= newlen
;
305 bit
= ffs(ng_iface_units
[index
]) - 1;
306 KASSERT(bit
>= 0 && bit
<= UNITS_BITSPERWORD
- 1,
307 ("%s: word=%d bit=%d", __func__
, ng_iface_units
[index
], bit
));
308 ng_iface_units
[index
] &= ~(1 << bit
);
309 *unit
= (index
* UNITS_BITSPERWORD
) + bit
;
314 * Free a no longer needed unit number.
316 static __inline__
void
317 ng_iface_free_unit(int unit
)
321 index
= unit
/ UNITS_BITSPERWORD
;
322 bit
= unit
% UNITS_BITSPERWORD
;
323 KASSERT(index
< ng_iface_units_len
,
324 ("%s: unit=%d len=%d", __func__
, unit
, ng_iface_units_len
));
325 KASSERT((ng_iface_units
[index
] & (1 << bit
)) == 0,
326 ("%s: unit=%d is free", __func__
, unit
));
327 ng_iface_units
[index
] |= (1 << bit
);
329 * XXX We could think about reducing the size of ng_iface_units[]
330 * XXX here if the last portion is all ones
334 /************************************************************************
336 ************************************************************************/
339 * Process an ioctl for the virtual interface
342 ng_iface_ioctl(struct ifnet
*ifp
, u_long command
, caddr_t data
,
345 struct ifreq
*const ifr
= (struct ifreq
*) data
;
349 ng_iface_print_ioctl(ifp
, command
, data
);
354 /* These two are mostly handled at a higher layer */
356 ifp
->if_flags
|= (IFF_UP
| IFF_RUNNING
);
357 ifp
->if_flags
&= ~(IFF_OACTIVE
);
365 * If the interface is marked up and stopped, then start it.
366 * If it is marked down and running, then stop it.
368 if (ifr
->ifr_flags
& IFF_UP
) {
369 if (!(ifp
->if_flags
& IFF_RUNNING
)) {
370 ifp
->if_flags
&= ~(IFF_OACTIVE
);
371 ifp
->if_flags
|= IFF_RUNNING
;
374 if (ifp
->if_flags
& IFF_RUNNING
)
375 ifp
->if_flags
&= ~(IFF_RUNNING
| IFF_OACTIVE
);
379 /* Set the interface MTU */
381 if (ifr
->ifr_mtu
> NG_IFACE_MTU_MAX
382 || ifr
->ifr_mtu
< NG_IFACE_MTU_MIN
)
385 ifp
->if_mtu
= ifr
->ifr_mtu
;
388 /* Stuff that's not supported */
406 * This routine is called to deliver a packet out the interface.
407 * We simply look at the address family and relay the packet to
408 * the corresponding hook, if it exists and is connected.
412 ng_iface_output(struct ifnet
*ifp
, struct mbuf
*m
,
413 struct sockaddr
*dst
, struct rtentry
*rt0
)
415 const priv_p priv
= (priv_p
) ifp
->if_softc
;
416 const iffam_p iffam
= get_iffam_from_af(dst
->sa_family
);
420 /* Check interface flags */
421 if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
)) {
426 /* BPF writes need to be handled specially */
427 if (dst
->sa_family
== AF_UNSPEC
) {
428 if (m
->m_len
< 4 && (m
= m_pullup(m
, 4)) == NULL
)
430 dst
->sa_family
= (sa_family_t
)*mtod(m
, int32_t *);
433 m
->m_pkthdr
.len
-= 4;
436 /* Berkeley packet filter */
437 ng_iface_bpftap(ifp
, m
, dst
->sa_family
);
439 /* Check address family to determine hook (if known) */
442 log(LOG_WARNING
, "%s: can't handle af%d\n",
443 ifp
->if_xname
, (int)dst
->sa_family
);
444 return (EAFNOSUPPORT
);
447 /* Copy length before the mbuf gets invalidated */
448 len
= m
->m_pkthdr
.len
;
450 /* Send packet; if hook is not connected, mbuf will get freed. */
451 NG_SEND_DATA(error
, *get_hook_from_iffam(priv
, iffam
), m
, meta
);
455 ifp
->if_obytes
+= len
;
462 * This routine should never be called
466 ng_iface_start(struct ifnet
*ifp
)
468 kprintf("%s: %s called?", ifp
->if_xname
, __func__
);
472 * Flash a packet by the BPF (requires prepending 4 byte AF header)
475 ng_iface_bpftap(struct ifnet
*ifp
, struct mbuf
*m
, sa_family_t family
)
477 int32_t family4
= (int32_t)family
;
479 KASSERT(family
!= AF_UNSPEC
, ("%s: family=AF_UNSPEC", __func__
));
482 bpf_ptap(ifp
->if_bpf
, m
, &family
, sizeof(family4
));
487 * Display an ioctl to the virtual interface
491 ng_iface_print_ioctl(struct ifnet
*ifp
, int command
, caddr_t data
)
495 switch (command
& IOC_DIRMASK
) {
511 log(LOG_DEBUG
, "%s: %s('%c', %d, char[%d])\n",
516 IOCPARM_LEN(command
));
520 /************************************************************************
522 ************************************************************************/
525 * Constructor for a node
528 ng_iface_constructor(node_p
*nodep
)
530 char ifname
[NG_IFACE_IFACE_NAME_MAX
+ 1];
536 /* Allocate node and interface private structures */
537 MALLOC(priv
, priv_p
, sizeof(*priv
), M_NETGRAPH
, M_NOWAIT
);
540 bzero(priv
, sizeof(*priv
));
541 MALLOC(ifp
, struct ifnet
*, sizeof(*ifp
), M_NETGRAPH
, M_NOWAIT
);
543 FREE(priv
, M_NETGRAPH
);
546 bzero(ifp
, sizeof(*ifp
));
548 /* Link them together */
549 ifp
->if_softc
= priv
;
552 /* Get an interface unit number */
553 if ((error
= ng_iface_get_unit(&priv
->unit
)) != 0) {
554 FREE(ifp
, M_NETGRAPH
);
555 FREE(priv
, M_NETGRAPH
);
559 /* Call generic node constructor */
560 if ((error
= ng_make_node_common(&typestruct
, nodep
)) != 0) {
561 ng_iface_free_unit(priv
->unit
);
562 FREE(ifp
, M_NETGRAPH
);
563 FREE(priv
, M_NETGRAPH
);
568 /* Link together node and private info */
569 node
->private = priv
;
572 /* Initialize interface structure */
573 if_initname(ifp
, NG_IFACE_IFACE_NAME
, priv
->unit
);
574 ifp
->if_output
= ng_iface_output
;
575 ifp
->if_start
= ng_iface_start
;
576 ifp
->if_ioctl
= ng_iface_ioctl
;
577 ifp
->if_watchdog
= NULL
;
578 ifp
->if_snd
.ifq_maxlen
= IFQ_MAXLEN
;
579 ifp
->if_mtu
= NG_IFACE_MTU_DEFAULT
;
580 ifp
->if_flags
= (IFF_SIMPLEX
|IFF_POINTOPOINT
|IFF_NOARP
|IFF_MULTICAST
);
581 ifp
->if_type
= IFT_PROPVIRTUAL
; /* XXX */
582 ifp
->if_addrlen
= 0; /* XXX */
583 ifp
->if_hdrlen
= 0; /* XXX */
584 ifp
->if_baudrate
= 64000; /* XXX */
585 TAILQ_INIT(&ifp
->if_addrhead
);
587 /* Give this node the same name as the interface (if possible) */
588 bzero(ifname
, sizeof(ifname
));
589 strlcpy(ifname
, ifp
->if_xname
, sizeof(ifname
));
590 if (ng_name_node(node
, ifname
) != 0)
591 log(LOG_WARNING
, "%s: can't acquire netgraph name\n", ifname
);
593 /* Attach the interface */
594 if_attach(ifp
, NULL
);
595 bpfattach(ifp
, DLT_NULL
, sizeof(u_int
));
602 * Give our ok for a hook to be added
605 ng_iface_newhook(node_p node
, hook_p hook
, const char *name
)
607 const iffam_p iffam
= get_iffam_from_name(name
);
611 return (EPFNOSUPPORT
);
612 hookptr
= get_hook_from_iffam((priv_p
) node
->private, iffam
);
613 if (*hookptr
!= NULL
)
620 * Receive a control message
623 ng_iface_rcvmsg(node_p node
, struct ng_mesg
*msg
,
624 const char *retaddr
, struct ng_mesg
**rptr
)
626 const priv_p priv
= node
->private;
627 struct ifnet
*const ifp
= priv
->ifp
;
628 struct ng_mesg
*resp
= NULL
;
631 switch (msg
->header
.typecookie
) {
632 case NGM_IFACE_COOKIE
:
633 switch (msg
->header
.cmd
) {
634 case NGM_IFACE_GET_IFNAME
:
636 struct ng_iface_ifname
*arg
;
638 NG_MKRESPONSE(resp
, msg
, sizeof(*arg
), M_NOWAIT
);
643 arg
= (struct ng_iface_ifname
*)resp
->data
;
644 strlcpy(arg
->ngif_name
, ifp
->if_xname
,
645 sizeof(arg
->ngif_name
));
649 case NGM_IFACE_POINT2POINT
:
650 case NGM_IFACE_BROADCAST
:
653 /* Deny request if interface is UP */
654 if ((ifp
->if_flags
& IFF_UP
) != 0)
658 switch (msg
->header
.cmd
) {
659 case NGM_IFACE_POINT2POINT
:
660 ifp
->if_flags
|= IFF_POINTOPOINT
;
661 ifp
->if_flags
&= ~IFF_BROADCAST
;
663 case NGM_IFACE_BROADCAST
:
664 ifp
->if_flags
&= ~IFF_POINTOPOINT
;
665 ifp
->if_flags
|= IFF_BROADCAST
;
676 case NGM_CISCO_COOKIE
:
677 switch (msg
->header
.cmd
) {
678 case NGM_CISCO_GET_IPADDR
: /* we understand this too */
682 /* Return the first configured IP address */
683 TAILQ_FOREACH(ifa
, &ifp
->if_addrhead
, ifa_link
) {
684 struct ng_cisco_ipaddr
*ips
;
686 if (ifa
->ifa_addr
->sa_family
!= AF_INET
)
688 NG_MKRESPONSE(resp
, msg
, sizeof(ips
), M_NOWAIT
);
693 ips
= (struct ng_cisco_ipaddr
*)resp
->data
;
694 ips
->ipaddr
= ((struct sockaddr_in
*)
695 ifa
->ifa_addr
)->sin_addr
;
696 ips
->netmask
= ((struct sockaddr_in
*)
697 ifa
->ifa_netmask
)->sin_addr
;
701 /* No IP addresses on this interface? */
703 error
= EADDRNOTAVAIL
;
718 FREE(resp
, M_NETGRAPH
);
719 FREE(msg
, M_NETGRAPH
);
724 * Recive data from a hook. Pass the packet to the correct input routine.
727 ng_iface_rcvdata(hook_p hook
, struct mbuf
*m
, meta_p meta
)
729 const priv_p priv
= hook
->node
->private;
730 const iffam_p iffam
= get_iffam_from_hook(priv
, hook
);
731 struct ifnet
*const ifp
= priv
->ifp
;
735 KASSERT(iffam
!= NULL
, ("%s: iffam", __func__
));
736 KASSERT(m
->m_flags
& M_PKTHDR
, ("%s: not pkthdr", __func__
));
739 if ((ifp
->if_flags
& IFF_UP
) == 0) {
740 NG_FREE_DATA(m
, meta
);
744 /* Update interface stats */
746 ifp
->if_ibytes
+= m
->m_pkthdr
.len
;
748 /* Note receiving interface */
749 m
->m_pkthdr
.rcvif
= ifp
;
751 /* Berkeley packet filter */
752 ng_iface_bpftap(ifp
, m
, iffam
->family
);
754 /* Ignore any meta-data */
758 switch (iffam
->family
) {
781 return (EAFNOSUPPORT
);
783 netisr_dispatch(isr
, m
);
788 * Shutdown and remove the node and its associated interface.
791 ng_iface_rmnode(node_p node
)
793 const priv_p priv
= node
->private;
797 bpfdetach(priv
->ifp
);
798 if_detach(priv
->ifp
);
799 FREE(priv
->ifp
, M_NETGRAPH
);
801 ng_iface_free_unit(priv
->unit
);
802 FREE(priv
, M_NETGRAPH
);
803 node
->private = NULL
;
809 * Hook disconnection. Note that we do *not* shutdown when all
810 * hooks have been disconnected.
813 ng_iface_disconnect(hook_p hook
)
815 const priv_p priv
= hook
->node
->private;
816 const iffam_p iffam
= get_iffam_from_hook(priv
, hook
);
820 *get_hook_from_iffam(priv
, iffam
) = NULL
;