ddp_pcb.c revision 165974
1230479Snetchild/*- 2230479Snetchild * Copyright (c) 2004-2005 Robert N. M. Watson 3230479Snetchild * All rights reserved. 4230479Snetchild * 5230479Snetchild * Redistribution and use in source and binary forms, with or without 6230479Snetchild * modification, are permitted provided that the following conditions 7230479Snetchild * are met: 8230479Snetchild * 1. Redistributions of source code must retain the above copyright 9230479Snetchild * notice, this list of conditions and the following disclaimer. 10230479Snetchild * 2. Redistributions in binary form must reproduce the above copyright 11230479Snetchild * notice, this list of conditions and the following disclaimer in the 12230479Snetchild * documentation and/or other materials provided with the distribution. 13230479Snetchild * 14230479Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15230479Snetchild * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16230479Snetchild * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17230479Snetchild * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18230479Snetchild * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19230479Snetchild * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20230479Snetchild * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21230479Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * Copyright (c) 1990, 1994 Regents of The University of Michigan. 27 * All Rights Reserved. 28 * 29 * Permission to use, copy, modify, and distribute this software and 30 * its documentation for any purpose and without fee is hereby granted, 31 * provided that the above copyright notice appears in all copies and 32 * that both that copyright notice and this permission notice appear 33 * in supporting documentation, and that the name of The University 34 * of Michigan not be used in advertising or publicity pertaining to 35 * distribution of the software without specific, written prior 36 * permission. This software is supplied as is without expressed or 37 * implied warranties of any kind. 38 * 39 * This product includes software developed by the University of 40 * California, Berkeley and its contributors. 41 * 42 * Research Systems Unix Group 43 * The University of Michigan 44 * c/o Wesley Craig 45 * 535 W. William Street 46 * Ann Arbor, Michigan 47 * +1-313-764-2278 48 * netatalk@umich.edu 49 * $FreeBSD: head/sys/netatalk/ddp_pcb.c 165974 2007-01-12 15:07:51Z rwatson $ 50 */ 51 52#include <sys/param.h> 53#include <sys/systm.h> 54#include <sys/malloc.h> 55#include <sys/mbuf.h> 56#include <sys/priv.h> 57#include <sys/socket.h> 58#include <sys/socketvar.h> 59#include <sys/protosw.h> 60#include <net/if.h> 61#include <net/route.h> 62#include <net/netisr.h> 63 64#include <netatalk/at.h> 65#include <netatalk/at_var.h> 66#include <netatalk/ddp_var.h> 67#include <netatalk/ddp_pcb.h> 68#include <netatalk/at_extern.h> 69 70struct mtx ddp_list_mtx; 71static struct ddpcb *ddp_ports[ATPORT_LAST]; 72struct ddpcb *ddpcb_list = NULL; 73 74void 75at_sockaddr(struct ddpcb *ddp, struct sockaddr **addr) 76{ 77 78 /* 79 * Prevent modification of ddp during copy of addr. 80 */ 81 DDP_LOCK_ASSERT(ddp); 82 *addr = sodupsockaddr((struct sockaddr *)&ddp->ddp_lsat, M_NOWAIT); 83} 84 85int 86at_pcbsetaddr(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) 87{ 88 struct sockaddr_at lsat, *sat; 89 struct at_ifaddr *aa; 90 struct ddpcb *ddpp; 91 92 /* 93 * We read and write both the ddp passed in, and also ddp_ports. 94 */ 95 DDP_LIST_XLOCK_ASSERT(); 96 DDP_LOCK_ASSERT(ddp); 97 98 /* 99 * Shouldn't be bound. 100 */ 101 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT) 102 return (EINVAL); 103 104 /* 105 * Validate passed address. 106 */ 107 if (addr != NULL) { 108 sat = (struct sockaddr_at *)addr; 109 if (sat->sat_family != AF_APPLETALK) 110 return (EAFNOSUPPORT); 111 112 if (sat->sat_addr.s_node != ATADDR_ANYNODE || 113 sat->sat_addr.s_net != ATADDR_ANYNET) { 114 for (aa = at_ifaddr_list; aa != NULL; 115 aa = aa->aa_next) { 116 if ((sat->sat_addr.s_net == 117 AA_SAT(aa)->sat_addr.s_net) && 118 (sat->sat_addr.s_node == 119 AA_SAT(aa)->sat_addr.s_node)) 120 break; 121 } 122 if (aa == NULL) 123 return (EADDRNOTAVAIL); 124 } 125 126 if (sat->sat_port != ATADDR_ANYPORT) { 127 if (sat->sat_port < ATPORT_FIRST || 128 sat->sat_port >= ATPORT_LAST) 129 return (EINVAL); 130 if (sat->sat_port < ATPORT_RESERVED && 131 priv_check(td, PRIV_NETATALK_RESERVEDPORT)) 132 return (EACCES); 133 } 134 } else { 135 bzero((caddr_t)&lsat, sizeof(struct sockaddr_at)); 136 lsat.sat_len = sizeof(struct sockaddr_at); 137 lsat.sat_addr.s_node = ATADDR_ANYNODE; 138 lsat.sat_addr.s_net = ATADDR_ANYNET; 139 lsat.sat_family = AF_APPLETALK; 140 sat = &lsat; 141 } 142 143 if (sat->sat_addr.s_node == ATADDR_ANYNODE && 144 sat->sat_addr.s_net == ATADDR_ANYNET) { 145 if (at_ifaddr_list == NULL) 146 return (EADDRNOTAVAIL); 147 sat->sat_addr = AA_SAT(at_ifaddr_list)->sat_addr; 148 } 149 ddp->ddp_lsat = *sat; 150 151 /* 152 * Choose port. 153 */ 154 if (sat->sat_port == ATADDR_ANYPORT) { 155 for (sat->sat_port = ATPORT_RESERVED; 156 sat->sat_port < ATPORT_LAST; sat->sat_port++) { 157 if (ddp_ports[sat->sat_port - 1] == NULL) 158 break; 159 } 160 if (sat->sat_port == ATPORT_LAST) 161 return (EADDRNOTAVAIL); 162 ddp->ddp_lsat.sat_port = sat->sat_port; 163 ddp_ports[sat->sat_port - 1] = ddp; 164 } else { 165 for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp; 166 ddpp = ddpp->ddp_pnext) { 167 if (ddpp->ddp_lsat.sat_addr.s_net == 168 sat->sat_addr.s_net && 169 ddpp->ddp_lsat.sat_addr.s_node == 170 sat->sat_addr.s_node) 171 break; 172 } 173 if (ddpp != NULL) 174 return (EADDRINUSE); 175 ddp->ddp_pnext = ddp_ports[sat->sat_port - 1]; 176 ddp_ports[sat->sat_port - 1] = ddp; 177 if (ddp->ddp_pnext != NULL) 178 ddp->ddp_pnext->ddp_pprev = ddp; 179 } 180 181 return (0); 182} 183 184int 185at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) 186{ 187 struct sockaddr_at *sat = (struct sockaddr_at *)addr; 188 struct route *ro; 189 struct at_ifaddr *aa = NULL; 190 struct ifnet *ifp; 191 u_short hintnet = 0, net; 192 193 DDP_LIST_XLOCK_ASSERT(); 194 DDP_LOCK_ASSERT(ddp); 195 196 if (sat->sat_family != AF_APPLETALK) 197 return (EAFNOSUPPORT); 198 199 /* 200 * Under phase 2, network 0 means "the network". We take "the 201 * network" to mean the network the control block is bound to. If 202 * the control block is not bound, there is an error. 203 */ 204 if (sat->sat_addr.s_net == ATADDR_ANYNET && 205 sat->sat_addr.s_node != ATADDR_ANYNODE) { 206 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 207 return (EADDRNOTAVAIL); 208 hintnet = ddp->ddp_lsat.sat_addr.s_net; 209 } 210 211 ro = &ddp->ddp_route; 212 /* 213 * If we've got an old route for this pcb, check that it is valid. 214 * If we've changed our address, we may have an old "good looking" 215 * route here. Attempt to detect it. 216 */ 217 if (ro->ro_rt) { 218 if (hintnet) 219 net = hintnet; 220 else 221 net = sat->sat_addr.s_net; 222 aa = NULL; 223 if ((ifp = ro->ro_rt->rt_ifp) != NULL) { 224 for (aa = at_ifaddr_list; aa != NULL; 225 aa = aa->aa_next) { 226 if (aa->aa_ifp == ifp && 227 ntohs(net) >= ntohs(aa->aa_firstnet) && 228 ntohs(net) <= ntohs(aa->aa_lastnet)) 229 break; 230 } 231 } 232 if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net != 233 (hintnet ? hintnet : sat->sat_addr.s_net) || 234 satosat(&ro->ro_dst)->sat_addr.s_node != 235 sat->sat_addr.s_node)) { 236 RTFREE(ro->ro_rt); 237 ro->ro_rt = NULL; 238 } 239 } 240 241 /* 242 * If we've got no route for this interface, try to find one. 243 */ 244 if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { 245 ro->ro_dst.sa_len = sizeof(struct sockaddr_at); 246 ro->ro_dst.sa_family = AF_APPLETALK; 247 if (hintnet) 248 satosat(&ro->ro_dst)->sat_addr.s_net = hintnet; 249 else 250 satosat(&ro->ro_dst)->sat_addr.s_net = 251 sat->sat_addr.s_net; 252 satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node; 253 rtalloc(ro); 254 } 255 256 /* 257 * Make sure any route that we have has a valid interface. 258 */ 259 aa = NULL; 260 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) { 261 for (aa = at_ifaddr_list; aa != NULL; aa = aa->aa_next) { 262 if (aa->aa_ifp == ifp) 263 break; 264 } 265 } 266 if (aa == NULL) 267 return (ENETUNREACH); 268 269 ddp->ddp_fsat = *sat; 270 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 271 return (at_pcbsetaddr(ddp, NULL, td)); 272 return (0); 273} 274 275void 276at_pcbdisconnect(struct ddpcb *ddp) 277{ 278 279 DDP_LOCK_ASSERT(ddp); 280 281 ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; 282 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 283 ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; 284} 285 286int 287at_pcballoc(struct socket *so) 288{ 289 struct ddpcb *ddp; 290 291 DDP_LIST_XLOCK_ASSERT(); 292 293 MALLOC(ddp, struct ddpcb *, sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO); 294 if (ddp == NULL) 295 return (ENOBUFS); 296 DDP_LOCK_INIT(ddp); 297 ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; 298 299 ddp->ddp_socket = so; 300 so->so_pcb = (caddr_t)ddp; 301 302 ddp->ddp_next = ddpcb_list; 303 ddp->ddp_prev = NULL; 304 ddp->ddp_pprev = NULL; 305 ddp->ddp_pnext = NULL; 306 if (ddpcb_list != NULL) 307 ddpcb_list->ddp_prev = ddp; 308 ddpcb_list = ddp; 309 return(0); 310} 311 312void 313at_pcbdetach(struct socket *so, struct ddpcb *ddp) 314{ 315 316 /* 317 * We modify ddp, ddp_ports, and the global list. 318 */ 319 DDP_LIST_XLOCK_ASSERT(); 320 DDP_LOCK_ASSERT(ddp); 321 KASSERT(so->so_pcb != NULL, ("at_pcbdetach: so_pcb == NULL")); 322 323 so->so_pcb = NULL; 324 325 /* Remove ddp from ddp_ports list. */ 326 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && 327 ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) { 328 if (ddp->ddp_pprev != NULL) 329 ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; 330 else 331 ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext; 332 if (ddp->ddp_pnext != NULL) 333 ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; 334 } 335 336 if (ddp->ddp_route.ro_rt) 337 RTFREE(ddp->ddp_route.ro_rt); 338 339 if (ddp->ddp_prev) 340 ddp->ddp_prev->ddp_next = ddp->ddp_next; 341 else 342 ddpcb_list = ddp->ddp_next; 343 if (ddp->ddp_next) 344 ddp->ddp_next->ddp_prev = ddp->ddp_prev; 345 DDP_UNLOCK(ddp); 346 DDP_LOCK_DESTROY(ddp); 347 FREE(ddp, M_PCB); 348} 349 350/* 351 * For the moment, this just find the pcb with the correct local address. In 352 * the future, this will actually do some real searching, so we can use the 353 * sender's address to do de-multiplexing on a single port to many sockets 354 * (pcbs). 355 */ 356struct ddpcb * 357ddp_search(struct sockaddr_at *from, struct sockaddr_at *to, 358 struct at_ifaddr *aa) 359{ 360 struct ddpcb *ddp; 361 362 DDP_LIST_SLOCK_ASSERT(); 363 364 /* 365 * Check for bad ports. 366 */ 367 if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) 368 return (NULL); 369 370 /* 371 * Make sure the local address matches the sent address. What about 372 * the interface? 373 */ 374 for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) { 375 DDP_LOCK(ddp); 376 /* XXX should we handle 0.YY? */ 377 /* XXXX.YY to socket on destination interface */ 378 if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && 379 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) { 380 DDP_UNLOCK(ddp); 381 break; 382 } 383 384 /* 0.255 to socket on receiving interface */ 385 if (to->sat_addr.s_node == ATADDR_BCAST && 386 (to->sat_addr.s_net == 0 || 387 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) && 388 ddp->ddp_lsat.sat_addr.s_net == 389 AA_SAT(aa)->sat_addr.s_net) { 390 DDP_UNLOCK(ddp); 391 break; 392 } 393 394 /* XXXX.0 to socket on destination interface */ 395 if (to->sat_addr.s_net == aa->aa_firstnet && 396 to->sat_addr.s_node == 0 && 397 ntohs(ddp->ddp_lsat.sat_addr.s_net) >= 398 ntohs(aa->aa_firstnet) && 399 ntohs(ddp->ddp_lsat.sat_addr.s_net) <= 400 ntohs(aa->aa_lastnet)) { 401 DDP_UNLOCK(ddp); 402 break; 403 } 404 DDP_UNLOCK(ddp); 405 } 406 return (ddp); 407} 408