1 1.21 thorpej /* $NetBSD: af_atalk.c,v 1.21 2020/06/07 06:02:58 thorpej Exp $ */ 2 1.1 thorpej 3 1.1 thorpej /* 4 1.1 thorpej * Copyright (c) 1983, 1993 5 1.1 thorpej * The Regents of the University of California. All rights reserved. 6 1.1 thorpej * 7 1.1 thorpej * Redistribution and use in source and binary forms, with or without 8 1.1 thorpej * modification, are permitted provided that the following conditions 9 1.1 thorpej * are met: 10 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 11 1.1 thorpej * notice, this list of conditions and the following disclaimer. 12 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 14 1.1 thorpej * documentation and/or other materials provided with the distribution. 15 1.1 thorpej * 3. Neither the name of the University nor the names of its contributors 16 1.1 thorpej * may be used to endorse or promote products derived from this software 17 1.1 thorpej * without specific prior written permission. 18 1.1 thorpej * 19 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 thorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 thorpej * SUCH DAMAGE. 30 1.1 thorpej */ 31 1.1 thorpej 32 1.1 thorpej #include <sys/cdefs.h> 33 1.1 thorpej #ifndef lint 34 1.21 thorpej __RCSID("$NetBSD: af_atalk.c,v 1.21 2020/06/07 06:02:58 thorpej Exp $"); 35 1.1 thorpej #endif /* not lint */ 36 1.1 thorpej 37 1.20 msaitoh #include <sys/param.h> 38 1.20 msaitoh #include <sys/ioctl.h> 39 1.1 thorpej #include <sys/socket.h> 40 1.1 thorpej 41 1.20 msaitoh #include <net/if.h> 42 1.1 thorpej 43 1.1 thorpej #include <netatalk/at.h> 44 1.1 thorpej 45 1.16 is #include <netdb.h> 46 1.16 is 47 1.1 thorpej #include <err.h> 48 1.1 thorpej #include <errno.h> 49 1.1 thorpej #include <string.h> 50 1.15 dyoung #include <stddef.h> 51 1.1 thorpej #include <stdlib.h> 52 1.1 thorpej #include <stdio.h> 53 1.4 christos #include <util.h> 54 1.1 thorpej 55 1.7 dyoung #include "env.h" 56 1.13 dyoung #include "af_inetany.h" 57 1.7 dyoung #include "parse.h" 58 1.1 thorpej #include "extern.h" 59 1.17 pooka #include "prog_ops.h" 60 1.1 thorpej 61 1.13 dyoung #ifndef satocsat 62 1.13 dyoung #define satocsat(__sa) ((const struct sockaddr_at *)(__sa)) 63 1.13 dyoung #endif 64 1.13 dyoung 65 1.13 dyoung static void at_status(prop_dictionary_t, prop_dictionary_t, bool); 66 1.13 dyoung static void at_commit_address(prop_dictionary_t, prop_dictionary_t); 67 1.13 dyoung 68 1.13 dyoung static void at_constructor(void) __attribute__((constructor)); 69 1.13 dyoung 70 1.13 dyoung static struct afswtch ataf = { 71 1.13 dyoung .af_name = "atalk", .af_af = AF_APPLETALK, .af_status = at_status, 72 1.13 dyoung .af_addr_commit = at_commit_address 73 1.13 dyoung }; 74 1.7 dyoung struct pinteger phase = PINTEGER_INITIALIZER1(&phase, "phase", 75 1.13 dyoung 1, 2, 10, NULL, "phase", &command_root.pb_parser); 76 1.7 dyoung 77 1.13 dyoung struct pstr parse_range = PSTR_INITIALIZER(&range, "range", NULL, "range", 78 1.7 dyoung &command_root.pb_parser); 79 1.7 dyoung 80 1.11 dyoung static const struct kwinst atalkkw[] = { 81 1.11 dyoung {.k_word = "phase", .k_nextparser = &phase.pi_parser} 82 1.11 dyoung , {.k_word = "range", .k_nextparser = &parse_range.ps_parser} 83 1.11 dyoung }; 84 1.11 dyoung 85 1.11 dyoung struct pkw atalk = PKW_INITIALIZER(&atalk, "AppleTalk", NULL, NULL, 86 1.11 dyoung atalkkw, __arraycount(atalkkw), NULL); 87 1.11 dyoung 88 1.13 dyoung static cmdloop_branch_t branch; 89 1.1 thorpej 90 1.13 dyoung static void 91 1.14 dyoung setatrange_impl(prop_dictionary_t env, prop_dictionary_t oenv, 92 1.12 dyoung struct netrange *nr) 93 1.1 thorpej { 94 1.7 dyoung char range[24]; 95 1.1 thorpej u_short first = 123, last = 123; 96 1.1 thorpej 97 1.7 dyoung if (getargstr(env, "range", range, sizeof(range)) == -1) 98 1.13 dyoung return; 99 1.7 dyoung 100 1.7 dyoung if (sscanf(range, "%hu-%hu", &first, &last) != 2 || 101 1.7 dyoung first == 0 || last == 0 || first > last) 102 1.1 thorpej errx(EXIT_FAILURE, "%s: illegal net range: %u-%u", range, 103 1.1 thorpej first, last); 104 1.12 dyoung nr->nr_firstnet = htons(first); 105 1.12 dyoung nr->nr_lastnet = htons(last); 106 1.1 thorpej } 107 1.1 thorpej 108 1.13 dyoung static void 109 1.13 dyoung at_commit_address(prop_dictionary_t env, prop_dictionary_t oenv) 110 1.12 dyoung { 111 1.13 dyoung struct ifreq ifr; 112 1.13 dyoung struct ifaliasreq ifra __attribute__((aligned(4))); 113 1.13 dyoung struct afparam atparam = { 114 1.13 dyoung .req = BUFPARAM(ifra) 115 1.13 dyoung , .dgreq = BUFPARAM(ifr) 116 1.13 dyoung , .name = { 117 1.13 dyoung {.buf = ifr.ifr_name, 118 1.13 dyoung .buflen = sizeof(ifr.ifr_name)} 119 1.13 dyoung , {.buf = ifra.ifra_name, 120 1.13 dyoung .buflen = sizeof(ifra.ifra_name)} 121 1.13 dyoung } 122 1.13 dyoung , .dgaddr = BUFPARAM(ifr.ifr_addr) 123 1.13 dyoung , .addr = BUFPARAM(ifra.ifra_addr) 124 1.13 dyoung , .dst = BUFPARAM(ifra.ifra_dstaddr) 125 1.13 dyoung , .brd = BUFPARAM(ifra.ifra_broadaddr) 126 1.13 dyoung , .mask = BUFPARAM(ifra.ifra_mask) 127 1.13 dyoung , .aifaddr = IFADDR_PARAM(SIOCAIFADDR) 128 1.13 dyoung , .difaddr = IFADDR_PARAM(SIOCDIFADDR) 129 1.13 dyoung , .gifaddr = IFADDR_PARAM(SIOCGIFADDR) 130 1.13 dyoung , .defmask = {.buf = NULL, .buflen = 0} 131 1.13 dyoung }; 132 1.13 dyoung struct netrange nr = {.nr_phase = 2}; /* AppleTalk net range */ 133 1.15 dyoung prop_data_t d, d0; 134 1.15 dyoung prop_dictionary_t ienv; 135 1.15 dyoung struct paddr_prefix *addr; 136 1.15 dyoung struct sockaddr_at *sat; 137 1.13 dyoung 138 1.15 dyoung if ((d0 = (prop_data_t)prop_dictionary_get(env, "address")) == NULL) 139 1.13 dyoung return; 140 1.13 dyoung 141 1.21 thorpej addr = malloc(prop_data_size(d0)); 142 1.21 thorpej if (addr == NULL) 143 1.21 thorpej return; 144 1.21 thorpej if (!prop_data_copy_value(d0, addr, prop_data_size(d0))) { 145 1.21 thorpej free(addr); 146 1.21 thorpej return; 147 1.21 thorpej } 148 1.13 dyoung 149 1.15 dyoung sat = (struct sockaddr_at *)&addr->pfx_addr; 150 1.12 dyoung 151 1.13 dyoung (void)prop_dictionary_get_uint8(env, "phase", &nr.nr_phase); 152 1.13 dyoung /* Default range of one */ 153 1.15 dyoung nr.nr_firstnet = nr.nr_lastnet = sat->sat_addr.s_net; 154 1.13 dyoung setatrange_impl(env, oenv, &nr); 155 1.12 dyoung 156 1.15 dyoung if (ntohs(nr.nr_firstnet) > ntohs(sat->sat_addr.s_net) || 157 1.15 dyoung ntohs(nr.nr_lastnet) < ntohs(sat->sat_addr.s_net)) 158 1.13 dyoung errx(EXIT_FAILURE, "AppleTalk address is not in range"); 159 1.18 christos memcpy(&sat->sat_zero, &nr, sizeof(nr)); 160 1.15 dyoung 161 1.15 dyoung /* Copy the new address to a temporary input environment */ 162 1.15 dyoung 163 1.21 thorpej d = prop_data_create_copy(addr, paddr_prefix_size(addr)); 164 1.21 thorpej free(addr); 165 1.21 thorpej 166 1.15 dyoung ienv = prop_dictionary_copy_mutable(env); 167 1.15 dyoung 168 1.15 dyoung if (d == NULL) 169 1.21 thorpej err(EXIT_FAILURE, "%s: prop_data_create_copy", __func__); 170 1.15 dyoung if (ienv == NULL) 171 1.15 dyoung err(EXIT_FAILURE, "%s: prop_dictionary_copy_mutable", __func__); 172 1.15 dyoung 173 1.15 dyoung if (!prop_dictionary_set(ienv, "address", (prop_object_t)d)) 174 1.15 dyoung err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__); 175 1.15 dyoung 176 1.15 dyoung /* copy to output environment for good measure */ 177 1.15 dyoung if (!prop_dictionary_set(oenv, "address", (prop_object_t)d)) 178 1.15 dyoung err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__); 179 1.15 dyoung 180 1.15 dyoung prop_object_release((prop_object_t)d); 181 1.1 thorpej 182 1.13 dyoung memset(&ifr, 0, sizeof(ifr)); 183 1.13 dyoung memset(&ifra, 0, sizeof(ifra)); 184 1.15 dyoung commit_address(ienv, oenv, &atparam); 185 1.15 dyoung 186 1.15 dyoung /* release temporary input environment */ 187 1.15 dyoung prop_object_release((prop_object_t)ienv); 188 1.12 dyoung } 189 1.12 dyoung 190 1.13 dyoung static void 191 1.16 is sat_print1(const char *prefix, const struct sockaddr *sa) 192 1.1 thorpej { 193 1.16 is char buf[40]; 194 1.1 thorpej 195 1.19 christos (void)getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, 0); 196 1.20 msaitoh 197 1.16 is printf("%s%s", prefix, buf); 198 1.1 thorpej } 199 1.1 thorpej 200 1.13 dyoung static void 201 1.9 dyoung at_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force) 202 1.1 thorpej { 203 1.12 dyoung struct sockaddr_at *sat; 204 1.7 dyoung struct ifreq ifr; 205 1.13 dyoung int s; 206 1.7 dyoung const char *ifname; 207 1.7 dyoung unsigned short flags; 208 1.1 thorpej 209 1.7 dyoung if ((s = getsock(AF_APPLETALK)) == -1) { 210 1.2 tron if (errno == EAFNOSUPPORT) 211 1.1 thorpej return; 212 1.8 dyoung err(EXIT_FAILURE, "getsock"); 213 1.1 thorpej } 214 1.7 dyoung if ((ifname = getifinfo(env, oenv, &flags)) == NULL) 215 1.7 dyoung err(EXIT_FAILURE, "%s: getifinfo", __func__); 216 1.7 dyoung 217 1.7 dyoung memset(&ifr, 0, sizeof(ifr)); 218 1.7 dyoung estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 219 1.13 dyoung ifr.ifr_addr.sa_family = AF_APPLETALK; 220 1.17 pooka if (prog_ioctl(s, SIOCGIFADDR, &ifr) != -1) 221 1.13 dyoung ; 222 1.13 dyoung else if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) { 223 1.13 dyoung if (!force) 224 1.13 dyoung return; 225 1.13 dyoung memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 226 1.13 dyoung } else 227 1.13 dyoung warn("SIOCGIFADDR"); 228 1.1 thorpej sat = (struct sockaddr_at *)&ifr.ifr_addr; 229 1.1 thorpej 230 1.16 is sat_print1("\tatalk ", &ifr.ifr_addr); 231 1.7 dyoung 232 1.1 thorpej if (flags & IFF_POINTOPOINT) { 233 1.12 dyoung estrlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); 234 1.17 pooka if (prog_ioctl(s, SIOCGIFDSTADDR, &ifr) == -1) { 235 1.1 thorpej if (errno == EADDRNOTAVAIL) 236 1.7 dyoung memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 237 1.1 thorpej else 238 1.7 dyoung warn("SIOCGIFDSTADDR"); 239 1.1 thorpej } 240 1.16 is sat_print1(" --> ", &ifr.ifr_dstaddr); 241 1.1 thorpej } 242 1.1 thorpej if (flags & IFF_BROADCAST) { 243 1.1 thorpej /* note RTAX_BRD overlap with IFF_POINTOPOINT */ 244 1.16 is /* note Appletalk broadcast is fixed. */ 245 1.16 is printf(" broadcast %u.%u", ntohs(sat->sat_addr.s_net), 246 1.16 is ATADDR_BCAST); 247 1.1 thorpej } 248 1.1 thorpej printf("\n"); 249 1.1 thorpej } 250 1.1 thorpej 251 1.13 dyoung static void 252 1.13 dyoung at_constructor(void) 253 1.13 dyoung { 254 1.13 dyoung register_family(&ataf); 255 1.13 dyoung cmdloop_branch_init(&branch, &atalk.pk_parser); 256 1.13 dyoung register_cmdloop_branch(&branch); 257 1.13 dyoung } 258