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