1/*
2 *   $Id: device-bsd44.c,v 1.23 2009/06/19 07:28:06 psavola Exp $
3 *
4 *   Authors:
5 *    Craig Metz		<cmetz@inner.net>
6 *
7 *   This software is Copyright 1996,1997 by the above mentioned author(s),
8 *   All Rights Reserved.
9 *
10 *   The license which is distributed with this software in the file COPYRIGHT
11 *   applies to this software. If your distribution is missing this file, you
12 *   may request it from <pekkas@netcore.fi>.
13 *
14 */
15
16#include <config.h>
17#include <includes.h>
18#include <radvd.h>
19#include <defaults.h>
20#include <pathnames.h>		/* for PATH_PROC_NET_IF_INET6 */
21
22static uint8_t ll_prefix[] = { 0xfe, 0x80 };
23
24/*
25 * this function gets the hardware type and address of an interface,
26 * determines the link layer token length and checks it against
27 * the defined prefixes
28 */
29int
30setup_deviceinfo(int sock, struct Interface *iface)
31{
32	struct ifconf ifconf;
33	struct ifreq ifr;
34	unsigned int nlen;
35	uint8_t *p, *end;
36	struct AdvPrefix *prefix;
37	char zero[sizeof(iface->if_addr)];
38
39	/* just allocate 8192 bytes, should be more than enough.. */
40	if (!(ifconf.ifc_buf = malloc(ifconf.ifc_len = (32 << 8))))
41	{
42		flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
43		goto ret;
44	}
45
46	if (ioctl(sock, SIOCGIFCONF, &ifconf) < 0)
47	{
48		flog(LOG_ERR, "ioctl(SIOCGIFCONF) failed: %s(%d)", strerror(errno), errno);
49		goto ret;
50	}
51
52 	memset(&ifr, 0, sizeof(ifr));
53	strncpy(ifr.ifr_name, iface->Name, IFNAMSIZ-1);
54	ifr.ifr_name[IFNAMSIZ-1] = '\0';
55
56	if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) {
57		flog(LOG_ERR, "ioctl(SIOCGIFMTU) failed for %s: %s", iface->Name, strerror(errno));
58		goto ret;
59	}
60
61	dlog(LOG_DEBUG, 3, "mtu for %s is %d", iface->Name, ifr.ifr_mtu);
62	iface->if_maxmtu = ifr.ifr_mtu;
63
64	p = (uint8_t *)ifconf.ifc_buf;
65	end = p + ifconf.ifc_len;
66	nlen = strlen(iface->Name);
67
68	while(p < end)
69	{
70		p += IFNAMSIZ;
71
72		if ((p + 2) >= end)
73			break;
74
75		if ((p + *p) >= end)
76			break;
77
78		if ((*(p + 1) == AF_LINK) &&
79		    (((struct sockaddr_dl *)p)->sdl_nlen == nlen) &&
80		    (!memcmp(iface->Name, ((struct sockaddr_dl *)p)->sdl_data, nlen)))
81		{
82
83			if (((struct sockaddr_dl *)p)->sdl_alen > sizeof(iface->if_addr))
84			{
85				flog(LOG_ERR, "address length %d too big for",
86					((struct sockaddr_dl *)p)->sdl_alen,
87					iface->Name);
88				goto ret;
89			}
90
91			memcpy(iface->if_hwaddr, LLADDR((struct sockaddr_dl *)p), ((struct sockaddr_dl *)p)->sdl_alen);
92			iface->if_hwaddr_len = ((struct sockaddr_dl *)p)->sdl_alen << 3;
93
94          		switch(((struct sockaddr_dl *)p)->sdl_type) {
95            		case IFT_ETHER:
96            		case IFT_ISO88023:
97            			iface->if_prefix_len = 64;
98              			break;
99            		case IFT_FDDI:
100            			iface->if_prefix_len = 64;
101              			break;
102            		default:
103            			iface->if_prefix_len = -1;
104				iface->if_maxmtu = -1;
105				break;
106          		}
107
108			dlog(LOG_DEBUG, 3, "link layer token length for %s is %d", iface->Name,
109				iface->if_hwaddr_len);
110
111			dlog(LOG_DEBUG, 3, "prefix length for %s is %d", iface->Name,
112				iface->if_prefix_len);
113
114			if (iface->if_prefix_len != -1) {
115				memset(zero, 0, ((struct sockaddr_dl *)p)->sdl_alen);
116				if (!memcmp(iface->if_hwaddr, zero, ((struct sockaddr_dl *)p)->sdl_alen))
117					flog(LOG_WARNING, "WARNING, MAC address on %s is all zero!",
118						iface->Name);
119			}
120
121			prefix = iface->AdvPrefixList;
122			while (prefix)
123			{
124				if ((iface->if_prefix_len != -1) &&
125					(iface->if_prefix_len != prefix->PrefixLen))
126				{
127					flog(LOG_WARNING, "prefix length should be %d for %s",
128						iface->if_prefix_len, iface->Name);
129 				}
130
131 				prefix = prefix->next;
132			}
133
134          		free(ifconf.ifc_buf);
135          		return 0;
136        	}
137
138    		p += *p;
139	}
140
141ret:
142	iface->if_maxmtu = -1;
143	iface->if_hwaddr_len = -1;
144	iface->if_prefix_len = -1;
145	free(ifconf.ifc_buf);
146	return -1;
147}
148
149/*
150 * Saves the first link local address seen on the specified interface to iface->if_addr
151 *
152 */
153int setup_linklocal_addr(int sock, struct Interface *iface)
154{
155	struct ifaddrs *addresses, *ifa;
156
157	if (getifaddrs(&addresses) != 0)
158	{
159		flog(LOG_ERR, "getifaddrs failed: %s(%d)", strerror(errno), errno);
160		goto ret;
161	}
162
163	for (ifa = addresses; ifa != NULL; ifa = ifa->ifa_next)
164	{
165		if (strcmp(ifa->ifa_name, iface->Name) != 0)
166			continue;
167
168		if (ifa->ifa_addr == NULL)
169			continue;
170
171		if (ifa->ifa_addr->sa_family == AF_LINK) {
172			struct sockaddr_dl *dl = (struct sockaddr_dl*)ifa->ifa_addr;
173			if (memcmp(iface->Name, dl->sdl_data, dl->sdl_nlen) == 0)
174				iface->if_index = dl->sdl_index;
175			continue;
176		}
177
178		if (ifa->ifa_addr->sa_family != AF_INET6)
179			continue;
180
181		struct sockaddr_in6 *a6 = (struct sockaddr_in6*)ifa->ifa_addr;
182
183		/* Skip if it is not a linklocal address */
184		if (memcmp(&(a6->sin6_addr), ll_prefix, sizeof(ll_prefix)) != 0)
185			continue;
186
187		memcpy(&iface->if_addr, &(a6->sin6_addr), sizeof(struct in6_addr));
188		freeifaddrs(addresses);
189		return 0;
190	}
191	freeifaddrs(addresses);
192
193ret:
194	flog(LOG_ERR, "no linklocal address configured for %s", iface->Name);
195	return -1;
196}
197
198int setup_allrouters_membership(int sock, struct Interface *iface)
199{
200	return (0);
201}
202
203int check_allrouters_membership(int sock, struct Interface *iface)
204{
205	return (0);
206}
207
208int
209set_interface_linkmtu(const char *iface, uint32_t mtu)
210{
211	dlog(LOG_DEBUG, 4, "setting LinkMTU (%u) for %s is not supported",
212	     mtu, iface);
213	return -1;
214}
215
216int
217set_interface_curhlim(const char *iface, uint8_t hlim)
218{
219	dlog(LOG_DEBUG, 4, "setting CurHopLimit (%u) for %s is not supported",
220	     hlim, iface);
221	return -1;
222}
223
224int
225set_interface_reachtime(const char *iface, uint32_t rtime)
226{
227	dlog(LOG_DEBUG, 4, "setting BaseReachableTime (%u) for %s is not supported",
228	     rtime, iface);
229	return -1;
230}
231
232int
233set_interface_retranstimer(const char *iface, uint32_t rettimer)
234{
235	dlog(LOG_DEBUG, 4, "setting RetransTimer (%u) for %s is not supported",
236	     rettimer, iface);
237	return -1;
238}
239
240