[ Team LiB ] |
18.6 Interface Name and Index FunctionsRFC 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).
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 FunctionFigure 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 list12–13 Our net_rt_iflist function returns the interface list. Process only RTM_IFINFO messages17–30 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 FunctionThe 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 FunctionThe 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 result13–18 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 messages23–36 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 array38–39 The final entry in the array has a null if_name and an index of 0. if_freenameindex FunctionThe 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. |
[ Team LiB ] |