get_ifi_info.c 4.65 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1 2 3 4 5 6
/*
 * EMULAB-COPYRIGHT
 * Copyright (c) 2000-2002 University of Utah and the Flux Group.
 * All rights reserved.
 */

Kristin Wright's avatar
Kristin Wright committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
/* 
 * This is a very slightly modified version of
 * example code from Unix Netwok Programming, edition 2.
 */

/*
 * need: 
 * - flags (IFF_UP, IFF_LOOPBACK)
 * - index (really need string name which we get from if_indextoname()
 * - broadcast addr (brdaddr)
 * set:
 * - nbors
 * 
 */

#include "discvr.h"

#define min(a,b) ((a) < (b) ? (a) : (b))

struct ifi_info *
get_ifi_info(int family, int doaliases)
{
	int 			flags;
	char			*buf, *next, *lim;
	size_t			len;
	struct if_msghdr	*ifm;
	struct ifa_msghdr	*ifam;
	struct sockaddr		*sa, *rti_info[RTAX_MAX];
	struct sockaddr_dl	*sdl;
	struct ifi_info		*ifi, *ifisave, *ifihead, **ifipnext;

38 39 40 41
	// Get the temporary list of interfaces in the "buf" buffer and the 
	// length of the list in "len"... 
	// there may be some interfaces which are not up... or some may not 
	// be having network addresses already... -ik
Kristin Wright's avatar
Kristin Wright committed
42 43 44 45 46 47 48 49
	buf = net_rt_iflist(family, 0, &len);

	ifihead = NULL;
	ifipnext = &ifihead;

	lim = buf + len;
	for (next = buf; next < lim; next += ifm->ifm_msglen) {
		ifm = (struct if_msghdr *) next;
50 51
		// "ifm_type" is the interface information message type
		// RTM_IFINFO: interface going up or down
Kristin Wright's avatar
Kristin Wright committed
52 53 54 55
		if (ifm->ifm_type == RTM_IFINFO) {
			if ( ((flags = ifm->ifm_flags) & IFF_UP) == 0)
				continue;	/* ignore if interface not up */

56 57
			// Interface is up.. get the list of addresses on the back of
			// message header and proceed
Kristin Wright's avatar
Kristin Wright committed
58
			sa = (struct sockaddr *) (ifm + 1);
59 60 61

			// Get the sockadders in the rti_info array after reading from
			// "sa" list
Kristin Wright's avatar
Kristin Wright committed
62
			get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
63 64 65

			// The sockaddr at "RTAX_IFP" index has the name and link level
			// address for the interface.
Kristin Wright's avatar
Kristin Wright committed
66
			if ( (sa = rti_info[RTAX_IFP]) != NULL) {
67 68 69

				// Make a node of the link list "ifi" to store information 
				// about an interface..
Kristin Wright's avatar
Kristin Wright committed
70 71 72 73 74
				ifi = calloc(1, sizeof(struct ifi_info));
				*ifipnext = ifi;			/* prev points to this new one */
				ifipnext = &ifi->ifi_next;	/* ptr to next one goes here */

				ifi->ifi_flags = flags;
75 76

				// If its not a link layer interface then ignore
Kristin Wright's avatar
Kristin Wright committed
77
				if (sa->sa_family == AF_LINK) {
78 79 80

					// copy the sock adder to link level sockaddr
					// coz we now know its a link level address
Kristin Wright's avatar
Kristin Wright committed
81
					sdl = (struct sockaddr_dl *) sa;
82 83 84

					// Now, get the name and address of the link level
					// interface...
Kristin Wright's avatar
Kristin Wright committed
85 86 87 88 89 90 91 92 93 94 95 96
					if (sdl->sdl_nlen > 0)
						snprintf(ifi->ifi_name, IFNAMSIZ, "%*s",
								 sdl->sdl_nlen, &sdl->sdl_data[0]);
					else
						snprintf(ifi->ifi_name, IFNAMSIZ, "index %d",
								 sdl->sdl_index);

					if ( (ifi->ifi_hlen = sdl->sdl_alen) > 0)
						memcpy(ifi->ifi_haddr, LLADDR(sdl),
							   min(IFHADDRSIZ, sdl->sdl_alen));
				}
			}
97 98

		// Check if address is being added to the interface...
Kristin Wright's avatar
Kristin Wright committed
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
		} else if (ifm->ifm_type == RTM_NEWADDR) {
			if (ifi->ifi_addr) {	/* already have an IP addr for i/f */
				if (doaliases == 0)
					continue;

					/* 4we have a new IP addr for existing interface */
				ifisave = ifi;
				ifi = (struct ifi_info *)calloc(1, sizeof(struct ifi_info));
				*ifipnext = ifi;			/* prev points to this new one */
				ifipnext = &ifi->ifi_next;	/* ptr to next one goes here */
				ifi->ifi_flags = ifisave->ifi_flags;
				ifi->ifi_hlen = ifisave->ifi_hlen;
				memcpy(ifi->ifi_name, ifisave->ifi_name, IFNAMSIZ);
				memcpy(ifi->ifi_haddr, ifisave->ifi_haddr, IFHADDRSIZ);
			}

			ifam = (struct ifa_msghdr *) next;
			sa = (struct sockaddr *) (ifam + 1);
			get_rtaddrs(ifam->ifam_addrs, sa, rti_info);

			if ( (sa = rti_info[RTAX_IFA]) != NULL) {
				ifi->ifi_addr = (struct sockaddr *)calloc(1, sa->sa_len);
				memcpy(ifi->ifi_addr, sa, sa->sa_len);
			}

			if ((flags & IFF_BROADCAST) &&
				(sa = rti_info[RTAX_BRD]) != NULL) {
				ifi->ifi_brdaddr = (struct sockaddr *)calloc(1, sa->sa_len);
				memcpy(ifi->ifi_brdaddr, sa, sa->sa_len);
			}

			if ((flags & IFF_POINTOPOINT) &&
				(sa = rti_info[RTAX_BRD]) != NULL) {
				ifi->ifi_dstaddr = (struct sockaddr *)calloc(1, sa->sa_len);
				memcpy(ifi->ifi_dstaddr, sa, sa->sa_len);
			}

		} else {
			fprintf(stderr, "unexpected message type %d", ifm->ifm_type);
			exit(1);
		}
	}
	/* "ifihead" points to the first structure in the linked list */
	return(ifihead);	/* ptr to first structure in linked list */
}

void
free_ifi_info(struct ifi_info *ifihead)
{
	struct ifi_info	*ifi, *ifinext;

	for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
		if (ifi->ifi_addr != NULL)
			free(ifi->ifi_addr);
		if (ifi->ifi_brdaddr != NULL)
			free(ifi->ifi_brdaddr);
		if (ifi->ifi_dstaddr != NULL)
			free(ifi->ifi_dstaddr);
		ifinext = ifi->ifi_next;		/* can't fetch ifi_next after free() */
		free(ifi);					/* the ifi_info{} itself */
	}
}