af_link.c revision 1.3 1 /* $NetBSD: af_link.c,v 1.3 2008/07/02 07:44:14 dyoung Exp $ */
2
3 /*-
4 * Copyright (c) 2008 David Young. All rights reserved.
5 *
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.
14 *
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.
26 */
27
28 #include <sys/cdefs.h>
29 #ifndef lint
30 __RCSID("$NetBSD: af_link.c,v 1.3 2008/07/02 07:44:14 dyoung Exp $");
31 #endif /* not lint */
32
33 #include <sys/param.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36
37 #include <net/if.h>
38 #include <net/if_dl.h>
39
40 #include <assert.h>
41 #include <err.h>
42 #include <errno.h>
43 #include <ifaddrs.h>
44 #include <netdb.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <util.h>
49
50 #include "env.h"
51 #include "extern.h"
52 #include "af_inetany.h"
53
54 static void link_status(prop_dictionary_t, prop_dictionary_t, bool);
55 static void link_commit_address(prop_dictionary_t, prop_dictionary_t);
56
57 static const struct kwinst linkkw[] = {
58 {.k_word = "active", .k_key = "active", .k_type = KW_T_BOOL,
59 .k_bool = true, .k_nextparser = &command_root.pb_parser}
60 };
61
62 struct pkw link = PKW_INITIALIZER(&link, "link", NULL, NULL,
63 linkkw, __arraycount(linkkw), NULL);
64
65 static struct afswtch af = {
66 .af_name = "link", .af_af = AF_LINK, .af_status = link_status,
67 .af_addr_commit = link_commit_address
68 };
69
70 static cmdloop_branch_t branch;
71
72 static void link_constructor(void) __attribute__((constructor));
73
74 static void
75 link_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force)
76 {
77 const char *delim, *ifname;
78 int i, s;
79 struct ifaddrs *ifa, *ifap;
80 const struct sockaddr_dl *sdl;
81 struct if_laddrreq iflr;
82 const uint8_t *octets;
83
84 if ((ifname = getifname(env)) == NULL)
85 err(EXIT_FAILURE, "%s: getifname", __func__);
86
87 if ((s = getsock(AF_LINK)) == -1)
88 err(EXIT_FAILURE, "%s: getsock", __func__);
89
90 if (getifaddrs(&ifap) == -1)
91 err(EXIT_FAILURE, "%s: getifaddrs", __func__);
92
93 memset(&iflr, 0, sizeof(iflr));
94
95 strlcpy(iflr.iflr_name, ifname, sizeof(iflr.iflr_name));
96
97 for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
98 if (strcmp(ifname, ifa->ifa_name) != 0)
99 continue;
100 if (ifa->ifa_addr->sa_family != AF_LINK)
101 continue;
102 if (ifa->ifa_data != NULL)
103 continue;
104
105 sdl = satocsdl(ifa->ifa_addr);
106
107 memcpy(&iflr.addr, ifa->ifa_addr, MIN(ifa->ifa_addr->sa_len,
108 sizeof(iflr.addr)));
109 iflr.flags = IFLR_PREFIX;
110 iflr.prefixlen = sdl->sdl_alen * NBBY;
111
112 if (ioctl(s, SIOCGLIFADDR, &iflr) == -1)
113 err(EXIT_FAILURE, "%s: ioctl", __func__);
114
115 if ((iflr.flags & IFLR_ACTIVE) != 0)
116 continue;
117
118 octets = (const uint8_t *)&sdl->sdl_data[sdl->sdl_nlen];
119
120 delim = "\tlink ";
121 for (i = 0; i < sdl->sdl_alen; i++) {
122 printf("%s%02" PRIx8, delim, octets[i]);
123 delim = ":";
124 }
125 printf("\n");
126 }
127 }
128
129 static int
130 link_pre_aifaddr(prop_dictionary_t env, const struct afparam *param)
131 {
132 bool active;
133 struct if_laddrreq *iflr = param->req.buf;
134
135 if (prop_dictionary_get_bool(env, "active", &active) && active)
136 iflr->flags |= IFLR_ACTIVE;
137
138 return 0;
139 }
140
141 static void
142 link_commit_address(prop_dictionary_t env, prop_dictionary_t oenv)
143 {
144 struct if_laddrreq dgreq = {
145 .addr = {
146 .ss_family = AF_LINK,
147 .ss_len = sizeof(dgreq.addr),
148 },
149 };
150 struct if_laddrreq req = {
151 .addr = {
152 .ss_family = AF_LINK,
153 .ss_len = sizeof(req.addr),
154 }
155 };
156 struct afparam linkparam = {
157 .req = BUFPARAM(req)
158 , .dgreq = BUFPARAM(dgreq)
159 , .name = {
160 {.buf = dgreq.iflr_name,
161 .buflen = sizeof(dgreq.iflr_name)},
162 {.buf = req.iflr_name,
163 .buflen = sizeof(req.iflr_name)}
164 }
165 , .dgaddr = BUFPARAM(dgreq.addr)
166 , .addr = BUFPARAM(req.addr)
167 , .aifaddr = IFADDR_PARAM(SIOCALIFADDR)
168 , .difaddr = IFADDR_PARAM(SIOCDLIFADDR)
169 , .gifaddr = IFADDR_PARAM(0)
170 , .pre_aifaddr = link_pre_aifaddr
171 };
172 commit_address(env, oenv, &linkparam);
173 }
174
175 static void
176 link_constructor(void)
177 {
178 register_family(&af);
179 cmdloop_branch_init(&branch, &link.pk_parser);
180 register_cmdloop_branch(&branch);
181 }
182