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