1139827Simp/*- 2194619Srwatson * Copyright (c) 2004-2009 Robert N. M. Watson 3165891Srwatson * All rights reserved. 4165891Srwatson * 5165891Srwatson * Redistribution and use in source and binary forms, with or without 6165891Srwatson * modification, are permitted provided that the following conditions 7165891Srwatson * are met: 8165891Srwatson * 1. Redistributions of source code must retain the above copyright 9165891Srwatson * notice, this list of conditions and the following disclaimer. 10165891Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11165891Srwatson * notice, this list of conditions and the following disclaimer in the 12165891Srwatson * documentation and/or other materials provided with the distribution. 13165891Srwatson * 14165891Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15165891Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16165891Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17165891Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18165891Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19165891Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20165891Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21165891Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22165891Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23165891Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24165891Srwatson * SUCH DAMAGE. 25165891Srwatson * 26165974Srwatson * Copyright (c) 1990, 1994 Regents of The University of Michigan. 27139827Simp * All Rights Reserved. 2867893Sphk * 29139827Simp * Permission to use, copy, modify, and distribute this software and 30139827Simp * its documentation for any purpose and without fee is hereby granted, 31139827Simp * provided that the above copyright notice appears in all copies and 32139827Simp * that both that copyright notice and this permission notice appear 33139827Simp * in supporting documentation, and that the name of The University 34139827Simp * of Michigan not be used in advertising or publicity pertaining to 35139827Simp * distribution of the software without specific, written prior 36139827Simp * permission. This software is supplied as is without expressed or 37139827Simp * implied warranties of any kind. 38139827Simp * 39139827Simp * This product includes software developed by the University of 40139827Simp * California, Berkeley and its contributors. 41139827Simp * 42139827Simp * Research Systems Unix Group 43139827Simp * The University of Michigan 44139827Simp * c/o Wesley Craig 45139827Simp * 535 W. William Street 46139827Simp * Ann Arbor, Michigan 47139827Simp * +1-313-764-2278 48139827Simp * netatalk@umich.edu 4967893Sphk * $FreeBSD$ 5015885Sjulian */ 5115885Sjulian 5215885Sjulian#include <sys/param.h> 5315885Sjulian#include <sys/systm.h> 5429024Sbde#include <sys/malloc.h> 5515885Sjulian#include <sys/mbuf.h> 56164033Srwatson#include <sys/priv.h> 5715885Sjulian#include <sys/socket.h> 5815885Sjulian#include <sys/socketvar.h> 5915885Sjulian#include <sys/protosw.h> 6015885Sjulian#include <net/if.h> 6115885Sjulian#include <net/route.h> 62111888Sjlemon#include <net/netisr.h> 6315885Sjulian 6418207Sbde#include <netatalk/at.h> 6518207Sbde#include <netatalk/at_var.h> 6618207Sbde#include <netatalk/ddp_var.h> 67127195Srwatson#include <netatalk/ddp_pcb.h> 6815885Sjulian#include <netatalk/at_extern.h> 6915885Sjulian 70132043Srwatsonstruct mtx ddp_list_mtx; 71165974Srwatsonstatic struct ddpcb *ddp_ports[ATPORT_LAST]; 72132043Srwatsonstruct ddpcb *ddpcb_list = NULL; 7315885Sjulian 74127195Srwatsonvoid 7528270Swollmanat_sockaddr(struct ddpcb *ddp, struct sockaddr **addr) 7615885Sjulian{ 77132043Srwatson 78165974Srwatson /* 79165974Srwatson * Prevent modification of ddp during copy of addr. 80165974Srwatson */ 81165974Srwatson DDP_LOCK_ASSERT(ddp); 82165974Srwatson *addr = sodupsockaddr((struct sockaddr *)&ddp->ddp_lsat, M_NOWAIT); 8315885Sjulian} 8415885Sjulian 85127195Srwatsonint 8683366Sjulianat_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) 8715885Sjulian{ 88165974Srwatson struct sockaddr_at lsat, *sat; 89165974Srwatson struct at_ifaddr *aa; 90165974Srwatson struct ddpcb *ddpp; 9115885Sjulian 92165974Srwatson /* 93165974Srwatson * We read and write both the ddp passed in, and also ddp_ports. 94165974Srwatson */ 95165974Srwatson DDP_LIST_XLOCK_ASSERT(); 96165974Srwatson DDP_LOCK_ASSERT(ddp); 97132043Srwatson 98165974Srwatson /* 99165974Srwatson * Shouldn't be bound. 100165974Srwatson */ 101165974Srwatson if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) 102165974Srwatson return (EINVAL); 10315885Sjulian 104165974Srwatson /* 105165974Srwatson * Validate passed address. 106165974Srwatson */ 107194619Srwatson aa = NULL; 108165974Srwatson if (addr != NULL) { 109165974Srwatson sat = (struct sockaddr_at *)addr; 110165974Srwatson if (sat->sat_family != AF_APPLETALK) 111165974Srwatson return (EAFNOSUPPORT); 11215885Sjulian 113165974Srwatson if (sat->sat_addr.s_node != ATADDR_ANYNODE || 114165974Srwatson sat->sat_addr.s_net != ATADDR_ANYNET) { 115194619Srwatson AT_IFADDR_RLOCK(); 116194913Srwatson TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 117165974Srwatson if ((sat->sat_addr.s_net == 118165974Srwatson AA_SAT(aa)->sat_addr.s_net) && 119165974Srwatson (sat->sat_addr.s_node == 120165974Srwatson AA_SAT(aa)->sat_addr.s_node)) 121165974Srwatson break; 122165974Srwatson } 123194619Srwatson AT_IFADDR_RUNLOCK(); 124165974Srwatson if (aa == NULL) 125165974Srwatson return (EADDRNOTAVAIL); 12615885Sjulian } 12715885Sjulian 128165974Srwatson if (sat->sat_port != ATADDR_ANYPORT) { 129165974Srwatson if (sat->sat_port < ATPORT_FIRST || 130165974Srwatson sat->sat_port >= ATPORT_LAST) 131165974Srwatson return (EINVAL); 132165974Srwatson if (sat->sat_port < ATPORT_RESERVED && 133165974Srwatson priv_check(td, PRIV_NETATALK_RESERVEDPORT)) 134165974Srwatson return (EACCES); 135165974Srwatson } 136165974Srwatson } else { 137165974Srwatson bzero((caddr_t)&lsat, sizeof(struct sockaddr_at)); 138165974Srwatson lsat.sat_len = sizeof(struct sockaddr_at); 139165974Srwatson lsat.sat_addr.s_node = ATADDR_ANYNODE; 140165974Srwatson lsat.sat_addr.s_net = ATADDR_ANYNET; 141165974Srwatson lsat.sat_family = AF_APPLETALK; 142165974Srwatson sat = &lsat; 14315885Sjulian } 14415885Sjulian 145165974Srwatson if (sat->sat_addr.s_node == ATADDR_ANYNODE && 146127288Srwatson sat->sat_addr.s_net == ATADDR_ANYNET) { 147194619Srwatson AT_IFADDR_RLOCK(); 148194913Srwatson if (TAILQ_EMPTY(&at_ifaddrhead)) { 149194619Srwatson AT_IFADDR_RUNLOCK(); 150165974Srwatson return (EADDRNOTAVAIL); 151194619Srwatson } 152194913Srwatson sat->sat_addr = AA_SAT(TAILQ_FIRST(&at_ifaddrhead))->sat_addr; 153194619Srwatson AT_IFADDR_RUNLOCK(); 15415885Sjulian } 155165974Srwatson ddp->ddp_lsat = *sat; 15615885Sjulian 157165974Srwatson /* 158165974Srwatson * Choose port. 159165974Srwatson */ 160165974Srwatson if (sat->sat_port == ATADDR_ANYPORT) { 161165974Srwatson for (sat->sat_port = ATPORT_RESERVED; 162165974Srwatson sat->sat_port < ATPORT_LAST; sat->sat_port++) { 163165974Srwatson if (ddp_ports[sat->sat_port - 1] == NULL) 164165974Srwatson break; 165165974Srwatson } 166165974Srwatson if (sat->sat_port == ATPORT_LAST) 167165974Srwatson return (EADDRNOTAVAIL); 168165974Srwatson ddp->ddp_lsat.sat_port = sat->sat_port; 169165974Srwatson ddp_ports[sat->sat_port - 1] = ddp; 170165974Srwatson } else { 171165974Srwatson for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp; 172165974Srwatson ddpp = ddpp->ddp_pnext) { 173165974Srwatson if (ddpp->ddp_lsat.sat_addr.s_net == 174165974Srwatson sat->sat_addr.s_net && 175165974Srwatson ddpp->ddp_lsat.sat_addr.s_node == 176165974Srwatson sat->sat_addr.s_node) 177165974Srwatson break; 178165974Srwatson } 179165974Srwatson if (ddpp != NULL) 180165974Srwatson return (EADDRINUSE); 181165974Srwatson ddp->ddp_pnext = ddp_ports[sat->sat_port - 1]; 182165974Srwatson ddp_ports[sat->sat_port - 1] = ddp; 183165974Srwatson if (ddp->ddp_pnext != NULL) 184165974Srwatson ddp->ddp_pnext->ddp_pprev = ddp; 18515885Sjulian } 18615885Sjulian 187165974Srwatson return (0); 18815885Sjulian} 18915885Sjulian 190127195Srwatsonint 19183366Sjulianat_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) 19215885Sjulian{ 193165974Srwatson struct sockaddr_at *sat = (struct sockaddr_at *)addr; 194165974Srwatson struct route *ro; 195165974Srwatson struct at_ifaddr *aa = NULL; 196165974Srwatson struct ifnet *ifp; 197165974Srwatson u_short hintnet = 0, net; 19815885Sjulian 199165974Srwatson DDP_LIST_XLOCK_ASSERT(); 200165974Srwatson DDP_LOCK_ASSERT(ddp); 201132043Srwatson 202165974Srwatson if (sat->sat_family != AF_APPLETALK) 203165974Srwatson return (EAFNOSUPPORT); 20415885Sjulian 205165974Srwatson /* 206165974Srwatson * Under phase 2, network 0 means "the network". We take "the 207165974Srwatson * network" to mean the network the control block is bound to. If 208165974Srwatson * the control block is not bound, there is an error. 209165974Srwatson */ 210165974Srwatson if (sat->sat_addr.s_net == ATADDR_ANYNET && 211165974Srwatson sat->sat_addr.s_node != ATADDR_ANYNODE) { 212165974Srwatson if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 213165974Srwatson return (EADDRNOTAVAIL); 214165974Srwatson hintnet = ddp->ddp_lsat.sat_addr.s_net; 21515885Sjulian } 21615885Sjulian 217165974Srwatson ro = &ddp->ddp_route; 218165974Srwatson /* 219165974Srwatson * If we've got an old route for this pcb, check that it is valid. 220165974Srwatson * If we've changed our address, we may have an old "good looking" 221165974Srwatson * route here. Attempt to detect it. 222165974Srwatson */ 223165974Srwatson if (ro->ro_rt) { 224165974Srwatson if (hintnet) 225165974Srwatson net = hintnet; 226165974Srwatson else 227165974Srwatson net = sat->sat_addr.s_net; 228165974Srwatson aa = NULL; 229194619Srwatson AT_IFADDR_RLOCK(); 230165974Srwatson if ((ifp = ro->ro_rt->rt_ifp) != NULL) { 231194913Srwatson TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 232165974Srwatson if (aa->aa_ifp == ifp && 233165974Srwatson ntohs(net) >= ntohs(aa->aa_firstnet) && 234165974Srwatson ntohs(net) <= ntohs(aa->aa_lastnet)) 235165974Srwatson break; 236165974Srwatson } 23715885Sjulian } 238165974Srwatson if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net != 239165974Srwatson (hintnet ? hintnet : sat->sat_addr.s_net) || 240165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_node != 241165974Srwatson sat->sat_addr.s_node)) { 242165974Srwatson RTFREE(ro->ro_rt); 243165974Srwatson ro->ro_rt = NULL; 244165974Srwatson } 245194619Srwatson AT_IFADDR_RUNLOCK(); 24615885Sjulian } 24715885Sjulian 248165974Srwatson /* 249165974Srwatson * If we've got no route for this interface, try to find one. 250165974Srwatson */ 251165974Srwatson if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { 252165974Srwatson ro->ro_dst.sa_len = sizeof(struct sockaddr_at); 253165974Srwatson ro->ro_dst.sa_family = AF_APPLETALK; 254165974Srwatson if (hintnet) 255165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_net = hintnet; 256165974Srwatson else 257165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_net = 258165974Srwatson sat->sat_addr.s_net; 259165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node; 260165974Srwatson rtalloc(ro); 26115885Sjulian } 26215885Sjulian 263165974Srwatson /* 264165974Srwatson * Make sure any route that we have has a valid interface. 265165974Srwatson */ 266165974Srwatson aa = NULL; 267165974Srwatson if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) { 268194619Srwatson AT_IFADDR_RLOCK(); 269194913Srwatson TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 270165974Srwatson if (aa->aa_ifp == ifp) 271165974Srwatson break; 272165974Srwatson } 273194619Srwatson AT_IFADDR_RUNLOCK(); 27415885Sjulian } 275165974Srwatson if (aa == NULL) 276165974Srwatson return (ENETUNREACH); 27715885Sjulian 278165974Srwatson ddp->ddp_fsat = *sat; 279165974Srwatson if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 280165974Srwatson return (at_pcbsetaddr(ddp, NULL, td)); 281165974Srwatson return (0); 28215885Sjulian} 28315885Sjulian 284127195Srwatsonvoid 285127288Srwatsonat_pcbdisconnect(struct ddpcb *ddp) 28615885Sjulian{ 287132043Srwatson 288165974Srwatson DDP_LOCK_ASSERT(ddp); 289132043Srwatson 290165974Srwatson ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; 291165974Srwatson ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 292165974Srwatson ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; 29315885Sjulian} 29415885Sjulian 295127195Srwatsonint 296127288Srwatsonat_pcballoc(struct socket *so) 29715885Sjulian{ 298165974Srwatson struct ddpcb *ddp; 29915885Sjulian 300132043Srwatson DDP_LIST_XLOCK_ASSERT(); 301132043Srwatson 302184205Sdes ddp = malloc(sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO); 303139597Srwatson if (ddp == NULL) 304139597Srwatson return (ENOBUFS); 305132043Srwatson DDP_LOCK_INIT(ddp); 30628270Swollman ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; 30715885Sjulian 308132043Srwatson ddp->ddp_socket = so; 309132043Srwatson so->so_pcb = (caddr_t)ddp; 310132043Srwatson 311127293Srwatson ddp->ddp_next = ddpcb_list; 31228270Swollman ddp->ddp_prev = NULL; 31328270Swollman ddp->ddp_pprev = NULL; 31428270Swollman ddp->ddp_pnext = NULL; 315165974Srwatson if (ddpcb_list != NULL) 316127293Srwatson ddpcb_list->ddp_prev = ddp; 317127293Srwatson ddpcb_list = ddp; 318132043Srwatson return(0); 31915885Sjulian} 32015885Sjulian 321127195Srwatsonvoid 322127288Srwatsonat_pcbdetach(struct socket *so, struct ddpcb *ddp) 32315885Sjulian{ 324132043Srwatson 325165974Srwatson /* 326165974Srwatson * We modify ddp, ddp_ports, and the global list. 327165974Srwatson */ 328165974Srwatson DDP_LIST_XLOCK_ASSERT(); 329165974Srwatson DDP_LOCK_ASSERT(ddp); 330165974Srwatson KASSERT(so->so_pcb != NULL, ("at_pcbdetach: so_pcb == NULL")); 331132043Srwatson 332165974Srwatson so->so_pcb = NULL; 33315885Sjulian 334165974Srwatson /* Remove ddp from ddp_ports list. */ 335165974Srwatson if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && 336165974Srwatson ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) { 337165974Srwatson if (ddp->ddp_pprev != NULL) 338165974Srwatson ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; 339165974Srwatson else 340165974Srwatson ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext; 341165974Srwatson if (ddp->ddp_pnext != NULL) 342165974Srwatson ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; 34315885Sjulian } 34415885Sjulian 345165974Srwatson if (ddp->ddp_route.ro_rt) 346165974Srwatson RTFREE(ddp->ddp_route.ro_rt); 34715885Sjulian 348165974Srwatson if (ddp->ddp_prev) 349165974Srwatson ddp->ddp_prev->ddp_next = ddp->ddp_next; 350165974Srwatson else 351165974Srwatson ddpcb_list = ddp->ddp_next; 352165974Srwatson if (ddp->ddp_next) 353165974Srwatson ddp->ddp_next->ddp_prev = ddp->ddp_prev; 354165974Srwatson DDP_UNLOCK(ddp); 355165974Srwatson DDP_LOCK_DESTROY(ddp); 356184205Sdes free(ddp, M_PCB); 35715885Sjulian} 35815885Sjulian 35915885Sjulian/* 360165974Srwatson * For the moment, this just find the pcb with the correct local address. In 361165974Srwatson * the future, this will actually do some real searching, so we can use the 362165974Srwatson * sender's address to do de-multiplexing on a single port to many sockets 363165974Srwatson * (pcbs). 36415885Sjulian */ 36515885Sjulianstruct ddpcb * 366127288Srwatsonddp_search(struct sockaddr_at *from, struct sockaddr_at *to, 367165974Srwatson struct at_ifaddr *aa) 36815885Sjulian{ 369165974Srwatson struct ddpcb *ddp; 37015885Sjulian 371165974Srwatson DDP_LIST_SLOCK_ASSERT(); 372132043Srwatson 373165974Srwatson /* 374165974Srwatson * Check for bad ports. 375165974Srwatson */ 376165974Srwatson if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) 377165974Srwatson return (NULL); 37815885Sjulian 379165974Srwatson /* 380165974Srwatson * Make sure the local address matches the sent address. What about 381165974Srwatson * the interface? 382165974Srwatson */ 383165974Srwatson for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) { 384165974Srwatson DDP_LOCK(ddp); 385165974Srwatson /* XXX should we handle 0.YY? */ 386165974Srwatson /* XXXX.YY to socket on destination interface */ 387165974Srwatson if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && 388165974Srwatson to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) { 389165974Srwatson DDP_UNLOCK(ddp); 390165974Srwatson break; 391165974Srwatson } 39215885Sjulian 393165974Srwatson /* 0.255 to socket on receiving interface */ 394165974Srwatson if (to->sat_addr.s_node == ATADDR_BCAST && 395165974Srwatson (to->sat_addr.s_net == 0 || 396165974Srwatson to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) && 397165974Srwatson ddp->ddp_lsat.sat_addr.s_net == 398165974Srwatson AA_SAT(aa)->sat_addr.s_net) { 399165974Srwatson DDP_UNLOCK(ddp); 400165974Srwatson break; 401165974Srwatson } 40215885Sjulian 403165974Srwatson /* XXXX.0 to socket on destination interface */ 404165974Srwatson if (to->sat_addr.s_net == aa->aa_firstnet && 405165974Srwatson to->sat_addr.s_node == 0 && 406165974Srwatson ntohs(ddp->ddp_lsat.sat_addr.s_net) >= 407165974Srwatson ntohs(aa->aa_firstnet) && 408165974Srwatson ntohs(ddp->ddp_lsat.sat_addr.s_net) <= 409165974Srwatson ntohs(aa->aa_lastnet)) { 410165974Srwatson DDP_UNLOCK(ddp); 411165974Srwatson break; 412165974Srwatson } 413165974Srwatson DDP_UNLOCK(ddp); 41415885Sjulian } 415165974Srwatson return (ddp); 41615885Sjulian} 417