ddp_pcb.c revision 194619
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: head/sys/netatalk/ddp_pcb.c 194619 2009-06-22 10:23:54Z rwatson $ 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(); 116165974Srwatson for (aa = at_ifaddr_list; aa != NULL; 117165974Srwatson aa = aa->aa_next) { 118165974Srwatson if ((sat->sat_addr.s_net == 119165974Srwatson AA_SAT(aa)->sat_addr.s_net) && 120165974Srwatson (sat->sat_addr.s_node == 121165974Srwatson AA_SAT(aa)->sat_addr.s_node)) 122165974Srwatson break; 123165974Srwatson } 124194619Srwatson AT_IFADDR_RUNLOCK(); 125165974Srwatson if (aa == NULL) 126165974Srwatson return (EADDRNOTAVAIL); 12715885Sjulian } 12815885Sjulian 129165974Srwatson if (sat->sat_port != ATADDR_ANYPORT) { 130165974Srwatson if (sat->sat_port < ATPORT_FIRST || 131165974Srwatson sat->sat_port >= ATPORT_LAST) 132165974Srwatson return (EINVAL); 133165974Srwatson if (sat->sat_port < ATPORT_RESERVED && 134165974Srwatson priv_check(td, PRIV_NETATALK_RESERVEDPORT)) 135165974Srwatson return (EACCES); 136165974Srwatson } 137165974Srwatson } else { 138165974Srwatson bzero((caddr_t)&lsat, sizeof(struct sockaddr_at)); 139165974Srwatson lsat.sat_len = sizeof(struct sockaddr_at); 140165974Srwatson lsat.sat_addr.s_node = ATADDR_ANYNODE; 141165974Srwatson lsat.sat_addr.s_net = ATADDR_ANYNET; 142165974Srwatson lsat.sat_family = AF_APPLETALK; 143165974Srwatson sat = &lsat; 14415885Sjulian } 14515885Sjulian 146165974Srwatson if (sat->sat_addr.s_node == ATADDR_ANYNODE && 147127288Srwatson sat->sat_addr.s_net == ATADDR_ANYNET) { 148194619Srwatson AT_IFADDR_RLOCK(); 149194619Srwatson if (at_ifaddr_list == NULL) { 150194619Srwatson AT_IFADDR_RUNLOCK(); 151165974Srwatson return (EADDRNOTAVAIL); 152194619Srwatson } 153165974Srwatson sat->sat_addr = AA_SAT(at_ifaddr_list)->sat_addr; 154194619Srwatson AT_IFADDR_RUNLOCK(); 15515885Sjulian } 156165974Srwatson ddp->ddp_lsat = *sat; 15715885Sjulian 158165974Srwatson /* 159165974Srwatson * Choose port. 160165974Srwatson */ 161165974Srwatson if (sat->sat_port == ATADDR_ANYPORT) { 162165974Srwatson for (sat->sat_port = ATPORT_RESERVED; 163165974Srwatson sat->sat_port < ATPORT_LAST; sat->sat_port++) { 164165974Srwatson if (ddp_ports[sat->sat_port - 1] == NULL) 165165974Srwatson break; 166165974Srwatson } 167165974Srwatson if (sat->sat_port == ATPORT_LAST) 168165974Srwatson return (EADDRNOTAVAIL); 169165974Srwatson ddp->ddp_lsat.sat_port = sat->sat_port; 170165974Srwatson ddp_ports[sat->sat_port - 1] = ddp; 171165974Srwatson } else { 172165974Srwatson for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp; 173165974Srwatson ddpp = ddpp->ddp_pnext) { 174165974Srwatson if (ddpp->ddp_lsat.sat_addr.s_net == 175165974Srwatson sat->sat_addr.s_net && 176165974Srwatson ddpp->ddp_lsat.sat_addr.s_node == 177165974Srwatson sat->sat_addr.s_node) 178165974Srwatson break; 179165974Srwatson } 180165974Srwatson if (ddpp != NULL) 181165974Srwatson return (EADDRINUSE); 182165974Srwatson ddp->ddp_pnext = ddp_ports[sat->sat_port - 1]; 183165974Srwatson ddp_ports[sat->sat_port - 1] = ddp; 184165974Srwatson if (ddp->ddp_pnext != NULL) 185165974Srwatson ddp->ddp_pnext->ddp_pprev = ddp; 18615885Sjulian } 18715885Sjulian 188165974Srwatson return (0); 18915885Sjulian} 19015885Sjulian 191127195Srwatsonint 19283366Sjulianat_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) 19315885Sjulian{ 194165974Srwatson struct sockaddr_at *sat = (struct sockaddr_at *)addr; 195165974Srwatson struct route *ro; 196165974Srwatson struct at_ifaddr *aa = NULL; 197165974Srwatson struct ifnet *ifp; 198165974Srwatson u_short hintnet = 0, net; 19915885Sjulian 200165974Srwatson DDP_LIST_XLOCK_ASSERT(); 201165974Srwatson DDP_LOCK_ASSERT(ddp); 202132043Srwatson 203165974Srwatson if (sat->sat_family != AF_APPLETALK) 204165974Srwatson return (EAFNOSUPPORT); 20515885Sjulian 206165974Srwatson /* 207165974Srwatson * Under phase 2, network 0 means "the network". We take "the 208165974Srwatson * network" to mean the network the control block is bound to. If 209165974Srwatson * the control block is not bound, there is an error. 210165974Srwatson */ 211165974Srwatson if (sat->sat_addr.s_net == ATADDR_ANYNET && 212165974Srwatson sat->sat_addr.s_node != ATADDR_ANYNODE) { 213165974Srwatson if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 214165974Srwatson return (EADDRNOTAVAIL); 215165974Srwatson hintnet = ddp->ddp_lsat.sat_addr.s_net; 21615885Sjulian } 21715885Sjulian 218165974Srwatson ro = &ddp->ddp_route; 219165974Srwatson /* 220165974Srwatson * If we've got an old route for this pcb, check that it is valid. 221165974Srwatson * If we've changed our address, we may have an old "good looking" 222165974Srwatson * route here. Attempt to detect it. 223165974Srwatson */ 224165974Srwatson if (ro->ro_rt) { 225165974Srwatson if (hintnet) 226165974Srwatson net = hintnet; 227165974Srwatson else 228165974Srwatson net = sat->sat_addr.s_net; 229165974Srwatson aa = NULL; 230194619Srwatson AT_IFADDR_RLOCK(); 231165974Srwatson if ((ifp = ro->ro_rt->rt_ifp) != NULL) { 232165974Srwatson for (aa = at_ifaddr_list; aa != NULL; 233165974Srwatson aa = aa->aa_next) { 234165974Srwatson if (aa->aa_ifp == ifp && 235165974Srwatson ntohs(net) >= ntohs(aa->aa_firstnet) && 236165974Srwatson ntohs(net) <= ntohs(aa->aa_lastnet)) 237165974Srwatson break; 238165974Srwatson } 23915885Sjulian } 240165974Srwatson if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net != 241165974Srwatson (hintnet ? hintnet : sat->sat_addr.s_net) || 242165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_node != 243165974Srwatson sat->sat_addr.s_node)) { 244165974Srwatson RTFREE(ro->ro_rt); 245165974Srwatson ro->ro_rt = NULL; 246165974Srwatson } 247194619Srwatson AT_IFADDR_RUNLOCK(); 24815885Sjulian } 24915885Sjulian 250165974Srwatson /* 251165974Srwatson * If we've got no route for this interface, try to find one. 252165974Srwatson */ 253165974Srwatson if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { 254165974Srwatson ro->ro_dst.sa_len = sizeof(struct sockaddr_at); 255165974Srwatson ro->ro_dst.sa_family = AF_APPLETALK; 256165974Srwatson if (hintnet) 257165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_net = hintnet; 258165974Srwatson else 259165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_net = 260165974Srwatson sat->sat_addr.s_net; 261165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node; 262165974Srwatson rtalloc(ro); 26315885Sjulian } 26415885Sjulian 265165974Srwatson /* 266165974Srwatson * Make sure any route that we have has a valid interface. 267165974Srwatson */ 268165974Srwatson aa = NULL; 269165974Srwatson if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) { 270194619Srwatson AT_IFADDR_RLOCK(); 271165974Srwatson for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { 272165974Srwatson if (aa->aa_ifp == ifp) 273165974Srwatson break; 274165974Srwatson } 275194619Srwatson AT_IFADDR_RUNLOCK(); 27615885Sjulian } 277165974Srwatson if (aa == NULL) 278165974Srwatson return (ENETUNREACH); 27915885Sjulian 280165974Srwatson ddp->ddp_fsat = *sat; 281165974Srwatson if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 282165974Srwatson return (at_pcbsetaddr(ddp, NULL, td)); 283165974Srwatson return (0); 28415885Sjulian} 28515885Sjulian 286127195Srwatsonvoid 287127288Srwatsonat_pcbdisconnect(struct ddpcb *ddp) 28815885Sjulian{ 289132043Srwatson 290165974Srwatson DDP_LOCK_ASSERT(ddp); 291132043Srwatson 292165974Srwatson ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; 293165974Srwatson ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 294165974Srwatson ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; 29515885Sjulian} 29615885Sjulian 297127195Srwatsonint 298127288Srwatsonat_pcballoc(struct socket *so) 29915885Sjulian{ 300165974Srwatson struct ddpcb *ddp; 30115885Sjulian 302132043Srwatson DDP_LIST_XLOCK_ASSERT(); 303132043Srwatson 304184205Sdes ddp = malloc(sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO); 305139597Srwatson if (ddp == NULL) 306139597Srwatson return (ENOBUFS); 307132043Srwatson DDP_LOCK_INIT(ddp); 30828270Swollman ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; 30915885Sjulian 310132043Srwatson ddp->ddp_socket = so; 311132043Srwatson so->so_pcb = (caddr_t)ddp; 312132043Srwatson 313127293Srwatson ddp->ddp_next = ddpcb_list; 31428270Swollman ddp->ddp_prev = NULL; 31528270Swollman ddp->ddp_pprev = NULL; 31628270Swollman ddp->ddp_pnext = NULL; 317165974Srwatson if (ddpcb_list != NULL) 318127293Srwatson ddpcb_list->ddp_prev = ddp; 319127293Srwatson ddpcb_list = ddp; 320132043Srwatson return(0); 32115885Sjulian} 32215885Sjulian 323127195Srwatsonvoid 324127288Srwatsonat_pcbdetach(struct socket *so, struct ddpcb *ddp) 32515885Sjulian{ 326132043Srwatson 327165974Srwatson /* 328165974Srwatson * We modify ddp, ddp_ports, and the global list. 329165974Srwatson */ 330165974Srwatson DDP_LIST_XLOCK_ASSERT(); 331165974Srwatson DDP_LOCK_ASSERT(ddp); 332165974Srwatson KASSERT(so->so_pcb != NULL, ("at_pcbdetach: so_pcb == NULL")); 333132043Srwatson 334165974Srwatson so->so_pcb = NULL; 33515885Sjulian 336165974Srwatson /* Remove ddp from ddp_ports list. */ 337165974Srwatson if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && 338165974Srwatson ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) { 339165974Srwatson if (ddp->ddp_pprev != NULL) 340165974Srwatson ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; 341165974Srwatson else 342165974Srwatson ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext; 343165974Srwatson if (ddp->ddp_pnext != NULL) 344165974Srwatson ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; 34515885Sjulian } 34615885Sjulian 347165974Srwatson if (ddp->ddp_route.ro_rt) 348165974Srwatson RTFREE(ddp->ddp_route.ro_rt); 34915885Sjulian 350165974Srwatson if (ddp->ddp_prev) 351165974Srwatson ddp->ddp_prev->ddp_next = ddp->ddp_next; 352165974Srwatson else 353165974Srwatson ddpcb_list = ddp->ddp_next; 354165974Srwatson if (ddp->ddp_next) 355165974Srwatson ddp->ddp_next->ddp_prev = ddp->ddp_prev; 356165974Srwatson DDP_UNLOCK(ddp); 357165974Srwatson DDP_LOCK_DESTROY(ddp); 358184205Sdes free(ddp, M_PCB); 35915885Sjulian} 36015885Sjulian 36115885Sjulian/* 362165974Srwatson * For the moment, this just find the pcb with the correct local address. In 363165974Srwatson * the future, this will actually do some real searching, so we can use the 364165974Srwatson * sender's address to do de-multiplexing on a single port to many sockets 365165974Srwatson * (pcbs). 36615885Sjulian */ 36715885Sjulianstruct ddpcb * 368127288Srwatsonddp_search(struct sockaddr_at *from, struct sockaddr_at *to, 369165974Srwatson struct at_ifaddr *aa) 37015885Sjulian{ 371165974Srwatson struct ddpcb *ddp; 37215885Sjulian 373165974Srwatson DDP_LIST_SLOCK_ASSERT(); 374132043Srwatson 375165974Srwatson /* 376165974Srwatson * Check for bad ports. 377165974Srwatson */ 378165974Srwatson if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) 379165974Srwatson return (NULL); 38015885Sjulian 381165974Srwatson /* 382165974Srwatson * Make sure the local address matches the sent address. What about 383165974Srwatson * the interface? 384165974Srwatson */ 385165974Srwatson for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) { 386165974Srwatson DDP_LOCK(ddp); 387165974Srwatson /* XXX should we handle 0.YY? */ 388165974Srwatson /* XXXX.YY to socket on destination interface */ 389165974Srwatson if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && 390165974Srwatson to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) { 391165974Srwatson DDP_UNLOCK(ddp); 392165974Srwatson break; 393165974Srwatson } 39415885Sjulian 395165974Srwatson /* 0.255 to socket on receiving interface */ 396165974Srwatson if (to->sat_addr.s_node == ATADDR_BCAST && 397165974Srwatson (to->sat_addr.s_net == 0 || 398165974Srwatson to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) && 399165974Srwatson ddp->ddp_lsat.sat_addr.s_net == 400165974Srwatson AA_SAT(aa)->sat_addr.s_net) { 401165974Srwatson DDP_UNLOCK(ddp); 402165974Srwatson break; 403165974Srwatson } 40415885Sjulian 405165974Srwatson /* XXXX.0 to socket on destination interface */ 406165974Srwatson if (to->sat_addr.s_net == aa->aa_firstnet && 407165974Srwatson to->sat_addr.s_node == 0 && 408165974Srwatson ntohs(ddp->ddp_lsat.sat_addr.s_net) >= 409165974Srwatson ntohs(aa->aa_firstnet) && 410165974Srwatson ntohs(ddp->ddp_lsat.sat_addr.s_net) <= 411165974Srwatson ntohs(aa->aa_lastnet)) { 412165974Srwatson DDP_UNLOCK(ddp); 413165974Srwatson break; 414165974Srwatson } 415165974Srwatson DDP_UNLOCK(ddp); 41615885Sjulian } 417165974Srwatson return (ddp); 41815885Sjulian} 419