18.6 Interface Name and Index
Functions
RFC 3493 [Gilligan et al. 2003] defines four
functions that deal with interface names and indexes. These four
functions are used in many places where it is necessary to describe
an interface. They were introduced for use with the IPv6 API, as we
will describe in Chapters 21 and 27, but we find interface
indexes in the IPv4 API as well (e.g., in the IP_RECVIF
call, or in AF_LINK sockaddrs seen on the routing socket).
The basic concept is that each interface has a unique name and a
unique positive index (0 is never used as an index).
#include <net/if.h>
|
unsigned int if_nametoindex (const char
*ifname);
|
Returns: positive interface index if OK, 0 on
error
|
char *if_indextoname (unsigned int
ifindex, char
*ifname);
|
Returns: pointer to interface name if
OK, NULL on error
|
struct if_nameindex *if_nameindex
(void);
|
Returns: non-null pointer if OK,
NULL on error
|
void if_freenameindex(struct if_nameindex
*ptr);
|
if_nametoindex returns the index of the
interface whose name is ifname.
if_indextoname returns a pointer to the interface name
given its ifindex. The
ifname argument points to a buffer
of size IFNAMSIZ (defined by including the
<net/if.h> header; also shown in Figure 17.2) that
the caller must allocate to hold the result, and this pointer is
also the return value upon success.
if_nameindex returns a pointer to an
array of if_nameindex structures as follows:
struct if_nameindex {
unsigned int if_index; /* 1, 2, ... */
char *if_name; /* null-terminated name: "le0", ... */
};
The final entry in this array contains a
structure with an if_index of 0 and an if_name
that is a null pointer. The memory for this array, along with the
names pointed to by the array members, is dynamically obtained and
is returned by calling if_freenameindex.
We now provide an implementation of these four
functions using routing sockets.
if_nametoindex Function
Figure
18.18 shows the if_nametoindex function.
Figure 18.18
Return an interface index given its name.
libroute/if_nametoindex.c
1 #include "unpifi.h"
2 #include "unproute.h"
3 unsigned int
4 if_nametoindex(const char *name)
5 {
6 unsigned int idx, namelen;
7 char *buf, *next, *lim;
8 size_t len;
9 struct if_msghdr *ifm;
10 struct sockaddr *sa, *rti_info[RTAX_MAX];
11 struct sockaddr_dl *sdl;
12 if ( (buf = net_rt_iflist(0, 0, &len)) == NULL)
13 return (0);
14 namelen = strlen(name);
15 lim = buf + len;
16 for (next = buf; next < lim; next += ifm->ifm_msglen) {
17 ifm = (struct if_msghdr *) next;
18 if (ifm->ifm_type == RTM_IFINFO) {
19 sa = (struct sockaddr *) (ifm + 1);
20 get_rtaddrs (ifm->ifm_addrs, sa, rti_info);
21 if ( (sa = rti_info[RTAX_IFP]) != NULL) {
22 if (sa->sa_family == AF_LINK) {
23 sdl = (struct sockaddr_dl *) sa;
24 if (sdl->sdl_nlen == namelen
25 && strncmp (&sdl->sdl_data [0], name,
26 sdl->sdl_nlen) == 0) {
27 idx = sdl->sdl_index; /* save before free() */
28 free(buf);
29 return (idx);
30 }
31 }
32 }
33 }
34 }
35 free(buf);
36 return (0); /* no match for name */
37 }
Get interface list
12鈥?3
Our net_rt_iflist function returns the interface list.
Process only RTM_IFINFO
messages
17鈥?0
We process the messages in the buffer (Figure 18.14), looking
only for the RTM_IFINFO messages. When we find one, we
call our get_rtaddrs function to set up the pointers to
the socket address structures, and if an interface name structure
is present (the RTAX_IFP element of the rti_info
array), the interface name is compared to the argument.
if_indextoname Function
The next function, if_indextoname, is
shown in Figure 18.19.
Figure 18.19
Return an interface name given its index.
libroute/if_indextoname.c
1 #include "unpifi.h"
2 #include "unproute.h"
3 char *
4 if_indextoname(unsigned int idx, char *name)
5 {
6 char *buf, *next, *lim;
7 size_t len;
8 struct if_msghdr *ifm;
9 struct sockaddr *sa, *rti_info [RTAX_MAX];
10 struct sockaddr_dl *sdl;
11 if ( (buf = net_rt_iflist(0, idx, &len)) == NULL)
12 return (NULL);
13 lim = buf + len;
14 for (next = buf; next < lim; next += ifm->ifm_msglen) {
15 ifm = (struct if_msghdr *) next;
16 if (ifm->ifm_type == RTM_IFINFO) {
17 sa = (struct sockaddr *) (ifm + 1);
18 get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
19 if ( (sa = rti_info[RTAX_IFP]) != NULL) {
20 if (sa->sa_family == AF_LINK) {
21 sdl = (struct sockaddr_dl *) sa;
22 if (sdl->sdl_index == idx) {
23 int slen = min(IFNAMSIZ - 1, sdl->sdl_nlen);
24 strncpy(name, sdl->sdl_data, slen);
25 name[slen] = 0; /* null terminate */
26 free(buf);
27 return (name);
28 }
29 }
30 }
31 }
32 }
33 free(buf);
34 return (NULL); /* no match for index */
35 }
This function is nearly identical to the
previous function, but instead of looking for an interface name, we
compare the interface index against the caller's argument. Also,
the second argument to our net_rt_iflist function is the
desired index, so the result should contain the information for
only the desired interface. When a match is found, the interface
name is returned and it is also null-terminated.
if_nameindex Function
The next function, if_nameindex,
returns an array of if_nameindex structures containing all
the interface names and indexes. It is shown in Figure 18.20.
Figure 18.20
Return all the interface names and indexes.
libroute/if_nameindex.c
1 #include "unpifi.h"
2 #include "unproute.h"
3 struct if_nameindex *
4 if_nameindex (void)
5 {
6 char *buf, *next, *lim;
7 size_t len;
8 struct if_msghdr *ifm;
9 struct sockaddr *sa, *rti_info [RTAX_MAX];
10 struct sockaddr_dl *sdl;
11 struct if_nameindex *result, *ifptr;
12 char *namptr;
13 if ( (buf = net_rt_iflist (0, 0, &len) ) == NULL)
14 return (NULL);
15 if ( (result = malloc (len) ) == NULL) /* overestimate */
16 return (NULL);
17 ifptr = result;
18 namptr = (char *) result + len; /* names start at end of buffer */
19 lim = buf + len;
20 for (next = buf; next < lim; next += ifm->ifm_msglen) {
21 ifm = (struct if_msghdr *) next;
22 if (ifm->ifm_type == RTM_IFINFO) {
23 sa = (struct sockaddr *) (ifm + 1);
24 get_rtaddrs (ifm->ifm_addrs, sa, rti_info);
25 if ( (sa = rti_info[RTAX_IFP]) != NULL) {
26 if (sa->sa_family == AF_LINK) {
27 sdl = (struct sockaddr_dl *) sa;
28 namptr -= sdl->sdl_nlen + 1;
29 strncpy (namptr, &sdl->sdl_data[0], sdl->sdl_nlen);
30 namptr [sdl->sdl_nlen] = 0; /* null terminate */
31 ifptr->if_name = namptr;
32 ifptr->if_index = sdl->sdl_index;
33 ifptr++;
34 }
35 }
36 }
37 }
38 ifptr->if_name = NULL; /* mark end of array of structs */
39 ifptr->if_index = 0;
40 free (buf);
41 return (result); /* caller must free() this when done */
42 }
Get interface list, allocate room for
result
13鈥?8
We call our net_rt_iflist function to return the interface
list. We also use the returned size as the size of the buffer that
we allocate to contain the array of if_nameindex
structures we return. This is an overestimate, but it is simpler
than making two passes through the interface list: one to count the
number of interfaces and the total sizes of the names and another
to fill in the information. We create the if_nameindex
array at the beginning of this buffer and store the interface names
starting at the end of the buffer.
Process only RTM_IFINFO
messages
23鈥?6
We process all the messages looking for RTM_IFINFO
messages and the datalink socket address structures that follow.
The interface name and index are stored in the array we are
building.
Terminate array
38鈥?9
The final entry in the array has a null if_name and an
index of 0.
if_freenameindex
Function
The final function, shown in Figure 18.21, frees the memory that was
allocated for the array of if_nameindex structures and the
names contained therein.
Figure 18.21
Free the memory allocated by if_nameindex.
libroute/if_nameindex.c
43 void
44 if_freenameindex(struct if_nameindex *ptr)
45 {
46 free(ptr);
47 }
This function is trivial because we stored both
the array of structures and the names in the same buffer. If we had
called malloc for each name, to free the memory, we would
have to go through the entire array, free the memory for
each name, and then free the array.
|