1 1.44 riastrad /* $NetBSD: at_control.c,v 1.44 2023/03/30 15:58:10 riastradh Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (c) 1990,1994 Regents of The University of Michigan. 5 1.1 christos * All Rights Reserved. 6 1.1 christos * 7 1.1 christos * Permission to use, copy, modify, and distribute this software and 8 1.1 christos * its documentation for any purpose and without fee is hereby granted, 9 1.1 christos * provided that the above copyright notice appears in all copies and 10 1.1 christos * that both that copyright notice and this permission notice appear 11 1.1 christos * in supporting documentation, and that the name of The University 12 1.1 christos * of Michigan not be used in advertising or publicity pertaining to 13 1.1 christos * distribution of the software without specific, written prior 14 1.1 christos * permission. This software is supplied as is without expressed or 15 1.1 christos * implied warranties of any kind. 16 1.1 christos * 17 1.1 christos * This product includes software developed by the University of 18 1.1 christos * California, Berkeley and its contributors. 19 1.1 christos * 20 1.1 christos * Research Systems Unix Group 21 1.1 christos * The University of Michigan 22 1.1 christos * c/o Wesley Craig 23 1.1 christos * 535 W. William Street 24 1.1 christos * Ann Arbor, Michigan 25 1.1 christos * +1-313-764-2278 26 1.1 christos * netatalk (at) umich.edu 27 1.1 christos */ 28 1.6 lukem 29 1.6 lukem #include <sys/cdefs.h> 30 1.44 riastrad __KERNEL_RCSID(0, "$NetBSD: at_control.c,v 1.44 2023/03/30 15:58:10 riastradh Exp $"); 31 1.40 rjs 32 1.40 rjs #include "opt_atalk.h" 33 1.1 christos 34 1.1 christos #include <sys/param.h> 35 1.1 christos #include <sys/systm.h> 36 1.1 christos #include <sys/proc.h> 37 1.1 christos #include <sys/errno.h> 38 1.1 christos #include <sys/ioctl.h> 39 1.1 christos #include <sys/mbuf.h> 40 1.1 christos #include <sys/kernel.h> 41 1.1 christos #include <sys/socket.h> 42 1.1 christos #include <sys/socketvar.h> 43 1.13 elad #include <sys/kauth.h> 44 1.1 christos #include <net/if.h> 45 1.1 christos #include <net/route.h> 46 1.1 christos #include <net/if_ether.h> 47 1.1 christos #include <netinet/in.h> 48 1.1 christos #undef s_net 49 1.1 christos 50 1.1 christos #include <netatalk/at.h> 51 1.1 christos #include <netatalk/at_var.h> 52 1.1 christos #include <netatalk/aarp.h> 53 1.1 christos #include <netatalk/phase2.h> 54 1.1 christos #include <netatalk/at_extern.h> 55 1.1 christos 56 1.20 dyoung static int aa_dorangeroute(struct ifaddr * ifa, 57 1.20 dyoung u_int first, u_int last, int cmd); 58 1.20 dyoung static int aa_addsingleroute(struct ifaddr * ifa, 59 1.20 dyoung struct at_addr * addr, struct at_addr * mask); 60 1.20 dyoung static int aa_delsingleroute(struct ifaddr * ifa, 61 1.20 dyoung struct at_addr * addr, struct at_addr * mask); 62 1.20 dyoung static int aa_dosingleroute(struct ifaddr * ifa, struct at_addr * addr, 63 1.20 dyoung struct at_addr * mask, int cmd, int flags); 64 1.20 dyoung static int at_scrub(struct ifnet * ifp, struct at_ifaddr * aa); 65 1.20 dyoung static int at_ifinit(struct ifnet *, struct at_ifaddr *, 66 1.20 dyoung const struct sockaddr_at *); 67 1.1 christos #if 0 68 1.20 dyoung static void aa_clean(void); 69 1.1 christos #endif 70 1.1 christos 71 1.1 christos #define sateqaddr(a,b) ((a)->sat_len == (b)->sat_len && \ 72 1.1 christos (a)->sat_family == (b)->sat_family && \ 73 1.1 christos (a)->sat_addr.s_net == (b)->sat_addr.s_net && \ 74 1.1 christos (a)->sat_addr.s_node == (b)->sat_addr.s_node ) 75 1.1 christos 76 1.1 christos int 77 1.35 rtr at_control(u_long cmd, void *data, struct ifnet *ifp) 78 1.1 christos { 79 1.1 christos struct ifreq *ifr = (struct ifreq *) data; 80 1.20 dyoung const struct sockaddr_at *csat; 81 1.1 christos struct netrange *nr; 82 1.20 dyoung const struct netrange *cnr; 83 1.1 christos struct at_aliasreq *ifra = (struct at_aliasreq *) data; 84 1.1 christos struct at_ifaddr *aa0; 85 1.1 christos struct at_ifaddr *aa = 0; 86 1.1 christos 87 1.1 christos /* 88 1.1 christos * If we have an ifp, then find the matching at_ifaddr if it exists 89 1.1 christos */ 90 1.1 christos if (ifp) 91 1.43 riastrad TAILQ_FOREACH(aa, &at_ifaddr, aa_list) 92 1.1 christos if (aa->aa_ifp == ifp) 93 1.1 christos break; 94 1.1 christos 95 1.1 christos /* 96 1.1 christos * In this first switch table we are basically getting ready for 97 1.1 christos * the second one, by getting the atalk-specific things set up 98 1.1 christos * so that they start to look more similar to other protocols etc. 99 1.1 christos */ 100 1.1 christos 101 1.1 christos switch (cmd) { 102 1.1 christos case SIOCAIFADDR: 103 1.1 christos case SIOCDIFADDR: 104 1.1 christos /* 105 1.1 christos * If we have an appletalk sockaddr, scan forward of where 106 1.1 christos * we are now on the at_ifaddr list to find one with a matching 107 1.1 christos * address on this interface. 108 1.1 christos * This may leave aa pointing to the first address on the 109 1.1 christos * NEXT interface! 110 1.1 christos */ 111 1.1 christos if (ifra->ifra_addr.sat_family == AF_APPLETALK) { 112 1.43 riastrad for (; aa; aa = TAILQ_NEXT(aa, aa_list)) 113 1.1 christos if (aa->aa_ifp == ifp && 114 1.1 christos sateqaddr(&aa->aa_addr, &ifra->ifra_addr)) 115 1.1 christos break; 116 1.1 christos } 117 1.1 christos /* 118 1.41 andvar * If we a retrying to delete an address but didn't find such, 119 1.1 christos * then return with an error 120 1.1 christos */ 121 1.1 christos if (cmd == SIOCDIFADDR && aa == 0) 122 1.1 christos return (EADDRNOTAVAIL); 123 1.1 christos /* FALLTHROUGH */ 124 1.1 christos 125 1.1 christos case SIOCSIFADDR: 126 1.1 christos /* 127 1.1 christos * If we are not superuser, then we don't get to do these 128 1.1 christos * ops. 129 1.1 christos */ 130 1.42 christos if (kauth_authorize_network(kauth_cred_get(), 131 1.16 elad KAUTH_NETWORK_INTERFACE, 132 1.16 elad KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, 133 1.16 elad NULL) != 0) 134 1.1 christos return (EPERM); 135 1.1 christos 136 1.20 dyoung csat = satocsat(ifreq_getaddr(cmd, ifr)); 137 1.20 dyoung cnr = (const struct netrange *)csat->sat_zero; 138 1.20 dyoung if (cnr->nr_phase == 1) { 139 1.1 christos /* 140 1.1 christos * Look for a phase 1 address on this interface. 141 1.1 christos * This may leave aa pointing to the first address on 142 1.1 christos * the NEXT interface! 143 1.1 christos */ 144 1.43 riastrad for (; aa; aa = TAILQ_NEXT(aa, aa_list)) { 145 1.1 christos if (aa->aa_ifp == ifp && 146 1.1 christos (aa->aa_flags & AFA_PHASE2) == 0) 147 1.1 christos break; 148 1.1 christos } 149 1.1 christos } else { /* default to phase 2 */ 150 1.1 christos /* 151 1.1 christos * Look for a phase 2 address on this interface. 152 1.1 christos * This may leave aa pointing to the first address on 153 1.1 christos * the NEXT interface! 154 1.1 christos */ 155 1.43 riastrad for (; aa; aa = TAILQ_NEXT(aa, aa_list)) { 156 1.1 christos if (aa->aa_ifp == ifp && 157 1.1 christos (aa->aa_flags & AFA_PHASE2)) 158 1.1 christos break; 159 1.1 christos } 160 1.1 christos } 161 1.1 christos 162 1.1 christos if (ifp == 0) 163 1.1 christos panic("at_control"); 164 1.1 christos 165 1.1 christos /* 166 1.1 christos * If we failed to find an existing at_ifaddr entry, then we 167 1.1 christos * allocate a fresh one. 168 1.1 christos * XXX change this to use malloc 169 1.1 christos */ 170 1.1 christos if (aa == (struct at_ifaddr *) 0) { 171 1.1 christos aa = (struct at_ifaddr *) 172 1.10 perry malloc(sizeof(struct at_ifaddr), M_IFADDR, 173 1.9 matt M_WAITOK|M_ZERO); 174 1.1 christos 175 1.1 christos if (aa == NULL) 176 1.1 christos return (ENOBUFS); 177 1.1 christos 178 1.19 ad callout_init(&aa->aa_probe_ch, 0); 179 1.1 christos 180 1.43 riastrad if ((aa0 = TAILQ_FIRST(&at_ifaddr)) != NULL) { 181 1.1 christos /* 182 1.1 christos * Don't let the loopback be first, since the 183 1.1 christos * first address is the machine's default 184 1.1 christos * address for binding. 185 1.1 christos * If it is, stick ourself in front, otherwise 186 1.1 christos * go to the back of the list. 187 1.1 christos */ 188 1.1 christos if (aa0->aa_ifp->if_flags & IFF_LOOPBACK) { 189 1.1 christos TAILQ_INSERT_HEAD(&at_ifaddr, aa, 190 1.1 christos aa_list); 191 1.1 christos } else { 192 1.1 christos TAILQ_INSERT_TAIL(&at_ifaddr, aa, 193 1.1 christos aa_list); 194 1.1 christos } 195 1.1 christos } else { 196 1.1 christos TAILQ_INSERT_TAIL(&at_ifaddr, aa, aa_list); 197 1.1 christos } 198 1.36 rmind ifaref(&aa->aa_ifa); 199 1.39 ozaki ifa_psref_init(&aa->aa_ifa); 200 1.1 christos 201 1.1 christos /* 202 1.1 christos * Find the end of the interface's addresses 203 1.1 christos * and link our new one on the end 204 1.1 christos */ 205 1.24 dyoung ifa_insert(ifp, &aa->aa_ifa); 206 1.1 christos 207 1.1 christos /* 208 1.1 christos * As the at_ifaddr contains the actual sockaddrs, 209 1.1 christos * and the ifaddr itself, link them al together 210 1.1 christos * correctly. 211 1.1 christos */ 212 1.1 christos aa->aa_ifa.ifa_addr = 213 1.1 christos (struct sockaddr *) &aa->aa_addr; 214 1.1 christos aa->aa_ifa.ifa_dstaddr = 215 1.1 christos (struct sockaddr *) &aa->aa_addr; 216 1.1 christos aa->aa_ifa.ifa_netmask = 217 1.1 christos (struct sockaddr *) &aa->aa_netmask; 218 1.1 christos 219 1.1 christos /* 220 1.1 christos * Set/clear the phase 2 bit. 221 1.1 christos */ 222 1.20 dyoung if (cnr->nr_phase == 1) 223 1.1 christos aa->aa_flags &= ~AFA_PHASE2; 224 1.1 christos else 225 1.1 christos aa->aa_flags |= AFA_PHASE2; 226 1.1 christos 227 1.1 christos /* 228 1.1 christos * and link it all together 229 1.1 christos */ 230 1.1 christos aa->aa_ifp = ifp; 231 1.1 christos } else { 232 1.1 christos /* 233 1.1 christos * If we DID find one then we clobber any routes 234 1.1 christos * dependent on it.. 235 1.1 christos */ 236 1.1 christos at_scrub(ifp, aa); 237 1.1 christos } 238 1.1 christos break; 239 1.1 christos 240 1.1 christos case SIOCGIFADDR: 241 1.20 dyoung csat = satocsat(ifreq_getaddr(cmd, ifr)); 242 1.20 dyoung cnr = (const struct netrange *)csat->sat_zero; 243 1.20 dyoung if (cnr->nr_phase == 1) { 244 1.1 christos /* 245 1.1 christos * If the request is specifying phase 1, then 246 1.1 christos * only look at a phase one address 247 1.1 christos */ 248 1.43 riastrad for (; aa; aa = TAILQ_NEXT(aa, aa_list)) { 249 1.1 christos if (aa->aa_ifp == ifp && 250 1.1 christos (aa->aa_flags & AFA_PHASE2) == 0) 251 1.1 christos break; 252 1.1 christos } 253 1.20 dyoung } else if (cnr->nr_phase == 2) { 254 1.1 christos /* 255 1.8 is * If the request is specifying phase 2, then 256 1.8 is * only look at a phase two address 257 1.1 christos */ 258 1.43 riastrad for (; aa; aa = TAILQ_NEXT(aa, aa_list)) { 259 1.1 christos if (aa->aa_ifp == ifp && 260 1.1 christos (aa->aa_flags & AFA_PHASE2)) 261 1.8 is break; 262 1.8 is } 263 1.8 is } else { 264 1.8 is /* 265 1.8 is * default to everything 266 1.8 is */ 267 1.43 riastrad for (; aa; aa = TAILQ_NEXT(aa, aa_list)) { 268 1.8 is if (aa->aa_ifp == ifp) 269 1.1 christos break; 270 1.1 christos } 271 1.1 christos } 272 1.1 christos 273 1.1 christos if (aa == (struct at_ifaddr *) 0) 274 1.1 christos return (EADDRNOTAVAIL); 275 1.1 christos break; 276 1.1 christos } 277 1.1 christos 278 1.1 christos /* 279 1.1 christos * By the time this switch is run we should be able to assume that 280 1.1 christos * the "aa" pointer is valid when needed. 281 1.1 christos */ 282 1.1 christos switch (cmd) { 283 1.20 dyoung case SIOCGIFADDR: { 284 1.20 dyoung union { 285 1.20 dyoung struct sockaddr sa; 286 1.20 dyoung struct sockaddr_at sat; 287 1.20 dyoung } u; 288 1.1 christos 289 1.1 christos /* 290 1.1 christos * copy the contents of the sockaddr blindly. 291 1.1 christos */ 292 1.20 dyoung sockaddr_copy(&u.sa, sizeof(u), 293 1.20 dyoung (const struct sockaddr *)&aa->aa_addr); 294 1.1 christos /* 295 1.1 christos * and do some cleanups 296 1.1 christos */ 297 1.20 dyoung nr = (struct netrange *)&u.sat.sat_zero; 298 1.20 dyoung nr->nr_phase = (aa->aa_flags & AFA_PHASE2) ? 2 : 1; 299 1.20 dyoung nr->nr_firstnet = aa->aa_firstnet; 300 1.20 dyoung nr->nr_lastnet = aa->aa_lastnet; 301 1.20 dyoung ifreq_setaddr(cmd, ifr, &u.sa); 302 1.1 christos break; 303 1.20 dyoung } 304 1.1 christos 305 1.1 christos case SIOCSIFADDR: 306 1.20 dyoung return at_ifinit(ifp, aa, 307 1.20 dyoung (const struct sockaddr_at *)ifreq_getaddr(cmd, ifr)); 308 1.1 christos 309 1.1 christos case SIOCAIFADDR: 310 1.1 christos if (sateqaddr(&ifra->ifra_addr, &aa->aa_addr)) 311 1.1 christos return 0; 312 1.20 dyoung return at_ifinit(ifp, aa, 313 1.20 dyoung (const struct sockaddr_at *)ifreq_getaddr(cmd, ifr)); 314 1.1 christos 315 1.1 christos case SIOCDIFADDR: 316 1.23 dyoung at_purgeaddr(&aa->aa_ifa); 317 1.1 christos break; 318 1.1 christos 319 1.1 christos default: 320 1.27 dyoung return ENOTTY; 321 1.1 christos } 322 1.1 christos return (0); 323 1.2 thorpej } 324 1.2 thorpej 325 1.2 thorpej void 326 1.23 dyoung at_purgeaddr(struct ifaddr *ifa) 327 1.2 thorpej { 328 1.23 dyoung struct ifnet *ifp = ifa->ifa_ifp; 329 1.2 thorpej struct at_ifaddr *aa = (void *) ifa; 330 1.2 thorpej 331 1.2 thorpej /* 332 1.2 thorpej * scrub all routes.. didn't we just DO this? XXX yes, del it 333 1.2 thorpej * XXX above XXX not necessarily true anymore 334 1.2 thorpej */ 335 1.2 thorpej at_scrub(ifp, aa); 336 1.2 thorpej 337 1.2 thorpej /* 338 1.2 thorpej * remove the ifaddr from the interface 339 1.2 thorpej */ 340 1.24 dyoung ifa_remove(ifp, &aa->aa_ifa); 341 1.2 thorpej TAILQ_REMOVE(&at_ifaddr, aa, aa_list); 342 1.36 rmind ifafree(&aa->aa_ifa); 343 1.3 thorpej } 344 1.3 thorpej 345 1.3 thorpej void 346 1.23 dyoung at_purgeif(struct ifnet *ifp) 347 1.3 thorpej { 348 1.23 dyoung if_purgeaddrs(ifp, AF_APPLETALK, at_purgeaddr); 349 1.1 christos } 350 1.1 christos 351 1.1 christos /* 352 1.1 christos * Given an interface and an at_ifaddr (supposedly on that interface) remove 353 1.1 christos * any routes that depend on this. Why ifp is needed I'm not sure, as 354 1.1 christos * aa->at_ifaddr.ifa_ifp should be the same. 355 1.1 christos */ 356 1.1 christos static int 357 1.28 dsl at_scrub(struct ifnet *ifp, struct at_ifaddr *aa) 358 1.1 christos { 359 1.1 christos int error = 0; 360 1.1 christos 361 1.1 christos if (aa->aa_flags & AFA_ROUTE) { 362 1.1 christos if (ifp->if_flags & IFF_LOOPBACK) 363 1.1 christos error = aa_delsingleroute(&aa->aa_ifa, 364 1.1 christos &aa->aa_addr.sat_addr, &aa->aa_netmask.sat_addr); 365 1.1 christos else if (ifp->if_flags & IFF_POINTOPOINT) 366 1.1 christos error = rtinit(&aa->aa_ifa, RTM_DELETE, RTF_HOST); 367 1.1 christos else if (ifp->if_flags & IFF_BROADCAST) 368 1.1 christos error = aa_dorangeroute(&aa->aa_ifa, 369 1.1 christos ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), 370 1.1 christos RTM_DELETE); 371 1.1 christos 372 1.1 christos aa->aa_ifa.ifa_flags &= ~IFA_ROUTE; 373 1.1 christos aa->aa_flags &= ~AFA_ROUTE; 374 1.1 christos } 375 1.1 christos return error; 376 1.1 christos } 377 1.1 christos 378 1.1 christos /* 379 1.1 christos * given an at_ifaddr,a sockaddr_at and an ifp, 380 1.1 christos * bang them all together at high speed and see what happens 381 1.1 christos */ 382 1.1 christos static int 383 1.28 dsl at_ifinit(struct ifnet *ifp, struct at_ifaddr *aa, const struct sockaddr_at *sat) 384 1.1 christos { 385 1.1 christos struct netrange nr, onr; 386 1.1 christos struct sockaddr_at oldaddr; 387 1.5 thorpej int s = splnet(), error = 0, i, j; 388 1.1 christos int netinc, nodeinc, nnets; 389 1.1 christos u_short net; 390 1.1 christos 391 1.1 christos /* 392 1.1 christos * save the old addresses in the at_ifaddr just in case we need them. 393 1.1 christos */ 394 1.1 christos oldaddr = aa->aa_addr; 395 1.1 christos onr.nr_firstnet = aa->aa_firstnet; 396 1.1 christos onr.nr_lastnet = aa->aa_lastnet; 397 1.1 christos 398 1.1 christos /* 399 1.1 christos * take the address supplied as an argument, and add it to the 400 1.1 christos * at_ifnet (also given). Remember ing to update 401 1.1 christos * those parts of the at_ifaddr that need special processing 402 1.1 christos */ 403 1.30 cegger memset(AA_SAT(aa), 0, sizeof(struct sockaddr_at)); 404 1.32 tsutsui memcpy(&nr, sat->sat_zero, sizeof(struct netrange)); 405 1.32 tsutsui memcpy(AA_SAT(aa)->sat_zero, sat->sat_zero, sizeof(struct netrange)); 406 1.1 christos nnets = ntohs(nr.nr_lastnet) - ntohs(nr.nr_firstnet) + 1; 407 1.1 christos aa->aa_firstnet = nr.nr_firstnet; 408 1.1 christos aa->aa_lastnet = nr.nr_lastnet; 409 1.1 christos 410 1.1 christos #ifdef NETATALKDEBUG 411 1.1 christos printf("at_ifinit: %s: %u.%u range %u-%u phase %d\n", 412 1.1 christos ifp->if_xname, 413 1.1 christos ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, 414 1.1 christos ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), 415 1.1 christos (aa->aa_flags & AFA_PHASE2) ? 2 : 1); 416 1.1 christos #endif 417 1.1 christos 418 1.1 christos /* 419 1.1 christos * We could eliminate the need for a second phase 1 probe (post 420 1.1 christos * autoconf) if we check whether we're resetting the node. Note 421 1.1 christos * that phase 1 probes use only nodes, not net.node pairs. Under 422 1.1 christos * phase 2, both the net and node must be the same. 423 1.1 christos */ 424 1.44 riastrad AA_SAT(aa)->sat_len = sizeof(struct sockaddr_at); 425 1.1 christos AA_SAT(aa)->sat_family = AF_APPLETALK; 426 1.1 christos if (ifp->if_flags & IFF_LOOPBACK) { 427 1.1 christos AA_SAT(aa)->sat_addr.s_net = sat->sat_addr.s_net; 428 1.1 christos AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node; 429 1.1 christos #if 0 430 1.1 christos } else if (fp->if_flags & IFF_POINTOPOINT) { 431 1.1 christos /* unimplemented */ 432 1.1 christos /* 433 1.1 christos * we'd have to copy the dstaddr field over from the sat 434 1.1 christos * but it's not clear that it would contain the right info.. 435 1.1 christos */ 436 1.1 christos #endif 437 1.1 christos } else { 438 1.1 christos /* 439 1.1 christos * We are a normal (probably ethernet) interface. 440 1.1 christos * apply the new address to the interface structures etc. 441 1.1 christos * We will probe this address on the net first, before 442 1.1 christos * applying it to ensure that it is free.. If it is not, then 443 1.1 christos * we will try a number of other randomly generated addresses 444 1.1 christos * in this net and then increment the net. etc.etc. until 445 1.1 christos * we find an unused address. 446 1.1 christos */ 447 1.1 christos aa->aa_flags |= AFA_PROBING; /* if not loopback we Must 448 1.1 christos * probe? */ 449 1.1 christos if (aa->aa_flags & AFA_PHASE2) { 450 1.1 christos if (sat->sat_addr.s_net == ATADDR_ANYNET) { 451 1.1 christos /* 452 1.1 christos * If we are phase 2, and the net was not 453 1.1 christos * specified * then we select a random net 454 1.1 christos * within the supplied netrange. 455 1.1 christos * XXX use /dev/random? 456 1.1 christos */ 457 1.1 christos if (nnets != 1) { 458 1.1 christos net = ntohs(nr.nr_firstnet) + 459 1.14 kardel time_second % (nnets - 1); 460 1.1 christos } else { 461 1.1 christos net = ntohs(nr.nr_firstnet); 462 1.1 christos } 463 1.1 christos } else { 464 1.1 christos /* 465 1.1 christos * if a net was supplied, then check that it 466 1.1 christos * is within the netrange. If it is not then 467 1.1 christos * replace the old values and return an error 468 1.1 christos */ 469 1.1 christos if (ntohs(sat->sat_addr.s_net) < 470 1.1 christos ntohs(nr.nr_firstnet) || 471 1.1 christos ntohs(sat->sat_addr.s_net) > 472 1.1 christos ntohs(nr.nr_lastnet)) { 473 1.1 christos aa->aa_addr = oldaddr; 474 1.1 christos aa->aa_firstnet = onr.nr_firstnet; 475 1.1 christos aa->aa_lastnet = onr.nr_lastnet; 476 1.1 christos splx(s); 477 1.1 christos return (EINVAL); 478 1.1 christos } 479 1.1 christos /* 480 1.1 christos * otherwise just use the new net number.. 481 1.1 christos */ 482 1.1 christos net = ntohs(sat->sat_addr.s_net); 483 1.1 christos } 484 1.1 christos } else { 485 1.1 christos /* 486 1.1 christos * we must be phase one, so just use whatever we were 487 1.1 christos * given. I guess it really isn't going to be used... 488 1.1 christos * RIGHT? 489 1.1 christos */ 490 1.1 christos net = ntohs(sat->sat_addr.s_net); 491 1.1 christos } 492 1.1 christos 493 1.1 christos /* 494 1.1 christos * set the node part of the address into the ifaddr. If it's 495 1.1 christos * not specified, be random about it... XXX use /dev/random? 496 1.1 christos */ 497 1.1 christos if (sat->sat_addr.s_node == ATADDR_ANYNODE) { 498 1.14 kardel AA_SAT(aa)->sat_addr.s_node = time_second; 499 1.1 christos } else { 500 1.1 christos AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node; 501 1.1 christos } 502 1.1 christos 503 1.1 christos /* 504 1.1 christos * step through the nets in the range starting at the 505 1.1 christos * (possibly random) start point. 506 1.1 christos */ 507 1.1 christos for (i = nnets, netinc = 1; i > 0; net = ntohs(nr.nr_firstnet) + 508 1.1 christos ((net - ntohs(nr.nr_firstnet) + netinc) % nnets), i--) { 509 1.1 christos AA_SAT(aa)->sat_addr.s_net = htons(net); 510 1.1 christos 511 1.1 christos /* 512 1.1 christos * using a rather strange stepping method, 513 1.1 christos * stagger through the possible node addresses 514 1.1 christos * Once again, starting at the (possibly random) 515 1.1 christos * initial node address. 516 1.1 christos */ 517 1.14 kardel for (j = 0, nodeinc = time_second | 1; j < 256; 518 1.1 christos j++, AA_SAT(aa)->sat_addr.s_node += nodeinc) { 519 1.1 christos if (AA_SAT(aa)->sat_addr.s_node > 253 || 520 1.1 christos AA_SAT(aa)->sat_addr.s_node < 1) { 521 1.1 christos continue; 522 1.1 christos } 523 1.1 christos aa->aa_probcnt = 10; 524 1.1 christos 525 1.1 christos /* 526 1.1 christos * start off the probes as an asynchronous 527 1.1 christos * activity. though why wait 200mSec? 528 1.1 christos */ 529 1.4 thorpej callout_reset(&aa->aa_probe_ch, hz / 5, 530 1.4 thorpej aarpprobe, ifp); 531 1.26 ad if (tsleep(aa, PPAUSE | PCATCH, "at_ifinit", 532 1.26 ad 0)) { 533 1.1 christos /* 534 1.1 christos * theoretically we shouldn't time out 535 1.1 christos * here so if we returned with an error. 536 1.1 christos */ 537 1.1 christos printf("at_ifinit: timeout?!\n"); 538 1.1 christos aa->aa_addr = oldaddr; 539 1.1 christos aa->aa_firstnet = onr.nr_firstnet; 540 1.1 christos aa->aa_lastnet = onr.nr_lastnet; 541 1.1 christos splx(s); 542 1.1 christos return (EINTR); 543 1.1 christos } 544 1.1 christos /* 545 1.1 christos * The async activity should have woken us 546 1.1 christos * up. We need to see if it was successful in 547 1.1 christos * finding a free spot, or if we need to 548 1.1 christos * iterate to the next address to try. 549 1.1 christos */ 550 1.1 christos if ((aa->aa_flags & AFA_PROBING) == 0) 551 1.1 christos break; 552 1.1 christos } 553 1.1 christos 554 1.1 christos /* 555 1.1 christos * of course we need to break out through two loops... 556 1.1 christos */ 557 1.1 christos if ((aa->aa_flags & AFA_PROBING) == 0) 558 1.1 christos break; 559 1.1 christos 560 1.1 christos /* reset node for next network */ 561 1.14 kardel AA_SAT(aa)->sat_addr.s_node = time_second; 562 1.1 christos } 563 1.1 christos 564 1.1 christos /* 565 1.1 christos * if we are still trying to probe, then we have finished all 566 1.1 christos * the possible addresses, so we need to give up 567 1.1 christos */ 568 1.1 christos if (aa->aa_flags & AFA_PROBING) { 569 1.1 christos aa->aa_addr = oldaddr; 570 1.1 christos aa->aa_firstnet = onr.nr_firstnet; 571 1.1 christos aa->aa_lastnet = onr.nr_lastnet; 572 1.1 christos splx(s); 573 1.1 christos return (EADDRINUSE); 574 1.1 christos } 575 1.1 christos } 576 1.1 christos 577 1.1 christos /* 578 1.1 christos * Now that we have selected an address, we need to tell the 579 1.1 christos * interface about it, just in case it needs to adjust something. 580 1.1 christos */ 581 1.34 dyoung if ((error = if_addr_init(ifp, &aa->aa_ifa, true)) != 0) { 582 1.1 christos /* 583 1.1 christos * of course this could mean that it objects violently 584 1.1 christos * so if it does, we back out again.. 585 1.1 christos */ 586 1.1 christos aa->aa_addr = oldaddr; 587 1.1 christos aa->aa_firstnet = onr.nr_firstnet; 588 1.1 christos aa->aa_lastnet = onr.nr_lastnet; 589 1.1 christos splx(s); 590 1.1 christos return (error); 591 1.1 christos } 592 1.1 christos /* 593 1.1 christos * set up the netmask part of the at_ifaddr and point the appropriate 594 1.1 christos * pointer in the ifaddr to it. probably pointless, but what the 595 1.1 christos * heck.. XXX 596 1.1 christos */ 597 1.30 cegger memset(&aa->aa_netmask, 0, sizeof(aa->aa_netmask)); 598 1.1 christos aa->aa_netmask.sat_len = sizeof(struct sockaddr_at); 599 1.1 christos aa->aa_netmask.sat_family = AF_APPLETALK; 600 1.1 christos aa->aa_netmask.sat_addr.s_net = 0xffff; 601 1.1 christos aa->aa_netmask.sat_addr.s_node = 0; 602 1.1 christos #if 0 603 1.1 christos aa->aa_ifa.ifa_netmask = (struct sockaddr *) &(aa->aa_netmask);/* XXX */ 604 1.1 christos #endif 605 1.1 christos 606 1.1 christos /* 607 1.1 christos * Initialize broadcast (or remote p2p) address 608 1.1 christos */ 609 1.30 cegger memset(&aa->aa_broadaddr, 0, sizeof(aa->aa_broadaddr)); 610 1.1 christos aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at); 611 1.1 christos aa->aa_broadaddr.sat_family = AF_APPLETALK; 612 1.1 christos 613 1.1 christos aa->aa_ifa.ifa_metric = ifp->if_metric; 614 1.1 christos if (ifp->if_flags & IFF_BROADCAST) { 615 1.33 is aa->aa_broadaddr.sat_addr.s_net = htons(ATADDR_ANYNET); 616 1.33 is aa->aa_broadaddr.sat_addr.s_node = ATADDR_BCAST; 617 1.1 christos aa->aa_ifa.ifa_broadaddr = 618 1.1 christos (struct sockaddr *) &aa->aa_broadaddr; 619 1.1 christos /* add the range of routes needed */ 620 1.1 christos error = aa_dorangeroute(&aa->aa_ifa, 621 1.1 christos ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), RTM_ADD); 622 1.1 christos } else if (ifp->if_flags & IFF_POINTOPOINT) { 623 1.1 christos struct at_addr rtaddr, rtmask; 624 1.1 christos 625 1.30 cegger memset(&rtaddr, 0, sizeof(rtaddr)); 626 1.30 cegger memset(&rtmask, 0, sizeof(rtmask)); 627 1.1 christos /* fill in the far end if we know it here XXX */ 628 1.1 christos aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) & aa->aa_dstaddr; 629 1.1 christos error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); 630 1.1 christos } else if (ifp->if_flags & IFF_LOOPBACK) { 631 1.1 christos struct at_addr rtaddr, rtmask; 632 1.1 christos 633 1.30 cegger memset(&rtaddr, 0, sizeof(rtaddr)); 634 1.30 cegger memset(&rtmask, 0, sizeof(rtmask)); 635 1.1 christos rtaddr.s_net = AA_SAT(aa)->sat_addr.s_net; 636 1.1 christos rtaddr.s_node = AA_SAT(aa)->sat_addr.s_node; 637 1.1 christos rtmask.s_net = 0xffff; 638 1.1 christos rtmask.s_node = 0x0; 639 1.1 christos error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); 640 1.1 christos } 641 1.1 christos /* 642 1.1 christos * of course if we can't add these routes we back out, but it's getting 643 1.1 christos * risky by now XXX 644 1.1 christos */ 645 1.1 christos if (error) { 646 1.1 christos at_scrub(ifp, aa); 647 1.1 christos aa->aa_addr = oldaddr; 648 1.1 christos aa->aa_firstnet = onr.nr_firstnet; 649 1.1 christos aa->aa_lastnet = onr.nr_lastnet; 650 1.1 christos splx(s); 651 1.1 christos return (error); 652 1.1 christos } 653 1.1 christos /* 654 1.1 christos * note that the address has a route associated with it.... 655 1.1 christos */ 656 1.1 christos aa->aa_ifa.ifa_flags |= IFA_ROUTE; 657 1.1 christos aa->aa_flags |= AFA_ROUTE; 658 1.1 christos splx(s); 659 1.1 christos return (0); 660 1.1 christos } 661 1.1 christos 662 1.1 christos /* 663 1.1 christos * check whether a given address is a broadcast address for us.. 664 1.1 christos */ 665 1.1 christos int 666 1.17 dyoung at_broadcast(const struct sockaddr_at *sat) 667 1.1 christos { 668 1.1 christos struct at_ifaddr *aa; 669 1.1 christos 670 1.1 christos /* 671 1.1 christos * If the node is not right, it can't be a broadcast 672 1.1 christos */ 673 1.1 christos if (sat->sat_addr.s_node != ATADDR_BCAST) 674 1.1 christos return 0; 675 1.1 christos 676 1.1 christos /* 677 1.1 christos * If the node was right then if the net is right, it's a broadcast 678 1.1 christos */ 679 1.1 christos if (sat->sat_addr.s_net == ATADDR_ANYNET) 680 1.1 christos return 1; 681 1.1 christos 682 1.1 christos /* 683 1.1 christos * failing that, if the net is one we have, it's a broadcast as well. 684 1.1 christos */ 685 1.43 riastrad TAILQ_FOREACH(aa, &at_ifaddr, aa_list) { 686 1.1 christos if ((aa->aa_ifp->if_flags & IFF_BROADCAST) 687 1.1 christos && (ntohs(sat->sat_addr.s_net) >= ntohs(aa->aa_firstnet) 688 1.1 christos && ntohs(sat->sat_addr.s_net) <= ntohs(aa->aa_lastnet))) 689 1.1 christos return 1; 690 1.1 christos } 691 1.1 christos return 0; 692 1.1 christos } 693 1.1 christos 694 1.1 christos 695 1.1 christos /* 696 1.1 christos * aa_dorangeroute() 697 1.1 christos * 698 1.1 christos * Add a route for a range of networks from bot to top - 1. 699 1.1 christos * Algorithm: 700 1.1 christos * 701 1.1 christos * Split the range into two subranges such that the middle 702 1.1 christos * of the two ranges is the point where the highest bit of difference 703 1.37 snj * between the two addresses, makes its transition 704 1.1 christos * Each of the upper and lower ranges might not exist, or might be 705 1.1 christos * representable by 1 or more netmasks. In addition, if both 706 1.1 christos * ranges can be represented by the same netmask, then teh can be merged 707 1.1 christos * by using the next higher netmask.. 708 1.1 christos */ 709 1.1 christos 710 1.1 christos static int 711 1.28 dsl aa_dorangeroute(struct ifaddr *ifa, u_int bot, u_int top, int cmd) 712 1.1 christos { 713 1.1 christos u_int mask1; 714 1.1 christos struct at_addr addr; 715 1.1 christos struct at_addr mask; 716 1.1 christos int error; 717 1.1 christos 718 1.1 christos /* 719 1.1 christos * slight sanity check 720 1.1 christos */ 721 1.1 christos if (bot > top) 722 1.1 christos return (EINVAL); 723 1.1 christos 724 1.1 christos addr.s_node = 0; 725 1.1 christos mask.s_node = 0; 726 1.1 christos /* 727 1.1 christos * just start out with the lowest boundary 728 1.1 christos * and keep extending the mask till it's too big. 729 1.1 christos */ 730 1.1 christos 731 1.1 christos while (bot <= top) { 732 1.1 christos mask1 = 1; 733 1.1 christos while (((bot & ~mask1) >= bot) 734 1.1 christos && ((bot | mask1) <= top)) { 735 1.1 christos mask1 <<= 1; 736 1.1 christos mask1 |= 1; 737 1.1 christos } 738 1.1 christos mask1 >>= 1; 739 1.1 christos mask.s_net = htons(~mask1); 740 1.1 christos addr.s_net = htons(bot); 741 1.1 christos if (cmd == RTM_ADD) { 742 1.1 christos error = aa_addsingleroute(ifa, &addr, &mask); 743 1.1 christos if (error) { 744 1.1 christos /* XXX clean up? */ 745 1.1 christos return (error); 746 1.1 christos } 747 1.1 christos } else { 748 1.1 christos error = aa_delsingleroute(ifa, &addr, &mask); 749 1.1 christos } 750 1.1 christos bot = (bot | mask1) + 1; 751 1.1 christos } 752 1.1 christos return 0; 753 1.1 christos } 754 1.1 christos 755 1.1 christos static int 756 1.28 dsl aa_addsingleroute(struct ifaddr *ifa, struct at_addr *addr, struct at_addr *mask) 757 1.1 christos { 758 1.1 christos int error; 759 1.1 christos 760 1.1 christos #ifdef NETATALKDEBUG 761 1.1 christos printf("aa_addsingleroute: %x.%x mask %x.%x ...", 762 1.1 christos ntohs(addr->s_net), addr->s_node, 763 1.1 christos ntohs(mask->s_net), mask->s_node); 764 1.1 christos #endif 765 1.1 christos 766 1.1 christos error = aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP); 767 1.1 christos #ifdef NETATALKDEBUG 768 1.1 christos if (error) 769 1.1 christos printf("aa_addsingleroute: error %d\n", error); 770 1.1 christos #endif 771 1.1 christos return (error); 772 1.1 christos } 773 1.1 christos 774 1.1 christos static int 775 1.28 dsl aa_delsingleroute(struct ifaddr *ifa, struct at_addr *addr, struct at_addr *mask) 776 1.1 christos { 777 1.1 christos int error; 778 1.1 christos 779 1.1 christos #ifdef NETATALKDEBUG 780 1.1 christos printf("aa_delsingleroute: %x.%x mask %x.%x ...", 781 1.1 christos ntohs(addr->s_net), addr->s_node, 782 1.1 christos ntohs(mask->s_net), mask->s_node); 783 1.1 christos #endif 784 1.1 christos 785 1.1 christos error = aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0); 786 1.1 christos #ifdef NETATALKDEBUG 787 1.1 christos if (error) 788 1.1 christos printf("aa_delsingleroute: error %d\n", error); 789 1.1 christos #endif 790 1.1 christos return (error); 791 1.1 christos } 792 1.1 christos 793 1.1 christos static int 794 1.28 dsl aa_dosingleroute(struct ifaddr *ifa, struct at_addr *at_addr, struct at_addr *at_mask, int cmd, int flags) 795 1.1 christos { 796 1.1 christos struct sockaddr_at addr, mask, *gate; 797 1.1 christos 798 1.30 cegger memset(&addr, 0, sizeof(addr)); 799 1.30 cegger memset(&mask, 0, sizeof(mask)); 800 1.1 christos addr.sat_family = AF_APPLETALK; 801 1.1 christos addr.sat_len = sizeof(struct sockaddr_at); 802 1.1 christos addr.sat_addr.s_net = at_addr->s_net; 803 1.1 christos addr.sat_addr.s_node = at_addr->s_node; 804 1.1 christos mask.sat_family = AF_APPLETALK; 805 1.1 christos mask.sat_len = sizeof(struct sockaddr_at); 806 1.1 christos mask.sat_addr.s_net = at_mask->s_net; 807 1.1 christos mask.sat_addr.s_node = at_mask->s_node; 808 1.1 christos 809 1.1 christos if (at_mask->s_node) { 810 1.1 christos gate = satosat(ifa->ifa_dstaddr); 811 1.1 christos flags |= RTF_HOST; 812 1.1 christos } else { 813 1.1 christos gate = satosat(ifa->ifa_addr); 814 1.1 christos } 815 1.1 christos 816 1.1 christos #ifdef NETATALKDEBUG 817 1.1 christos printf("on %s %x.%x\n", (flags & RTF_HOST) ? "host" : "net", 818 1.1 christos ntohs(gate->sat_addr.s_net), gate->sat_addr.s_node); 819 1.1 christos #endif 820 1.1 christos return (rtrequest(cmd, (struct sockaddr *) &addr, 821 1.1 christos (struct sockaddr *) gate, (struct sockaddr *) &mask, flags, NULL)); 822 1.1 christos } 823 1.1 christos 824 1.1 christos #if 0 825 1.1 christos static void 826 1.29 cegger aa_clean(void) 827 1.1 christos { 828 1.1 christos struct at_ifaddr *aa; 829 1.1 christos struct ifaddr *ifa; 830 1.1 christos struct ifnet *ifp; 831 1.1 christos 832 1.21 dyoung while ((aa = TAILQ_FIRST(&at_ifaddr)) != NULL) { 833 1.21 dyoung TAILQ_REMOVE(&at_ifaddr, aa, aa_list); 834 1.1 christos ifp = aa->aa_ifp; 835 1.1 christos at_scrub(ifp, aa); 836 1.38 ozaki IFADDR_READER_FOREACH(ifa, ifp) { 837 1.21 dyoung if (ifa == &aa->aa_ifa) 838 1.21 dyoung break; 839 1.1 christos } 840 1.21 dyoung if (ifa == NULL) 841 1.21 dyoung panic("aa not present"); 842 1.24 dyoung ifa_remove(ifp, ifa); 843 1.1 christos } 844 1.1 christos } 845 1.1 christos #endif 846