#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <sys/filio.h>
#include <errno.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/route.h>
#include <string.h>
#include "LinkAddresses.h"
struct LinkAddresses_s {
struct sockaddr_dl * * list;
int count;
};
void
sockaddr_dl_print(struct sockaddr_dl * dl_p)
{
int i;
printf("link: len %d index %d family %d type 0x%x nlen %d alen %d"
" slen %d addr ", dl_p->sdl_len,
dl_p->sdl_index, dl_p->sdl_family, dl_p->sdl_type,
dl_p->sdl_nlen, dl_p->sdl_alen, dl_p->sdl_slen);
for (i = 0; i < dl_p->sdl_alen; i++)
printf("%s%x", i ? ":" : "",
((unsigned char *)dl_p->sdl_data + dl_p->sdl_nlen)[i]);
printf("\n");
}
#ifdef TEST_LINKADDRESSES
static void
LinkAddresses_print(LinkAddressesRef link_addrs)
{
int i;
for (i = 0; i < link_addrs->count; i++) {
struct sockaddr_dl * sdl = link_addrs->list[i];
printf("%.*s ", sdl->sdl_nlen, sdl->sdl_data);
sockaddr_dl_print(sdl);
}
}
#endif TEST_LINKADDRESSES
struct sockaddr_dl *
LinkAddresses_lookup(LinkAddressesRef list, char * ifname)
{
int i;
int len = strlen(ifname);
for (i = 0; i < list->count; i++) {
struct sockaddr_dl * sdl = list->list[i];
if (strncmp(sdl->sdl_data, ifname, sdl->sdl_nlen) == 0
&& len == sdl->sdl_nlen) {
return (sdl);
}
}
return (NULL);
}
int
LinkAddresses_count(LinkAddressesRef list)
{
return (list->count);
}
struct sockaddr_dl *
LinkAddresses_element(LinkAddressesRef list, int i)
{
if (i >= 0 && i < list->count) {
return (list->list[i]);
}
return (NULL);
}
void
LinkAddresses_free(LinkAddressesRef * list_p)
{
int i;
LinkAddressesRef list = *list_p;
if (list) {
for (i = 0; i < list->count; i++) {
free(list->list[i]);
list->list[i] = NULL;
}
free(list->list);
list->list = NULL;
list->count = 0;
free(list);
}
*list_p = NULL;
return;
}
LinkAddressesRef
LinkAddresses_create()
{
char * buf = NULL;
size_t buf_len = 0;
int mib[6];
int offset = 0;
struct sockaddr_dl * * list = NULL;
int list_size = 10;
int list_count = 0;
LinkAddressesRef ret_list = NULL;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_LINK;
mib[4] = NET_RT_IFLIST;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &buf_len, NULL, 0) < 0) {
fprintf(stderr, "sysctl() size failed: %s", strerror(errno));
goto failed;
}
buf = malloc(buf_len);
if (sysctl(mib, 6, buf, &buf_len, NULL, 0) < 0) {
fprintf(stderr, "sysctl() failed: %s", strerror(errno));
goto failed;
}
list = (struct sockaddr_dl * *)malloc(sizeof(*list) * list_size);
if (list == NULL) {
goto failed;
}
offset = 0;
while (offset < buf_len) {
struct if_msghdr * ifm;
struct sockaddr_dl * sdl;
struct sockaddr_dl * new_p;
ifm = (struct if_msghdr *)&buf[offset];
switch (ifm->ifm_type) {
case RTM_IFINFO:
sdl = (struct sockaddr_dl *)(ifm + 1);
if (list_count == list_size) {
list_size *= 2;
list = realloc(list, sizeof(*list) * list_size);
if (list == NULL) {
goto failed;
}
}
new_p = (void *)malloc(sdl->sdl_len);
if (new_p == NULL) {
break;
}
bcopy(sdl, new_p, sdl->sdl_len);
list[list_count++] = new_p;
break;
default:
break;
}
offset += ifm->ifm_msglen;
}
if (list_count == 0) {
free(list);
list = NULL;
}
else if (list_count < list_size) {
list = realloc(list, sizeof(*list) * list_count);
}
if (list) {
ret_list = (void *)malloc(sizeof(*ret_list));
if (ret_list) {
ret_list->list = list;
ret_list->count = list_count;
}
else {
free(list);
list = NULL;
}
}
failed:
if (buf) {
free(buf);
}
return (ret_list);
}
#ifdef TEST_LINKADDRESSES
int
main()
{
LinkAddressesRef link_addrs;
link_addrs = LinkAddresses_create();
if (link_addrs) {
LinkAddresses_print(link_addrs);
LinkAddresses_free(&link_addrs);
}
exit(0);
}
#endif TEST_LINKADDRESSES