ddp_pcb.c revision 165974
1139827Simp/*- 2139597Srwatson * Copyright (c) 2004-2005 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 165974 2007-01-12 15:07:51Z 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 */ 107165974Srwatson if (addr != NULL) { 108165974Srwatson sat = (struct sockaddr_at *)addr; 109165974Srwatson if (sat->sat_family != AF_APPLETALK) 110165974Srwatson return (EAFNOSUPPORT); 11115885Sjulian 112165974Srwatson if (sat->sat_addr.s_node != ATADDR_ANYNODE || 113165974Srwatson sat->sat_addr.s_net != ATADDR_ANYNET) { 114165974Srwatson for (aa = at_ifaddr_list; aa != NULL; 115165974Srwatson aa = aa->aa_next) { 116165974Srwatson if ((sat->sat_addr.s_net == 117165974Srwatson AA_SAT(aa)->sat_addr.s_net) && 118165974Srwatson (sat->sat_addr.s_node == 119165974Srwatson AA_SAT(aa)->sat_addr.s_node)) 120165974Srwatson break; 121165974Srwatson } 122165974Srwatson if (aa == NULL) 123165974Srwatson return (EADDRNOTAVAIL); 12415885Sjulian } 12515885Sjulian 126165974Srwatson if (sat->sat_port != ATADDR_ANYPORT) { 127165974Srwatson if (sat->sat_port < ATPORT_FIRST || 128165974Srwatson sat->sat_port >= ATPORT_LAST) 129165974Srwatson return (EINVAL); 130165974Srwatson if (sat->sat_port < ATPORT_RESERVED && 131165974Srwatson priv_check(td, PRIV_NETATALK_RESERVEDPORT)) 132165974Srwatson return (EACCES); 133165974Srwatson } 134165974Srwatson } else { 135165974Srwatson bzero((caddr_t)&lsat, sizeof(struct sockaddr_at)); 136165974Srwatson lsat.sat_len = sizeof(struct sockaddr_at); 137165974Srwatson lsat.sat_addr.s_node = ATADDR_ANYNODE; 138165974Srwatson lsat.sat_addr.s_net = ATADDR_ANYNET; 139165974Srwatson lsat.sat_family = AF_APPLETALK; 140165974Srwatson sat = &lsat; 14115885Sjulian } 14215885Sjulian 143165974Srwatson if (sat->sat_addr.s_node == ATADDR_ANYNODE && 144127288Srwatson sat->sat_addr.s_net == ATADDR_ANYNET) { 145165974Srwatson if (at_ifaddr_list == NULL) 146165974Srwatson return (EADDRNOTAVAIL); 147165974Srwatson sat->sat_addr = AA_SAT(at_ifaddr_list)->sat_addr; 14815885Sjulian } 149165974Srwatson ddp->ddp_lsat = *sat; 15015885Sjulian 151165974Srwatson /* 152165974Srwatson * Choose port. 153165974Srwatson */ 154165974Srwatson if (sat->sat_port == ATADDR_ANYPORT) { 155165974Srwatson for (sat->sat_port = ATPORT_RESERVED; 156165974Srwatson sat->sat_port < ATPORT_LAST; sat->sat_port++) { 157165974Srwatson if (ddp_ports[sat->sat_port - 1] == NULL) 158165974Srwatson break; 159165974Srwatson } 160165974Srwatson if (sat->sat_port == ATPORT_LAST) 161165974Srwatson return (EADDRNOTAVAIL); 162165974Srwatson ddp->ddp_lsat.sat_port = sat->sat_port; 163165974Srwatson ddp_ports[sat->sat_port - 1] = ddp; 164165974Srwatson } else { 165165974Srwatson for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp; 166165974Srwatson ddpp = ddpp->ddp_pnext) { 167165974Srwatson if (ddpp->ddp_lsat.sat_addr.s_net == 168165974Srwatson sat->sat_addr.s_net && 169165974Srwatson ddpp->ddp_lsat.sat_addr.s_node == 170165974Srwatson sat->sat_addr.s_node) 171165974Srwatson break; 172165974Srwatson } 173165974Srwatson if (ddpp != NULL) 174165974Srwatson return (EADDRINUSE); 175165974Srwatson ddp->ddp_pnext = ddp_ports[sat->sat_port - 1]; 176165974Srwatson ddp_ports[sat->sat_port - 1] = ddp; 177165974Srwatson if (ddp->ddp_pnext != NULL) 178165974Srwatson ddp->ddp_pnext->ddp_pprev = ddp; 17915885Sjulian } 18015885Sjulian 181165974Srwatson return (0); 18215885Sjulian} 18315885Sjulian 184127195Srwatsonint 18583366Sjulianat_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) 18615885Sjulian{ 187165974Srwatson struct sockaddr_at *sat = (struct sockaddr_at *)addr; 188165974Srwatson struct route *ro; 189165974Srwatson struct at_ifaddr *aa = NULL; 190165974Srwatson struct ifnet *ifp; 191165974Srwatson u_short hintnet = 0, net; 19215885Sjulian 193165974Srwatson DDP_LIST_XLOCK_ASSERT(); 194165974Srwatson DDP_LOCK_ASSERT(ddp); 195132043Srwatson 196165974Srwatson if (sat->sat_family != AF_APPLETALK) 197165974Srwatson return (EAFNOSUPPORT); 19815885Sjulian 199165974Srwatson /* 200165974Srwatson * Under phase 2, network 0 means "the network". We take "the 201165974Srwatson * network" to mean the network the control block is bound to. If 202165974Srwatson * the control block is not bound, there is an error. 203165974Srwatson */ 204165974Srwatson if (sat->sat_addr.s_net == ATADDR_ANYNET && 205165974Srwatson sat->sat_addr.s_node != ATADDR_ANYNODE) { 206165974Srwatson if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 207165974Srwatson return (EADDRNOTAVAIL); 208165974Srwatson hintnet = ddp->ddp_lsat.sat_addr.s_net; 20915885Sjulian } 21015885Sjulian 211165974Srwatson ro = &ddp->ddp_route; 212165974Srwatson /* 213165974Srwatson * If we've got an old route for this pcb, check that it is valid. 214165974Srwatson * If we've changed our address, we may have an old "good looking" 215165974Srwatson * route here. Attempt to detect it. 216165974Srwatson */ 217165974Srwatson if (ro->ro_rt) { 218165974Srwatson if (hintnet) 219165974Srwatson net = hintnet; 220165974Srwatson else 221165974Srwatson net = sat->sat_addr.s_net; 222165974Srwatson aa = NULL; 223165974Srwatson if ((ifp = ro->ro_rt->rt_ifp) != NULL) { 224165974Srwatson for (aa = at_ifaddr_list; aa != NULL; 225165974Srwatson aa = aa->aa_next) { 226165974Srwatson if (aa->aa_ifp == ifp && 227165974Srwatson ntohs(net) >= ntohs(aa->aa_firstnet) && 228165974Srwatson ntohs(net) <= ntohs(aa->aa_lastnet)) 229165974Srwatson break; 230165974Srwatson } 23115885Sjulian } 232165974Srwatson if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net != 233165974Srwatson (hintnet ? hintnet : sat->sat_addr.s_net) || 234165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_node != 235165974Srwatson sat->sat_addr.s_node)) { 236165974Srwatson RTFREE(ro->ro_rt); 237165974Srwatson ro->ro_rt = NULL; 238165974Srwatson } 23915885Sjulian } 24015885Sjulian 241165974Srwatson /* 242165974Srwatson * If we've got no route for this interface, try to find one. 243165974Srwatson */ 244165974Srwatson if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { 245165974Srwatson ro->ro_dst.sa_len = sizeof(struct sockaddr_at); 246165974Srwatson ro->ro_dst.sa_family = AF_APPLETALK; 247165974Srwatson if (hintnet) 248165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_net = hintnet; 249165974Srwatson else 250165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_net = 251165974Srwatson sat->sat_addr.s_net; 252165974Srwatson satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node; 253165974Srwatson rtalloc(ro); 25415885Sjulian } 25515885Sjulian 256165974Srwatson /* 257165974Srwatson * Make sure any route that we have has a valid interface. 258165974Srwatson */ 259165974Srwatson aa = NULL; 260165974Srwatson if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) { 261165974Srwatson for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { 262165974Srwatson if (aa->aa_ifp == ifp) 263165974Srwatson break; 264165974Srwatson } 26515885Sjulian } 266165974Srwatson if (aa == NULL) 267165974Srwatson return (ENETUNREACH); 26815885Sjulian 269165974Srwatson ddp->ddp_fsat = *sat; 270165974Srwatson if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 271165974Srwatson return (at_pcbsetaddr(ddp, NULL, td)); 272165974Srwatson return (0); 27315885Sjulian} 27415885Sjulian 275127195Srwatsonvoid 276127288Srwatsonat_pcbdisconnect(struct ddpcb *ddp) 27715885Sjulian{ 278132043Srwatson 279165974Srwatson DDP_LOCK_ASSERT(ddp); 280132043Srwatson 281165974Srwatson ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; 282165974Srwatson ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 283165974Srwatson ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; 28415885Sjulian} 28515885Sjulian 286127195Srwatsonint 287127288Srwatsonat_pcballoc(struct socket *so) 28815885Sjulian{ 289165974Srwatson struct ddpcb *ddp; 29015885Sjulian 291132043Srwatson DDP_LIST_XLOCK_ASSERT(); 292132043Srwatson 293132043Srwatson MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO); 294139597Srwatson if (ddp == NULL) 295139597Srwatson return (ENOBUFS); 296132043Srwatson DDP_LOCK_INIT(ddp); 29728270Swollman ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; 29815885Sjulian 299132043Srwatson ddp->ddp_socket = so; 300132043Srwatson so->so_pcb = (caddr_t)ddp; 301132043Srwatson 302127293Srwatson ddp->ddp_next = ddpcb_list; 30328270Swollman ddp->ddp_prev = NULL; 30428270Swollman ddp->ddp_pprev = NULL; 30528270Swollman ddp->ddp_pnext = NULL; 306165974Srwatson if (ddpcb_list != NULL) 307127293Srwatson ddpcb_list->ddp_prev = ddp; 308127293Srwatson ddpcb_list = ddp; 309132043Srwatson return(0); 31015885Sjulian} 31115885Sjulian 312127195Srwatsonvoid 313127288Srwatsonat_pcbdetach(struct socket *so, struct ddpcb *ddp) 31415885Sjulian{ 315132043Srwatson 316165974Srwatson /* 317165974Srwatson * We modify ddp, ddp_ports, and the global list. 318165974Srwatson */ 319165974Srwatson DDP_LIST_XLOCK_ASSERT(); 320165974Srwatson DDP_LOCK_ASSERT(ddp); 321165974Srwatson KASSERT(so->so_pcb != NULL, ("at_pcbdetach: so_pcb == NULL")); 322132043Srwatson 323165974Srwatson so->so_pcb = NULL; 32415885Sjulian 325165974Srwatson /* Remove ddp from ddp_ports list. */ 326165974Srwatson if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && 327165974Srwatson ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) { 328165974Srwatson if (ddp->ddp_pprev != NULL) 329165974Srwatson ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; 330165974Srwatson else 331165974Srwatson ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext; 332165974Srwatson if (ddp->ddp_pnext != NULL) 333165974Srwatson ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; 33415885Sjulian } 33515885Sjulian 336165974Srwatson if (ddp->ddp_route.ro_rt) 337165974Srwatson RTFREE(ddp->ddp_route.ro_rt); 33815885Sjulian 339165974Srwatson if (ddp->ddp_prev) 340165974Srwatson ddp->ddp_prev->ddp_next = ddp->ddp_next; 341165974Srwatson else 342165974Srwatson ddpcb_list = ddp->ddp_next; 343165974Srwatson if (ddp->ddp_next) 344165974Srwatson ddp->ddp_next->ddp_prev = ddp->ddp_prev; 345165974Srwatson DDP_UNLOCK(ddp); 346165974Srwatson DDP_LOCK_DESTROY(ddp); 347165974Srwatson FREE(ddp, M_PCB); 34815885Sjulian} 34915885Sjulian 35015885Sjulian/* 351165974Srwatson * For the moment, this just find the pcb with the correct local address. In 352165974Srwatson * the future, this will actually do some real searching, so we can use the 353165974Srwatson * sender's address to do de-multiplexing on a single port to many sockets 354165974Srwatson * (pcbs). 35515885Sjulian */ 35615885Sjulianstruct ddpcb * 357127288Srwatsonddp_search(struct sockaddr_at *from, struct sockaddr_at *to, 358165974Srwatson struct at_ifaddr *aa) 35915885Sjulian{ 360165974Srwatson struct ddpcb *ddp; 36115885Sjulian 362165974Srwatson DDP_LIST_SLOCK_ASSERT(); 363132043Srwatson 364165974Srwatson /* 365165974Srwatson * Check for bad ports. 366165974Srwatson */ 367165974Srwatson if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) 368165974Srwatson return (NULL); 36915885Sjulian 370165974Srwatson /* 371165974Srwatson * Make sure the local address matches the sent address. What about 372165974Srwatson * the interface? 373165974Srwatson */ 374165974Srwatson for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) { 375165974Srwatson DDP_LOCK(ddp); 376165974Srwatson /* XXX should we handle 0.YY? */ 377165974Srwatson /* XXXX.YY to socket on destination interface */ 378165974Srwatson if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && 379165974Srwatson to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) { 380165974Srwatson DDP_UNLOCK(ddp); 381165974Srwatson break; 382165974Srwatson } 38315885Sjulian 384165974Srwatson /* 0.255 to socket on receiving interface */ 385165974Srwatson if (to->sat_addr.s_node == ATADDR_BCAST && 386165974Srwatson (to->sat_addr.s_net == 0 || 387165974Srwatson to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) && 388165974Srwatson ddp->ddp_lsat.sat_addr.s_net == 389165974Srwatson AA_SAT(aa)->sat_addr.s_net) { 390165974Srwatson DDP_UNLOCK(ddp); 391165974Srwatson break; 392165974Srwatson } 39315885Sjulian 394165974Srwatson /* XXXX.0 to socket on destination interface */ 395165974Srwatson if (to->sat_addr.s_net == aa->aa_firstnet && 396165974Srwatson to->sat_addr.s_node == 0 && 397165974Srwatson ntohs(ddp->ddp_lsat.sat_addr.s_net) >= 398165974Srwatson ntohs(aa->aa_firstnet) && 399165974Srwatson ntohs(ddp->ddp_lsat.sat_addr.s_net) <= 400165974Srwatson ntohs(aa->aa_lastnet)) { 401165974Srwatson DDP_UNLOCK(ddp); 402165974Srwatson break; 403165974Srwatson } 404165974Srwatson DDP_UNLOCK(ddp); 40515885Sjulian } 406165974Srwatson return (ddp); 40715885Sjulian} 408