1139827Simp/*- 215885Sjulian * Copyright (c) 1990,1991 Regents of The University of Michigan. 3194619Srwatson * Copyright (c) 2009 Robert N. M. Watson 415885Sjulian * All Rights Reserved. 567893Sphk * 6139827Simp * Permission to use, copy, modify, and distribute this software and 7139827Simp * its documentation for any purpose and without fee is hereby granted, 8139827Simp * provided that the above copyright notice appears in all copies and 9139827Simp * that both that copyright notice and this permission notice appear 10139827Simp * in supporting documentation, and that the name of The University 11139827Simp * of Michigan not be used in advertising or publicity pertaining to 12139827Simp * distribution of the software without specific, written prior 13139827Simp * permission. This software is supplied as is without expressed or 14139827Simp * implied warranties of any kind. 15139827Simp * 16139827Simp * This product includes software developed by the University of 17139827Simp * California, Berkeley and its contributors. 18139827Simp * 19139827Simp * Research Systems Unix Group 20139827Simp * The University of Michigan 21139827Simp * c/o Wesley Craig 22139827Simp * 535 W. William Street 23139827Simp * Ann Arbor, Michigan 24139827Simp * +1-313-764-2278 25139827Simp * netatalk@umich.edu 2615885Sjulian */ 2715885Sjulian 28194619Srwatson#include <sys/cdefs.h> 29194619Srwatson__FBSDID("$FreeBSD$"); 30194619Srwatson 3115885Sjulian#include <sys/param.h> 3215885Sjulian#include <sys/systm.h> 3324204Sbde#include <sys/sockio.h> 34194619Srwatson#include <sys/lock.h> 3529024Sbde#include <sys/malloc.h> 3615885Sjulian#include <sys/kernel.h> 37166833Srwatson#include <sys/priv.h> 38194619Srwatson#include <sys/rwlock.h> 3915885Sjulian#include <sys/socket.h> 4015885Sjulian#include <net/if.h> 4115885Sjulian#include <net/route.h> 4215885Sjulian#include <netinet/in.h> 4315885Sjulian#undef s_net 4415885Sjulian#include <netinet/if_ether.h> 4515885Sjulian 4618207Sbde#include <netatalk/at.h> 4718207Sbde#include <netatalk/at_var.h> 4815885Sjulian#include <netatalk/at_extern.h> 4915885Sjulian 50194619Srwatsonstruct rwlock at_ifaddr_rw; 51194913Srwatsonstruct at_ifaddrhead at_ifaddrhead; 5229182Sbde 53194619SrwatsonRW_SYSINIT(at_ifaddr_rw, &at_ifaddr_rw, "at_ifaddr_rw"); 54194619Srwatson 55132411Srwatsonstatic int aa_dorangeroute(struct ifaddr *ifa, u_int first, u_int last, 56132411Srwatson int cmd); 57132411Srwatsonstatic int aa_addsingleroute(struct ifaddr *ifa, struct at_addr *addr, 58132411Srwatson struct at_addr *mask); 59132411Srwatsonstatic int aa_delsingleroute(struct ifaddr *ifa, struct at_addr *addr, 60132411Srwatson struct at_addr *mask); 6117254Sjulianstatic int aa_dosingleroute(struct ifaddr *ifa, struct at_addr *addr, 62132411Srwatson struct at_addr *mask, int cmd, int flags); 63127288Srwatsonstatic int at_scrub(struct ifnet *ifp, struct at_ifaddr *aa); 64127288Srwatsonstatic int at_ifinit(struct ifnet *ifp, struct at_ifaddr *aa, 65132411Srwatson struct sockaddr_at *sat); 6628845Sjulianstatic int aa_claim_addr(struct ifaddr *ifa, struct sockaddr *gw); 6715885Sjulian 68132411Srwatson#define sateqaddr(a,b) \ 69132411Srwatson ((a)->sat_len == (b)->sat_len && \ 70132411Srwatson (a)->sat_family == (b)->sat_family && \ 71132411Srwatson (a)->sat_addr.s_net == (b)->sat_addr.s_net && \ 72132411Srwatson (a)->sat_addr.s_node == (b)->sat_addr.s_node) 7315885Sjulian 7415885Sjulianint 75132410Srwatsonat_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, 76132410Srwatson struct thread *td) 7715885Sjulian{ 78132410Srwatson struct ifreq *ifr = (struct ifreq *)data; 79132410Srwatson struct sockaddr_at *sat; 80132410Srwatson struct netrange *nr; 81132410Srwatson struct at_aliasreq *ifra = (struct at_aliasreq *)data; 82194819Srwatson struct at_ifaddr *aa; 83194913Srwatson struct ifaddr *ifa; 84194619Srwatson int error; 8515885Sjulian 8617921Sjulian /* 87132410Srwatson * If we have an ifp, then find the matching at_ifaddr if it exists 8817921Sjulian */ 89194819Srwatson aa = NULL; 90194819Srwatson AT_IFADDR_RLOCK(); 91132410Srwatson if (ifp != NULL) { 92194913Srwatson TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 93132410Srwatson if (aa->aa_ifp == ifp) 94132410Srwatson break; 9515885Sjulian } 9615885Sjulian } 97194819Srwatson if (aa != NULL) 98194819Srwatson ifa_ref(&aa->aa_ifa); 99194819Srwatson AT_IFADDR_RUNLOCK(); 100132410Srwatson 10117921Sjulian /* 102132410Srwatson * In this first switch table we are basically getting ready for 103132410Srwatson * the second one, by getting the atalk-specific things set up 104132410Srwatson * so that they start to look more similar to other protocols etc. 10517921Sjulian */ 106194819Srwatson error = 0; 107132410Srwatson switch (cmd) { 108132410Srwatson case SIOCAIFADDR: 109132410Srwatson case SIOCDIFADDR: 110132410Srwatson /* 111132410Srwatson * If we have an appletalk sockaddr, scan forward of where we 112132410Srwatson * are now on the at_ifaddr list to find one with a matching 113132410Srwatson * address on this interface. This may leave aa pointing to 114132410Srwatson * the first address on the NEXT interface! 115132410Srwatson */ 116132410Srwatson if (ifra->ifra_addr.sat_family == AF_APPLETALK) { 117194819Srwatson struct at_ifaddr *oaa; 118194819Srwatson 119194819Srwatson AT_IFADDR_RLOCK(); 120194913Srwatson for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { 121132410Srwatson if (aa->aa_ifp == ifp && 122132410Srwatson sateqaddr(&aa->aa_addr, &ifra->ifra_addr)) 123132410Srwatson break; 124132410Srwatson } 125194819Srwatson if (oaa != NULL && oaa != aa) 126194819Srwatson ifa_free(&oaa->aa_ifa); 127194819Srwatson if (aa != NULL && oaa != aa) 128194819Srwatson ifa_ref(&aa->aa_ifa); 129194819Srwatson AT_IFADDR_RUNLOCK(); 130132410Srwatson } 131132410Srwatson /* 132132410Srwatson * If we a retrying to delete an addres but didn't find such, 133132410Srwatson * then rewurn with an error 134132410Srwatson */ 135194619Srwatson if (cmd == SIOCDIFADDR && aa == NULL) { 136194819Srwatson error = EADDRNOTAVAIL; 137194819Srwatson goto out; 138194619Srwatson } 139132410Srwatson /*FALLTHROUGH*/ 14015885Sjulian 141132410Srwatson case SIOCSIFADDR: 142132410Srwatson /* 143132410Srwatson * If we are not superuser, then we don't get to do these ops. 144164033Srwatson * 145164033Srwatson * XXXRW: Layering? 146132410Srwatson */ 147194619Srwatson if (priv_check(td, PRIV_NET_ADDIFADDR)) { 148194819Srwatson error = EPERM; 149194819Srwatson goto out; 150194619Srwatson } 151132410Srwatson 152132410Srwatson sat = satosat(&ifr->ifr_addr); 153132410Srwatson nr = (struct netrange *)sat->sat_zero; 154132410Srwatson if (nr->nr_phase == 1) { 155194819Srwatson struct at_ifaddr *oaa; 156194819Srwatson 157132410Srwatson /* 158132410Srwatson * Look for a phase 1 address on this interface. 159132410Srwatson * This may leave aa pointing to the first address on 160132410Srwatson * the NEXT interface! 161132410Srwatson */ 162194819Srwatson AT_IFADDR_RLOCK(); 163194913Srwatson for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { 164132410Srwatson if (aa->aa_ifp == ifp && 165132410Srwatson (aa->aa_flags & AFA_PHASE2) == 0) 166132410Srwatson break; 167132410Srwatson } 168194819Srwatson if (oaa != NULL && oaa != aa) 169194819Srwatson ifa_free(&oaa->aa_ifa); 170194819Srwatson if (aa != NULL && oaa != aa) 171194819Srwatson ifa_ref(&aa->aa_ifa); 172194819Srwatson AT_IFADDR_RUNLOCK(); 173132410Srwatson } else { /* default to phase 2 */ 174194819Srwatson struct at_ifaddr *oaa; 175194819Srwatson 176132410Srwatson /* 177132410Srwatson * Look for a phase 2 address on this interface. 178132410Srwatson * This may leave aa pointing to the first address on 179132410Srwatson * the NEXT interface! 180132410Srwatson */ 181194819Srwatson AT_IFADDR_RLOCK(); 182194913Srwatson for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { 183132410Srwatson if (aa->aa_ifp == ifp && (aa->aa_flags & 184132410Srwatson AFA_PHASE2)) 185132410Srwatson break; 186132410Srwatson } 187194819Srwatson if (oaa != NULL && oaa != aa) 188194819Srwatson ifa_free(&oaa->aa_ifa); 189194819Srwatson if (aa != NULL && oaa != aa) 190194819Srwatson ifa_ref(&aa->aa_ifa); 191194819Srwatson AT_IFADDR_RUNLOCK(); 19215885Sjulian } 19315885Sjulian 194132410Srwatson if (ifp == NULL) 195132410Srwatson panic("at_control"); 19615885Sjulian 19715885Sjulian /* 198132410Srwatson * If we failed to find an existing at_ifaddr entry, then we 199132410Srwatson * allocate a fresh one. 20015885Sjulian */ 201132410Srwatson if (aa == NULL) { 202194819Srwatson aa = malloc(sizeof(struct at_ifaddr), M_IFADDR, 203194619Srwatson M_NOWAIT | M_ZERO); 204194819Srwatson if (aa == NULL) { 205194819Srwatson error = ENOBUFS; 206194819Srwatson goto out; 207194619Srwatson } 208194819Srwatson callout_init(&aa->aa_callout, CALLOUT_MPSAFE); 20915885Sjulian 210132410Srwatson ifa = (struct ifaddr *)aa; 211194602Srwatson ifa_init(ifa); 21220407Swollman 213132410Srwatson /* 214132410Srwatson * As the at_ifaddr contains the actual sockaddrs, 215194819Srwatson * and the ifaddr itself, link them all together 216132410Srwatson * correctly. 217132410Srwatson */ 218132410Srwatson ifa->ifa_addr = (struct sockaddr *)&aa->aa_addr; 219132410Srwatson ifa->ifa_dstaddr = (struct sockaddr *)&aa->aa_addr; 220132410Srwatson ifa->ifa_netmask = (struct sockaddr *)&aa->aa_netmask; 22115885Sjulian 222132410Srwatson /* 223132410Srwatson * Set/clear the phase 2 bit. 224132410Srwatson */ 225132410Srwatson if (nr->nr_phase == 1) 226132410Srwatson aa->aa_flags &= ~AFA_PHASE2; 227132410Srwatson else 228132410Srwatson aa->aa_flags |= AFA_PHASE2; 22917921Sjulian 230194913Srwatson ifa_ref(&aa->aa_ifa); /* at_ifaddrhead */ 231194819Srwatson AT_IFADDR_WLOCK(); 232194913Srwatson if (!TAILQ_EMPTY(&at_ifaddrhead)) { 233194819Srwatson /* 234194819Srwatson * Don't let the loopback be first, since the 235194819Srwatson * first address is the machine's default 236194819Srwatson * address for binding. If it is, stick 237194819Srwatson * ourself in front, otherwise go to the back 238194819Srwatson * of the list. 239194819Srwatson */ 240194913Srwatson if (TAILQ_FIRST(&at_ifaddrhead)->aa_ifp-> 241194913Srwatson if_flags & IFF_LOOPBACK) 242194913Srwatson TAILQ_INSERT_HEAD(&at_ifaddrhead, aa, 243194913Srwatson aa_link); 244194913Srwatson else 245194913Srwatson TAILQ_INSERT_TAIL(&at_ifaddrhead, aa, 246194913Srwatson aa_link); 247194819Srwatson } else 248194913Srwatson TAILQ_INSERT_HEAD(&at_ifaddrhead, aa, 249194913Srwatson aa_link); 250194819Srwatson AT_IFADDR_WUNLOCK(); 251194819Srwatson 252132410Srwatson /* 253132410Srwatson * and link it all together 254132410Srwatson */ 255132410Srwatson aa->aa_ifp = ifp; 256194819Srwatson ifa_ref(&aa->aa_ifa); /* if_addrhead */ 257229621Sjhb IF_ADDR_WLOCK(ifp); 258191281Srwatson TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 259229621Sjhb IF_ADDR_WUNLOCK(ifp); 260132410Srwatson } else { 261132410Srwatson /* 262132410Srwatson * If we DID find one then we clobber any routes 263132410Srwatson * dependent on it.. 264132410Srwatson */ 265132410Srwatson at_scrub(ifp, aa); 266132410Srwatson } 267132410Srwatson break; 26815885Sjulian 269132410Srwatson case SIOCGIFADDR : 270132410Srwatson sat = satosat(&ifr->ifr_addr); 271132410Srwatson nr = (struct netrange *)sat->sat_zero; 272132410Srwatson if (nr->nr_phase == 1) { 273194819Srwatson struct at_ifaddr *oaa; 274194819Srwatson 275132410Srwatson /* 276132410Srwatson * If the request is specifying phase 1, then 277132410Srwatson * only look at a phase one address 278132410Srwatson */ 279196121Srwatson AT_IFADDR_RLOCK(); 280194913Srwatson for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { 281132410Srwatson if (aa->aa_ifp == ifp && 282132410Srwatson (aa->aa_flags & AFA_PHASE2) == 0) 283132410Srwatson break; 284132410Srwatson } 285194819Srwatson if (oaa != NULL && oaa != aa) 286194819Srwatson ifa_free(&oaa->aa_ifa); 287194819Srwatson if (aa != NULL && oaa != aa) 288194819Srwatson ifa_ref(&aa->aa_ifa); 289196121Srwatson AT_IFADDR_RUNLOCK(); 290132410Srwatson } else { 291194819Srwatson struct at_ifaddr *oaa; 292194819Srwatson 293132410Srwatson /* 294132410Srwatson * default to phase 2 295132410Srwatson */ 296194819Srwatson AT_IFADDR_RLOCK(); 297194913Srwatson for (oaa = aa; aa; aa = TAILQ_NEXT(aa, aa_link)) { 298132410Srwatson if (aa->aa_ifp == ifp && (aa->aa_flags & 299132410Srwatson AFA_PHASE2)) 300132410Srwatson break; 301132410Srwatson } 302194819Srwatson if (oaa != NULL && oaa != aa) 303194819Srwatson ifa_free(&oaa->aa_ifa); 304194819Srwatson if (aa != NULL && oaa != aa) 305194819Srwatson ifa_ref(&aa->aa_ifa); 306194819Srwatson AT_IFADDR_RUNLOCK(); 30715885Sjulian } 308132410Srwatson 309194619Srwatson if (aa == NULL) { 310194819Srwatson error = EADDRNOTAVAIL; 311194819Srwatson goto out; 312194619Srwatson } 313132410Srwatson break; 31415885Sjulian } 31515885Sjulian 31617921Sjulian /* 317132410Srwatson * By the time this switch is run we should be able to assume that 318132410Srwatson * the "aa" pointer is valid when needed. 31917921Sjulian */ 320132410Srwatson switch (cmd) { 321132410Srwatson case SIOCGIFADDR: 32217921Sjulian 323132410Srwatson /* 324132410Srwatson * copy the contents of the sockaddr blindly. 325132410Srwatson */ 326132410Srwatson sat = (struct sockaddr_at *)&ifr->ifr_addr; 327132410Srwatson *sat = aa->aa_addr; 32815885Sjulian 329132410Srwatson /* 330132410Srwatson * and do some cleanups 331132410Srwatson */ 332132410Srwatson ((struct netrange *)&sat->sat_zero)->nr_phase 333132410Srwatson = (aa->aa_flags & AFA_PHASE2) ? 2 : 1; 334132410Srwatson ((struct netrange *)&sat->sat_zero)->nr_firstnet = 335132410Srwatson aa->aa_firstnet; 336132410Srwatson ((struct netrange *)&sat->sat_zero)->nr_lastnet = 337132410Srwatson aa->aa_lastnet; 338132410Srwatson break; 33915885Sjulian 340132410Srwatson case SIOCSIFADDR: 341194619Srwatson error = at_ifinit(ifp, aa, 342194619Srwatson (struct sockaddr_at *)&ifr->ifr_addr); 343194819Srwatson goto out; 34415885Sjulian 345132410Srwatson case SIOCAIFADDR: 346194619Srwatson if (sateqaddr(&ifra->ifra_addr, &aa->aa_addr)) { 347194819Srwatson error = 0; 348194819Srwatson goto out; 349194619Srwatson } 350194619Srwatson error = at_ifinit(ifp, aa, 351194619Srwatson (struct sockaddr_at *)&ifr->ifr_addr); 352194819Srwatson goto out; 35317921Sjulian 354132410Srwatson case SIOCDIFADDR: 355194819Srwatson 356132410Srwatson /* 357132410Srwatson * remove the ifaddr from the interface 358132410Srwatson */ 359194913Srwatson ifa = (struct ifaddr *)aa; 360229621Sjhb IF_ADDR_WLOCK(ifp); 361194913Srwatson TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 362229621Sjhb IF_ADDR_WUNLOCK(ifp); 363194913Srwatson ifa_free(ifa); /* if_addrhead */ 36417921Sjulian 365132410Srwatson /* 366132410Srwatson * Now remove the at_ifaddr from the parallel structure 367132410Srwatson * as well, or we'd be in deep trouble 368132410Srwatson */ 369194819Srwatson 370194819Srwatson AT_IFADDR_WLOCK(); 371194913Srwatson TAILQ_REMOVE(&at_ifaddrhead, aa, aa_link); 372194619Srwatson AT_IFADDR_WUNLOCK(); 373194913Srwatson ifa_free(ifa); /* at_ifaddrhead */ 374132410Srwatson break; 375132410Srwatson 376132410Srwatson default: 377194819Srwatson if (ifp == NULL || ifp->if_ioctl == NULL) { 378194819Srwatson error = EOPNOTSUPP; 379194819Srwatson goto out; 380194819Srwatson } 381194819Srwatson error = ((*ifp->if_ioctl)(ifp, cmd, data)); 382132410Srwatson } 383194819Srwatson 384194819Srwatsonout: 385194819Srwatson if (aa != NULL) 386194819Srwatson ifa_free(&aa->aa_ifa); 387194819Srwatson return (error); 38815885Sjulian} 38917254Sjulian 39017921Sjulian/* 39117921Sjulian * Given an interface and an at_ifaddr (supposedly on that interface) 39217921Sjulian * remove any routes that depend on this. 39317921Sjulian * Why ifp is needed I'm not sure, 39417921Sjulian * as aa->at_ifaddr.ifa_ifp should be the same. 39517921Sjulian */ 39615885Sjulianstatic int 397132410Srwatsonat_scrub(struct ifnet *ifp, struct at_ifaddr *aa) 39815885Sjulian{ 399132410Srwatson int error; 40015885Sjulian 401132410Srwatson if (aa->aa_flags & AFA_ROUTE) { 402132410Srwatson if (ifp->if_flags & IFF_LOOPBACK) { 403132410Srwatson if ((error = aa_delsingleroute(&aa->aa_ifa, 404132410Srwatson &aa->aa_addr.sat_addr, &aa->aa_netmask.sat_addr)) 405132410Srwatson != 0) 406132410Srwatson return (error); 407132410Srwatson } else if (ifp->if_flags & IFF_POINTOPOINT) { 408132410Srwatson if ((error = rtinit(&aa->aa_ifa, RTM_DELETE, 409132410Srwatson RTF_HOST)) != 0) 410132410Srwatson return (error); 411132410Srwatson } else if (ifp->if_flags & IFF_BROADCAST) { 412132410Srwatson error = aa_dorangeroute(&aa->aa_ifa, 413132410Srwatson ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), 414132410Srwatson RTM_DELETE); 41518005Sjulian } 416132410Srwatson aa->aa_ifa.ifa_flags &= ~IFA_ROUTE; 417132410Srwatson aa->aa_flags &= ~AFA_ROUTE; 41815885Sjulian } 419132410Srwatson return (0); 42015885Sjulian} 42115885Sjulian 42217921Sjulian/* 42317921Sjulian * given an at_ifaddr,a sockaddr_at and an ifp, 42417921Sjulian * bang them all together at high speed and see what happens 42517921Sjulian */ 42615885Sjulianstatic int 427132410Srwatsonat_ifinit(struct ifnet *ifp, struct at_ifaddr *aa, struct sockaddr_at *sat) 42815885Sjulian{ 429132410Srwatson struct netrange nr, onr; 430132410Srwatson struct sockaddr_at oldaddr; 431132410Srwatson int error = 0, i, j; 432132410Srwatson int netinc, nodeinc, nnets; 433132410Srwatson u_short net; 43415885Sjulian 435132410Srwatson /* 436132410Srwatson * save the old addresses in the at_ifaddr just in case we need them. 437132410Srwatson */ 438132410Srwatson oldaddr = aa->aa_addr; 439132410Srwatson onr.nr_firstnet = aa->aa_firstnet; 440132410Srwatson onr.nr_lastnet = aa->aa_lastnet; 44117921Sjulian 442132410Srwatson /* 443132410Srwatson * take the address supplied as an argument, and add it to the 444132410Srwatson * at_ifnet (also given). Remember ing to update 445132410Srwatson * those parts of the at_ifaddr that need special processing 446132410Srwatson */ 447132410Srwatson bzero(AA_SAT(aa), sizeof(struct sockaddr_at)); 448132410Srwatson bcopy(sat->sat_zero, &nr, sizeof(struct netrange)); 449132410Srwatson bcopy(sat->sat_zero, AA_SAT(aa)->sat_zero, sizeof(struct netrange)); 450132410Srwatson nnets = ntohs(nr.nr_lastnet) - ntohs(nr.nr_firstnet) + 1; 451132410Srwatson aa->aa_firstnet = nr.nr_firstnet; 452132410Srwatson aa->aa_lastnet = nr.nr_lastnet; 45315885Sjulian 45417254Sjulian/* XXX ALC */ 45517964Sjulian#if 0 456132410Srwatson printf("at_ifinit: %s: %u.%u range %u-%u phase %d\n", 457132410Srwatson ifp->if_name, 458132410Srwatson ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, 459132410Srwatson ntohs(aa->aa_firstnet), ntohs(aa->aa_lastnet), 460132410Srwatson (aa->aa_flags & AFA_PHASE2) ? 2 : 1); 46117964Sjulian#endif 46217254Sjulian 46317921Sjulian /* 464132410Srwatson * We could eliminate the need for a second phase 1 probe (post 465132410Srwatson * autoconf) if we check whether we're resetting the node. Note 466132410Srwatson * that phase 1 probes use only nodes, not net.node pairs. Under 467132410Srwatson * phase 2, both the net and node must be the same. 46817921Sjulian */ 469132410Srwatson if (ifp->if_flags & IFF_LOOPBACK) { 470132410Srwatson AA_SAT(aa)->sat_len = sat->sat_len; 471132410Srwatson AA_SAT(aa)->sat_family = AF_APPLETALK; 472132410Srwatson AA_SAT(aa)->sat_addr.s_net = sat->sat_addr.s_net; 473132410Srwatson AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node; 474132410Srwatson#if 0 475132410Srwatson } else if (fp->if_flags & IFF_POINTOPOINT) { 476132410Srwatson /* unimplemented */ 477132410Srwatson /* 478132410Srwatson * we'd have to copy the dstaddr field over from the sat 479132410Srwatson * but it's not clear that it would contain the right info.. 480132410Srwatson */ 48117254Sjulian#endif 482132410Srwatson } else { 48317921Sjulian /* 484132410Srwatson * We are a normal (probably ethernet) interface. 485132410Srwatson * apply the new address to the interface structures etc. 486132410Srwatson * We will probe this address on the net first, before 487132410Srwatson * applying it to ensure that it is free.. If it is not, then 488132410Srwatson * we will try a number of other randomly generated addresses 489132410Srwatson * in this net and then increment the net. etc.etc. until 490132410Srwatson * we find an unused address. 49117921Sjulian */ 492132410Srwatson aa->aa_flags |= AFA_PROBING; /* not loopback we Must probe? */ 493132410Srwatson AA_SAT(aa)->sat_len = sizeof(struct sockaddr_at); 494132410Srwatson AA_SAT(aa)->sat_family = AF_APPLETALK; 495132410Srwatson if (aa->aa_flags & AFA_PHASE2) { 496132410Srwatson if (sat->sat_addr.s_net == ATADDR_ANYNET) { 497132410Srwatson /* 498132410Srwatson * If we are phase 2, and the net was not 499132410Srwatson * specified then we select a random net 500132410Srwatson * within the supplied netrange. 501132410Srwatson * XXX use /dev/random? 502132410Srwatson */ 503132410Srwatson if (nnets != 1) 504132410Srwatson net = ntohs(nr.nr_firstnet) + 505132410Srwatson time_second % (nnets - 1); 506132410Srwatson else 507132410Srwatson net = ntohs(nr.nr_firstnet); 508132410Srwatson } else { 509132410Srwatson /* 510132410Srwatson * if a net was supplied, then check that it 511132410Srwatson * is within the netrange. If it is not then 512132410Srwatson * replace the old values and return an error 513132410Srwatson */ 514132410Srwatson if (ntohs(sat->sat_addr.s_net) < 515132410Srwatson ntohs(nr.nr_firstnet) || 516132410Srwatson ntohs(sat->sat_addr.s_net) > 517132410Srwatson ntohs(nr.nr_lastnet)) { 518132410Srwatson aa->aa_addr = oldaddr; 519132410Srwatson aa->aa_firstnet = onr.nr_firstnet; 520132410Srwatson aa->aa_lastnet = onr.nr_lastnet; 521132410Srwatson return (EINVAL); 522132410Srwatson } 523132410Srwatson /* 524132410Srwatson * otherwise just use the new net number.. 525132410Srwatson */ 526132410Srwatson net = ntohs(sat->sat_addr.s_net); 527132410Srwatson } 52815885Sjulian } else { 529132410Srwatson /* 530132410Srwatson * we must be phase one, so just use whatever we were 531132410Srwatson * given. I guess it really isn't going to be 532132410Srwatson * used... RIGHT? 533132410Srwatson */ 534132410Srwatson net = ntohs(sat->sat_addr.s_net); 53515885Sjulian } 536132410Srwatson 537132410Srwatson /* 538132410Srwatson * set the node part of the address into the ifaddr. 539132410Srwatson * If it's not specified, be random about it... 540132410Srwatson * XXX use /dev/random? 54117921Sjulian */ 542132410Srwatson if (sat->sat_addr.s_node == ATADDR_ANYNODE) 543132410Srwatson AA_SAT(aa)->sat_addr.s_node = time_second; 544132410Srwatson else 545132410Srwatson AA_SAT(aa)->sat_addr.s_node = sat->sat_addr.s_node; 546132410Srwatson 547132410Srwatson /* 548132410Srwatson * Copy the phase. 549132410Srwatson */ 550132410Srwatson AA_SAT(aa)->sat_range.r_netrange.nr_phase = 551132410Srwatson ((aa->aa_flags & AFA_PHASE2) ? 2:1); 552132410Srwatson 553132410Srwatson /* 554132410Srwatson * step through the nets in the range 555132410Srwatson * starting at the (possibly random) start point. 556132410Srwatson */ 557132410Srwatson for (i = nnets, netinc = 1; i > 0; net = 558132410Srwatson ntohs(nr.nr_firstnet) + ((net - ntohs(nr.nr_firstnet) + 559132410Srwatson netinc) % nnets), i--) { 560132410Srwatson AA_SAT(aa)->sat_addr.s_net = htons(net); 561132410Srwatson 562132410Srwatson /* 563132410Srwatson * using a rather strange stepping method, 564132410Srwatson * stagger through the possible node addresses 565132410Srwatson * Once again, starting at the (possibly random) 566132410Srwatson * initial node address. 567132410Srwatson */ 568132410Srwatson for (j = 0, nodeinc = time_second | 1; j < 256; 569132410Srwatson j++, AA_SAT(aa)->sat_addr.s_node += nodeinc) { 570132410Srwatson if (AA_SAT(aa)->sat_addr.s_node > 253 || 571132410Srwatson AA_SAT(aa)->sat_addr.s_node < 1) 572132410Srwatson continue; 573132410Srwatson aa->aa_probcnt = 10; 574132410Srwatson 575132410Srwatson /* 576132410Srwatson * start off the probes as an asynchronous 577132410Srwatson * activity. though why wait 200mSec? 578132410Srwatson */ 579142226Srwatson AARPTAB_LOCK(); 580142226Srwatson callout_reset(&aa->aa_callout, hz / 5, 581142226Srwatson aarpprobe, ifp); 582142226Srwatson if (msleep(aa, &aarptab_mtx, PPAUSE|PCATCH, 583142226Srwatson "at_ifinit", 0)) { 584142226Srwatson AARPTAB_UNLOCK(); 585132410Srwatson /* 586132410Srwatson * theoretically we shouldn't time 587132410Srwatson * out here so if we returned with an 588132410Srwatson * error.. 589132410Srwatson */ 590132410Srwatson printf("at_ifinit: why did this " 591132410Srwatson "happen?!\n"); 592132410Srwatson aa->aa_addr = oldaddr; 593132410Srwatson aa->aa_firstnet = onr.nr_firstnet; 594132410Srwatson aa->aa_lastnet = onr.nr_lastnet; 595132410Srwatson return (EINTR); 596132410Srwatson } 597142226Srwatson AARPTAB_UNLOCK(); 598132410Srwatson 599132410Srwatson /* 600132410Srwatson * The async activity should have woken us 601132410Srwatson * up. We need to see if it was successful 602132410Srwatson * in finding a free spot, or if we need to 603132410Srwatson * iterate to the next address to try. 604132410Srwatson */ 605132410Srwatson if ((aa->aa_flags & AFA_PROBING) == 0) 606132410Srwatson break; 607132410Srwatson } 608132410Srwatson 609132410Srwatson /* 610132410Srwatson * of course we need to break out through two loops... 611132410Srwatson */ 612132410Srwatson if ((aa->aa_flags & AFA_PROBING) == 0) 613132410Srwatson break; 614132410Srwatson /* reset node for next network */ 615132410Srwatson AA_SAT(aa)->sat_addr.s_node = time_second; 61615885Sjulian } 617132410Srwatson 61817921Sjulian /* 619132410Srwatson * if we are still trying to probe, then we have finished all 620132410Srwatson * the possible addresses, so we need to give up 62117921Sjulian */ 622132410Srwatson if (aa->aa_flags & AFA_PROBING) { 623132410Srwatson aa->aa_addr = oldaddr; 624132410Srwatson aa->aa_firstnet = onr.nr_firstnet; 625132410Srwatson aa->aa_lastnet = onr.nr_lastnet; 626132410Srwatson return (EADDRINUSE); 627132410Srwatson } 62815885Sjulian } 62915885Sjulian 63017921Sjulian /* 631132410Srwatson * Now that we have selected an address, we need to tell the interface 632132410Srwatson * about it, just in case it needs to adjust something. 63317921Sjulian */ 634132410Srwatson if (ifp->if_ioctl != NULL && 635132410Srwatson (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)aa))) { 636132410Srwatson /* 637132410Srwatson * of course this could mean that it objects violently 638132410Srwatson * so if it does, we back out again.. 639132410Srwatson */ 640132410Srwatson aa->aa_addr = oldaddr; 641132410Srwatson aa->aa_firstnet = onr.nr_firstnet; 642132410Srwatson aa->aa_lastnet = onr.nr_lastnet; 643132410Srwatson return (error); 64415885Sjulian } 64515885Sjulian 64617921Sjulian /* 647132410Srwatson * set up the netmask part of the at_ifaddr 648132410Srwatson * and point the appropriate pointer in the ifaddr to it. 649132410Srwatson * probably pointless, but what the heck.. XXX 65028845Sjulian */ 651132410Srwatson bzero(&aa->aa_netmask, sizeof(aa->aa_netmask)); 652132410Srwatson aa->aa_netmask.sat_len = sizeof(struct sockaddr_at); 653132410Srwatson aa->aa_netmask.sat_family = AF_APPLETALK; 654132410Srwatson aa->aa_netmask.sat_addr.s_net = 0xffff; 655132410Srwatson aa->aa_netmask.sat_addr.s_node = 0; 656132410Srwatson aa->aa_ifa.ifa_netmask =(struct sockaddr *) &(aa->aa_netmask); /* XXX */ 65728845Sjulian 658132410Srwatson /* 659132410Srwatson * Initialize broadcast (or remote p2p) address 66017921Sjulian */ 661132410Srwatson bzero(&aa->aa_broadaddr, sizeof(aa->aa_broadaddr)); 662132410Srwatson aa->aa_broadaddr.sat_len = sizeof(struct sockaddr_at); 663132410Srwatson aa->aa_broadaddr.sat_family = AF_APPLETALK; 66415885Sjulian 665132410Srwatson aa->aa_ifa.ifa_metric = ifp->if_metric; 666132410Srwatson if (ifp->if_flags & IFF_BROADCAST) { 667132410Srwatson aa->aa_broadaddr.sat_addr.s_net = htons(0); 668132410Srwatson aa->aa_broadaddr.sat_addr.s_node = 0xff; 669132410Srwatson aa->aa_ifa.ifa_broadaddr = (struct sockaddr *) 670132410Srwatson &aa->aa_broadaddr; 671132410Srwatson /* add the range of routes needed */ 672132410Srwatson error = aa_dorangeroute(&aa->aa_ifa, ntohs(aa->aa_firstnet), 673132410Srwatson ntohs(aa->aa_lastnet), RTM_ADD); 674132410Srwatson } else if (ifp->if_flags & IFF_POINTOPOINT) { 675132410Srwatson struct at_addr rtaddr, rtmask; 67617921Sjulian 677132410Srwatson bzero(&rtaddr, sizeof(rtaddr)); 678132410Srwatson bzero(&rtmask, sizeof(rtmask)); 679132410Srwatson /* fill in the far end if we know it here XXX */ 680132410Srwatson aa->aa_ifa.ifa_dstaddr = (struct sockaddr *) &aa->aa_dstaddr; 681132410Srwatson error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); 682132410Srwatson } else if (ifp->if_flags & IFF_LOOPBACK) { 683132410Srwatson struct at_addr rtaddr, rtmask; 68417921Sjulian 685132410Srwatson bzero(&rtaddr, sizeof(rtaddr)); 686132410Srwatson bzero(&rtmask, sizeof(rtmask)); 687132410Srwatson rtaddr.s_net = AA_SAT(aa)->sat_addr.s_net; 688132410Srwatson rtaddr.s_node = AA_SAT(aa)->sat_addr.s_node; 689132410Srwatson rtmask.s_net = 0xffff; 690132410Srwatson /* XXX should not be so.. should be HOST route */ 691132410Srwatson rtmask.s_node = 0x0; 692132410Srwatson error = aa_addsingleroute(&aa->aa_ifa, &rtaddr, &rtmask); 69315885Sjulian } 69415885Sjulian 69517921Sjulian /* 696132410Srwatson * set the address of our "check if this addr is ours" routine. 69717921Sjulian */ 698132410Srwatson aa->aa_ifa.ifa_claim_addr = aa_claim_addr; 69917921Sjulian 700132410Srwatson /* 701132410Srwatson * of course if we can't add these routes we back out, but it's 702132410Srwatson * getting risky by now XXX 703132410Srwatson */ 704132410Srwatson if (error) { 705132410Srwatson at_scrub(ifp, aa); 706132410Srwatson aa->aa_addr = oldaddr; 707132410Srwatson aa->aa_firstnet = onr.nr_firstnet; 708132410Srwatson aa->aa_lastnet = onr.nr_lastnet; 709132410Srwatson return (error); 71015885Sjulian } 71115885Sjulian 71217921Sjulian /* 713132410Srwatson * note that the address has a route associated with it.... 71417921Sjulian */ 715132410Srwatson aa->aa_ifa.ifa_flags |= IFA_ROUTE; 716132410Srwatson aa->aa_flags |= AFA_ROUTE; 717132410Srwatson return (0); 71815885Sjulian} 71915885Sjulian 72017921Sjulian/* 72117921Sjulian * check whether a given address is a broadcast address for us.. 72217921Sjulian */ 72315885Sjulianint 724249925Sglebiusat_broadcast(const struct sockaddr_at *sat) 72515885Sjulian{ 726132410Srwatson struct at_ifaddr *aa; 72715885Sjulian 728194619Srwatson AT_IFADDR_LOCK_ASSERT(); 729194619Srwatson 730132410Srwatson /* 731132410Srwatson * If the node is not right, it can't be a broadcast 732132410Srwatson */ 733132410Srwatson if (sat->sat_addr.s_node != ATADDR_BCAST) 734132410Srwatson return (0); 73517921Sjulian 736132410Srwatson /* 737132410Srwatson * If the node was right then if the net is right, it's a broadcast 738132410Srwatson */ 739132410Srwatson if (sat->sat_addr.s_net == ATADDR_ANYNET) 740132410Srwatson return (1); 74117921Sjulian 742132410Srwatson /* 743132410Srwatson * failing that, if the net is one we have, it's a broadcast as well. 744132410Srwatson */ 745194913Srwatson TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 746132410Srwatson if ((aa->aa_ifp->if_flags & IFF_BROADCAST) 747132410Srwatson && (ntohs(sat->sat_addr.s_net) >= ntohs(aa->aa_firstnet) 748132410Srwatson && ntohs(sat->sat_addr.s_net) <= ntohs(aa->aa_lastnet))) 749127288Srwatson return (1); 75015885Sjulian } 751132410Srwatson return (0); 75215885Sjulian} 75315885Sjulian 75417254Sjulian/* 75517967Sjulian * aa_dorangeroute() 75617254Sjulian * 75717967Sjulian * Add a route for a range of networks from bot to top - 1. 75817254Sjulian * Algorithm: 75917254Sjulian * 76017967Sjulian * Split the range into two subranges such that the middle 76117967Sjulian * of the two ranges is the point where the highest bit of difference 76235256Sdes * between the two addresses makes its transition. 76317967Sjulian * Each of the upper and lower ranges might not exist, or might be 76417967Sjulian * representable by 1 or more netmasks. In addition, if both 76537965Salex * ranges can be represented by the same netmask, then they can be merged 76617967Sjulian * by using the next higher netmask.. 76717254Sjulian */ 76817254Sjulian 76917254Sjulianstatic int 77017967Sjulianaa_dorangeroute(struct ifaddr *ifa, u_int bot, u_int top, int cmd) 77117254Sjulian{ 77217964Sjulian u_int mask1; 77317964Sjulian struct at_addr addr; 77417964Sjulian struct at_addr mask; 77517964Sjulian int error; 77617254Sjulian 77717964Sjulian /* 77817964Sjulian * slight sanity check 77917964Sjulian */ 78017964Sjulian if (bot > top) return (EINVAL); 78117254Sjulian 78217964Sjulian addr.s_node = 0; 78317964Sjulian mask.s_node = 0; 78417964Sjulian /* 78517964Sjulian * just start out with the lowest boundary 78617964Sjulian * and keep extending the mask till it's too big. 78717964Sjulian */ 78817964Sjulian 78917964Sjulian while (bot <= top) { 79017964Sjulian mask1 = 1; 791132410Srwatson while (((bot & ~mask1) >= bot) && ((bot | mask1) <= top)) { 79217964Sjulian mask1 <<= 1; 79317964Sjulian mask1 |= 1; 79417964Sjulian } 79517964Sjulian mask1 >>= 1; 79617964Sjulian mask.s_net = htons(~mask1); 79717964Sjulian addr.s_net = htons(bot); 798132410Srwatson if (cmd == RTM_ADD) { 799132410Srwatson error = aa_addsingleroute(ifa,&addr,&mask); 80017967Sjulian if (error) { 80117967Sjulian /* XXX clean up? */ 80217967Sjulian return (error); 80317967Sjulian } 804132410Srwatson } else 80517967Sjulian error = aa_delsingleroute(ifa,&addr,&mask); 80617964Sjulian bot = (bot | mask1) + 1; 80717964Sjulian } 808127288Srwatson return (0); 80917254Sjulian} 81017254Sjulian 81117254Sjulianstatic int 812132410Srwatsonaa_addsingleroute(struct ifaddr *ifa, struct at_addr *addr, 813132410Srwatson struct at_addr *mask) 81417254Sjulian{ 81517254Sjulian 81617964Sjulian#if 0 817132410Srwatson printf("aa_addsingleroute: %x.%x mask %x.%x ...\n", 818132410Srwatson ntohs(addr->s_net), addr->s_node, ntohs(mask->s_net), 819132410Srwatson mask->s_node); 82017964Sjulian#endif 82117254Sjulian 822194822Srwatson return (aa_dosingleroute(ifa, addr, mask, RTM_ADD, RTF_UP)); 82317254Sjulian} 82417254Sjulian 82517254Sjulianstatic int 826132410Srwatsonaa_delsingleroute(struct ifaddr *ifa, struct at_addr *addr, 827132410Srwatson struct at_addr *mask) 82817254Sjulian{ 82917254Sjulian 830194822Srwatson return (aa_dosingleroute(ifa, addr, mask, RTM_DELETE, 0)); 83117254Sjulian} 83217254Sjulian 83317254Sjulianstatic int 834132410Srwatsonaa_dosingleroute(struct ifaddr *ifa, struct at_addr *at_addr, 835132410Srwatson struct at_addr *at_mask, int cmd, int flags) 83617254Sjulian{ 837132410Srwatson struct sockaddr_at addr, mask; 83817254Sjulian 839132410Srwatson bzero(&addr, sizeof(addr)); 840132410Srwatson bzero(&mask, sizeof(mask)); 841132410Srwatson addr.sat_family = AF_APPLETALK; 842132410Srwatson addr.sat_len = sizeof(struct sockaddr_at); 843132410Srwatson addr.sat_addr.s_net = at_addr->s_net; 844132410Srwatson addr.sat_addr.s_node = at_addr->s_node; 845132410Srwatson mask.sat_family = AF_APPLETALK; 846132410Srwatson mask.sat_len = sizeof(struct sockaddr_at); 847132410Srwatson mask.sat_addr.s_net = at_mask->s_net; 848132410Srwatson mask.sat_addr.s_node = at_mask->s_node; 849132410Srwatson if (at_mask->s_node) 850132410Srwatson flags |= RTF_HOST; 851132410Srwatson return (rtrequest(cmd, (struct sockaddr *) &addr, 852132410Srwatson (flags & RTF_HOST)?(ifa->ifa_dstaddr):(ifa->ifa_addr), 853132410Srwatson (struct sockaddr *) &mask, flags, NULL)); 85417254Sjulian} 85517254Sjulian 85628845Sjulianstatic int 85728845Sjulianaa_claim_addr(struct ifaddr *ifa, struct sockaddr *gw0) 85828845Sjulian{ 85928845Sjulian struct sockaddr_at *addr = (struct sockaddr_at *)ifa->ifa_addr; 86028845Sjulian struct sockaddr_at *gw = (struct sockaddr_at *)gw0; 86128845Sjulian 86228845Sjulian switch (gw->sat_range.r_netrange.nr_phase) { 86328845Sjulian case 1: 86428845Sjulian if(addr->sat_range.r_netrange.nr_phase == 1) 865127288Srwatson return (1); 866132410Srwatson 86728845Sjulian case 0: 86828845Sjulian case 2: 86928845Sjulian /* 87028845Sjulian * if it's our net (including 0), 87128845Sjulian * or netranges are valid, and we are in the range, 87228845Sjulian * then it's ours. 87328845Sjulian */ 87428845Sjulian if ((addr->sat_addr.s_net == gw->sat_addr.s_net) 875132410Srwatson || ((addr->sat_range.r_netrange.nr_lastnet) 876132410Srwatson && (ntohs(gw->sat_addr.s_net) >= 877132410Srwatson ntohs(addr->sat_range.r_netrange.nr_firstnet)) 878132410Srwatson && (ntohs(gw->sat_addr.s_net) <= 879132410Srwatson ntohs(addr->sat_range.r_netrange.nr_lastnet)))) 880127288Srwatson return (1); 88128845Sjulian break; 88228845Sjulian default: 88328845Sjulian printf("atalk: bad phase\n"); 88428845Sjulian } 885127288Srwatson return (0); 88628845Sjulian} 887