Sync some manuals from bin & sbin with NetBSD-8
[minix.git] / sbin / ifconfig / util.c
blob5bba576dca40e68a887b4755ef8bfe93d0883557
1 /* $NetBSD: util.c,v 1.17 2013/10/19 00:35:30 christos Exp $ */
3 /*-
4 * Copyright (c) 2008 David Young. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
28 #include <sys/cdefs.h>
29 #ifndef lint
30 __RCSID("$NetBSD: util.c,v 1.17 2013/10/19 00:35:30 christos Exp $");
31 #endif /* not lint */
33 #include <ctype.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <netdb.h>
37 #include <stddef.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <util.h>
44 #include <sys/param.h>
45 #include <sys/types.h>
46 #include <sys/socket.h>
47 #include <ifaddrs.h>
49 #include <sys/ioctl.h>
50 #include <net/if.h>
51 #include <net/if_dl.h>
52 #include <netinet/in.h> /* XXX */
54 #include "env.h"
55 #include "extern.h"
56 #include "util.h"
57 #include "prog_ops.h"
59 int
60 getsock(int naf)
62 static int oaf = -1, s;
64 if (oaf == naf || (oaf != -1 && naf == AF_UNSPEC))
65 return s;
67 if (oaf != -1)
68 prog_close(s);
70 if (naf == AF_UNSPEC)
71 naf = AF_INET;
73 s = prog_socket(naf, SOCK_DGRAM, 0);
74 if (s == -1)
75 oaf = -1;
76 else
77 oaf = naf;
78 return s;
81 const char *
82 get_string(const char *val, const char *sep, u_int8_t *buf, int *lenp,
83 bool hexok)
85 int len;
86 bool hexstr;
87 u_int8_t *p;
89 len = *lenp;
90 p = buf;
91 hexstr = hexok && val[0] == '0' && tolower((u_char)val[1]) == 'x';
92 if (hexstr)
93 val += 2;
94 for (;;) {
95 if (*val == '\0')
96 break;
97 if (sep != NULL && strchr(sep, *val) != NULL) {
98 val++;
99 break;
101 if (hexstr) {
102 if (!isxdigit((u_char)val[0]) ||
103 !isxdigit((u_char)val[1])) {
104 warnx("bad hexadecimal digits");
105 return NULL;
108 if (p >= buf + len) {
109 if (hexstr)
110 warnx("hexadecimal digits too long");
111 else
112 warnx("strings too long");
113 return NULL;
115 if (hexstr) {
116 #define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
117 *p++ = (tohex((u_char)val[0]) << 4) |
118 tohex((u_char)val[1]);
119 #undef tohex
120 val += 2;
121 } else
122 *p++ = *val++;
124 len = p - buf;
125 if (len < *lenp)
126 memset(p, 0, *lenp - len);
127 *lenp = len;
128 return val;
131 void
132 print_string(const u_int8_t *buf, int len)
134 int i;
135 bool hasspc;
137 i = 0;
138 hasspc = false;
139 if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
140 for (; i < len; i++) {
141 if (!isprint(buf[i]))
142 break;
143 if (isspace(buf[i]))
144 hasspc = true;
147 if (i == len) {
148 if (hasspc || len == 0)
149 printf("\"%.*s\"", len, buf);
150 else
151 printf("%.*s", len, buf);
152 } else {
153 printf("0x");
154 for (i = 0; i < len; i++)
155 printf("%02x", buf[i]);
159 struct paddr_prefix *
160 prefixlen_to_mask(int af, int plen)
162 union {
163 struct sockaddr sa;
164 struct sockaddr_in sin;
165 struct sockaddr_in6 sin6;
166 } u;
167 struct paddr_prefix *pfx;
168 size_t addrlen;
169 uint8_t *addr;
170 int nbit;
172 memset(&u, 0, sizeof(u));
174 switch (af) {
175 case AF_INET:
176 addrlen = sizeof(u.sin.sin_addr);
177 addr = (uint8_t *)&u.sin.sin_addr;
178 u.sa.sa_len = sizeof(u.sin);
179 break;
180 case AF_INET6:
181 addrlen = sizeof(u.sin6.sin6_addr);
182 addr = (uint8_t *)&u.sin6.sin6_addr;
183 u.sa.sa_len = sizeof(u.sin6);
184 break;
185 default:
186 errno = EINVAL;
187 return NULL;
189 u.sa.sa_family = af;
191 if (plen < 0 || (size_t)plen > addrlen * NBBY) {
192 errno = EINVAL;
193 return NULL;
196 if (plen == 0)
197 plen = addrlen * NBBY;
199 memset(addr, 0xff, (plen + NBBY - 1) / NBBY);
201 nbit = plen % NBBY;
202 if (nbit != 0)
203 addr[plen / NBBY] &= ~((uint8_t)0xff >> nbit);
204 pfx = malloc(offsetof(struct paddr_prefix, pfx_addr) + u.sa.sa_len);
205 if (pfx == NULL)
206 return NULL;
207 pfx->pfx_len = plen;
208 memcpy(&pfx->pfx_addr, &u.sa, u.sa.sa_len);
210 return pfx;
214 direct_ioctl(prop_dictionary_t env, unsigned long cmd, void *data)
216 const char *ifname;
217 int s;
219 if ((s = getsock(AF_UNSPEC)) == -1)
220 err(EXIT_FAILURE, "getsock");
222 if ((ifname = getifname(env)) == NULL)
223 err(EXIT_FAILURE, "getifname");
225 estrlcpy(data, ifname, IFNAMSIZ);
227 return prog_ioctl(s, cmd, data);
231 indirect_ioctl(prop_dictionary_t env, unsigned long cmd, void *data)
233 struct ifreq ifr;
235 memset(&ifr, 0, sizeof(ifr));
237 ifr.ifr_data = data;
239 return direct_ioctl(env, cmd, &ifr);
242 void
243 print_link_addresses(prop_dictionary_t env, bool print_active_only)
245 char hbuf[NI_MAXHOST];
246 const char *ifname;
247 int s;
248 struct ifaddrs *ifa, *ifap;
249 const struct sockaddr_dl *sdl;
250 struct if_laddrreq iflr;
252 if ((ifname = getifname(env)) == NULL)
253 err(EXIT_FAILURE, "%s: getifname", __func__);
255 if ((s = getsock(AF_LINK)) == -1)
256 err(EXIT_FAILURE, "%s: getsock", __func__);
258 if (getifaddrs(&ifap) == -1)
259 err(EXIT_FAILURE, "%s: getifaddrs", __func__);
261 memset(&iflr, 0, sizeof(iflr));
263 strlcpy(iflr.iflr_name, ifname, sizeof(iflr.iflr_name));
265 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
266 if (strcmp(ifname, ifa->ifa_name) != 0)
267 continue;
268 if (ifa->ifa_addr->sa_family != AF_LINK)
269 continue;
271 sdl = satocsdl(ifa->ifa_addr);
273 memcpy(&iflr.addr, ifa->ifa_addr, MIN(ifa->ifa_addr->sa_len,
274 sizeof(iflr.addr)));
275 iflr.flags = IFLR_PREFIX;
276 iflr.prefixlen = sdl->sdl_alen * NBBY;
278 if (prog_ioctl(s, SIOCGLIFADDR, &iflr) == -1)
279 err(EXIT_FAILURE, "%s: ioctl", __func__);
281 if (((iflr.flags & IFLR_ACTIVE) != 0) != print_active_only)
282 continue;
284 if (getnameinfo(ifa->ifa_addr, ifa->ifa_addr->sa_len,
285 hbuf, sizeof(hbuf), NULL, 0,
286 Nflag ? 0 : NI_NUMERICHOST) == 0 &&
287 hbuf[0] != '\0') {
288 printf("\t%s %s\n",
289 print_active_only ? "address:" : "link", hbuf);
292 freeifaddrs(ifap);
295 int16_t
296 ifa_get_preference(const char *ifname, const struct sockaddr *sa)
298 struct if_addrprefreq ifap;
299 int s;
301 if ((s = getsock(sa->sa_family)) == -1) {
302 if (errno == EPROTONOSUPPORT)
303 return 0;
304 err(EXIT_FAILURE, "socket");
306 memset(&ifap, 0, sizeof(ifap));
307 estrlcpy(ifap.ifap_name, ifname, sizeof(ifap.ifap_name));
308 memcpy(&ifap.ifap_addr, sa, MIN(sizeof(ifap.ifap_addr), sa->sa_len));
309 if (prog_ioctl(s, SIOCGIFADDRPREF, &ifap) == -1) {
310 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)
311 return 0;
312 warn("SIOCGIFADDRPREF");
314 return ifap.ifap_preference;
317 void
318 ifa_print_preference(const char *ifname, const struct sockaddr *sa)
320 int16_t preference;
322 if (lflag)
323 return;
325 preference = ifa_get_preference(ifname, sa);
326 printf(" preference %" PRId16, preference);
329 bool
330 ifa_any_preferences(const char *ifname, struct ifaddrs *ifap, int family)
332 struct ifaddrs *ifa;
334 /* Print address preference numbers if any address has a non-zero
335 * preference assigned.
337 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
338 if (strcmp(ifname, ifa->ifa_name) != 0)
339 continue;
340 if (ifa->ifa_addr->sa_family != family)
341 continue;
342 if (ifa_get_preference(ifa->ifa_name, ifa->ifa_addr) != 0)
343 return true;
345 return false;