1/*- 2 * Copyright (c) 2004-2009 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * 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$ 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 aa = NULL; 108 if (addr != NULL) { 109 sat = (struct sockaddr_at *)addr; 110 if (sat->sat_family != AF_APPLETALK) 111 return (EAFNOSUPPORT); 112 113 if (sat->sat_addr.s_node != ATADDR_ANYNODE || 114 sat->sat_addr.s_net != ATADDR_ANYNET) { 115 AT_IFADDR_RLOCK(); 116 TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 117 if ((sat->sat_addr.s_net == 118 AA_SAT(aa)->sat_addr.s_net) && 119 (sat->sat_addr.s_node == 120 AA_SAT(aa)->sat_addr.s_node)) 121 break; 122 } 123 AT_IFADDR_RUNLOCK(); 124 if (aa == NULL) 125 return (EADDRNOTAVAIL); 126 } 127 128 if (sat->sat_port != ATADDR_ANYPORT) { 129 if (sat->sat_port < ATPORT_FIRST || 130 sat->sat_port >= ATPORT_LAST) 131 return (EINVAL); 132 if (sat->sat_port < ATPORT_RESERVED && 133 priv_check(td, PRIV_NETATALK_RESERVEDPORT)) 134 return (EACCES); 135 } 136 } else { 137 bzero((caddr_t)&lsat, sizeof(struct sockaddr_at)); 138 lsat.sat_len = sizeof(struct sockaddr_at); 139 lsat.sat_addr.s_node = ATADDR_ANYNODE; 140 lsat.sat_addr.s_net = ATADDR_ANYNET; 141 lsat.sat_family = AF_APPLETALK; 142 sat = &lsat; 143 } 144 145 if (sat->sat_addr.s_node == ATADDR_ANYNODE && 146 sat->sat_addr.s_net == ATADDR_ANYNET) { 147 AT_IFADDR_RLOCK(); 148 if (TAILQ_EMPTY(&at_ifaddrhead)) { 149 AT_IFADDR_RUNLOCK(); 150 return (EADDRNOTAVAIL); 151 } 152 sat->sat_addr = AA_SAT(TAILQ_FIRST(&at_ifaddrhead))->sat_addr; 153 AT_IFADDR_RUNLOCK(); 154 } 155 ddp->ddp_lsat = *sat; 156 157 /* 158 * Choose port. 159 */ 160 if (sat->sat_port == ATADDR_ANYPORT) { 161 for (sat->sat_port = ATPORT_RESERVED; 162 sat->sat_port < ATPORT_LAST; sat->sat_port++) { 163 if (ddp_ports[sat->sat_port - 1] == NULL) 164 break; 165 } 166 if (sat->sat_port == ATPORT_LAST) 167 return (EADDRNOTAVAIL); 168 ddp->ddp_lsat.sat_port = sat->sat_port; 169 ddp_ports[sat->sat_port - 1] = ddp; 170 } else { 171 for (ddpp = ddp_ports[sat->sat_port - 1]; ddpp; 172 ddpp = ddpp->ddp_pnext) { 173 if (ddpp->ddp_lsat.sat_addr.s_net == 174 sat->sat_addr.s_net && 175 ddpp->ddp_lsat.sat_addr.s_node == 176 sat->sat_addr.s_node) 177 break; 178 } 179 if (ddpp != NULL) 180 return (EADDRINUSE); 181 ddp->ddp_pnext = ddp_ports[sat->sat_port - 1]; 182 ddp_ports[sat->sat_port - 1] = ddp; 183 if (ddp->ddp_pnext != NULL) 184 ddp->ddp_pnext->ddp_pprev = ddp; 185 } 186 187 return (0); 188} 189 190int 191at_pcbconnect(struct ddpcb *ddp, struct sockaddr *addr, struct thread *td) 192{ 193 struct sockaddr_at *sat = (struct sockaddr_at *)addr; 194 struct route *ro; 195 struct at_ifaddr *aa = NULL; 196 struct ifnet *ifp; 197 u_short hintnet = 0, net; 198 199 DDP_LIST_XLOCK_ASSERT(); 200 DDP_LOCK_ASSERT(ddp); 201 202 if (sat->sat_family != AF_APPLETALK) 203 return (EAFNOSUPPORT); 204 205 /* 206 * Under phase 2, network 0 means "the network". We take "the 207 * network" to mean the network the control block is bound to. If 208 * the control block is not bound, there is an error. 209 */ 210 if (sat->sat_addr.s_net == ATADDR_ANYNET && 211 sat->sat_addr.s_node != ATADDR_ANYNODE) { 212 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 213 return (EADDRNOTAVAIL); 214 hintnet = ddp->ddp_lsat.sat_addr.s_net; 215 } 216 217 ro = &ddp->ddp_route; 218 /* 219 * If we've got an old route for this pcb, check that it is valid. 220 * If we've changed our address, we may have an old "good looking" 221 * route here. Attempt to detect it. 222 */ 223 if (ro->ro_rt) { 224 if (hintnet) 225 net = hintnet; 226 else 227 net = sat->sat_addr.s_net; 228 aa = NULL; 229 AT_IFADDR_RLOCK(); 230 if ((ifp = ro->ro_rt->rt_ifp) != NULL) { 231 TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 232 if (aa->aa_ifp == ifp && 233 ntohs(net) >= ntohs(aa->aa_firstnet) && 234 ntohs(net) <= ntohs(aa->aa_lastnet)) 235 break; 236 } 237 } 238 if (aa == NULL || (satosat(&ro->ro_dst)->sat_addr.s_net != 239 (hintnet ? hintnet : sat->sat_addr.s_net) || 240 satosat(&ro->ro_dst)->sat_addr.s_node != 241 sat->sat_addr.s_node)) { 242 RTFREE(ro->ro_rt); 243 ro->ro_rt = NULL; 244 } 245 AT_IFADDR_RUNLOCK(); 246 } 247 248 /* 249 * If we've got no route for this interface, try to find one. 250 */ 251 if (ro->ro_rt == NULL || ro->ro_rt->rt_ifp == NULL) { 252 ro->ro_dst.sa_len = sizeof(struct sockaddr_at); 253 ro->ro_dst.sa_family = AF_APPLETALK; 254 if (hintnet) 255 satosat(&ro->ro_dst)->sat_addr.s_net = hintnet; 256 else 257 satosat(&ro->ro_dst)->sat_addr.s_net = 258 sat->sat_addr.s_net; 259 satosat(&ro->ro_dst)->sat_addr.s_node = sat->sat_addr.s_node; 260 rtalloc(ro); 261 } 262 263 /* 264 * Make sure any route that we have has a valid interface. 265 */ 266 aa = NULL; 267 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp)) { 268 AT_IFADDR_RLOCK(); 269 TAILQ_FOREACH(aa, &at_ifaddrhead, aa_link) { 270 if (aa->aa_ifp == ifp) 271 break; 272 } 273 AT_IFADDR_RUNLOCK(); 274 } 275 if (aa == NULL) 276 return (ENETUNREACH); 277 278 ddp->ddp_fsat = *sat; 279 if (ddp->ddp_lsat.sat_port == ATADDR_ANYPORT) 280 return (at_pcbsetaddr(ddp, NULL, td)); 281 return (0); 282} 283 284void 285at_pcbdisconnect(struct ddpcb *ddp) 286{ 287 288 DDP_LOCK_ASSERT(ddp); 289 290 ddp->ddp_fsat.sat_addr.s_net = ATADDR_ANYNET; 291 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 292 ddp->ddp_fsat.sat_port = ATADDR_ANYPORT; 293} 294 295int 296at_pcballoc(struct socket *so) 297{ 298 struct ddpcb *ddp; 299 300 DDP_LIST_XLOCK_ASSERT(); 301 302 ddp = malloc(sizeof *ddp, M_PCB, M_NOWAIT | M_ZERO); 303 if (ddp == NULL) 304 return (ENOBUFS); 305 DDP_LOCK_INIT(ddp); 306 ddp->ddp_lsat.sat_port = ATADDR_ANYPORT; 307 308 ddp->ddp_socket = so; 309 so->so_pcb = (caddr_t)ddp; 310 311 ddp->ddp_next = ddpcb_list; 312 ddp->ddp_prev = NULL; 313 ddp->ddp_pprev = NULL; 314 ddp->ddp_pnext = NULL; 315 if (ddpcb_list != NULL) 316 ddpcb_list->ddp_prev = ddp; 317 ddpcb_list = ddp; 318 return(0); 319} 320 321void 322at_pcbdetach(struct socket *so, struct ddpcb *ddp) 323{ 324 325 /* 326 * We modify ddp, ddp_ports, and the global list. 327 */ 328 DDP_LIST_XLOCK_ASSERT(); 329 DDP_LOCK_ASSERT(ddp); 330 KASSERT(so->so_pcb != NULL, ("at_pcbdetach: so_pcb == NULL")); 331 332 so->so_pcb = NULL; 333 334 /* Remove ddp from ddp_ports list. */ 335 if (ddp->ddp_lsat.sat_port != ATADDR_ANYPORT && 336 ddp_ports[ddp->ddp_lsat.sat_port - 1] != NULL) { 337 if (ddp->ddp_pprev != NULL) 338 ddp->ddp_pprev->ddp_pnext = ddp->ddp_pnext; 339 else 340 ddp_ports[ddp->ddp_lsat.sat_port - 1] = ddp->ddp_pnext; 341 if (ddp->ddp_pnext != NULL) 342 ddp->ddp_pnext->ddp_pprev = ddp->ddp_pprev; 343 } 344 345 if (ddp->ddp_route.ro_rt) 346 RTFREE(ddp->ddp_route.ro_rt); 347 348 if (ddp->ddp_prev) 349 ddp->ddp_prev->ddp_next = ddp->ddp_next; 350 else 351 ddpcb_list = ddp->ddp_next; 352 if (ddp->ddp_next) 353 ddp->ddp_next->ddp_prev = ddp->ddp_prev; 354 DDP_UNLOCK(ddp); 355 DDP_LOCK_DESTROY(ddp); 356 free(ddp, M_PCB); 357} 358 359/* 360 * For the moment, this just find the pcb with the correct local address. In 361 * the future, this will actually do some real searching, so we can use the 362 * sender's address to do de-multiplexing on a single port to many sockets 363 * (pcbs). 364 */ 365struct ddpcb * 366ddp_search(struct sockaddr_at *from, struct sockaddr_at *to, 367 struct at_ifaddr *aa) 368{ 369 struct ddpcb *ddp; 370 371 DDP_LIST_SLOCK_ASSERT(); 372 373 /* 374 * Check for bad ports. 375 */ 376 if (to->sat_port < ATPORT_FIRST || to->sat_port >= ATPORT_LAST) 377 return (NULL); 378 379 /* 380 * Make sure the local address matches the sent address. What about 381 * the interface? 382 */ 383 for (ddp = ddp_ports[to->sat_port - 1]; ddp; ddp = ddp->ddp_pnext) { 384 DDP_LOCK(ddp); 385 /* XXX should we handle 0.YY? */ 386 /* XXXX.YY to socket on destination interface */ 387 if (to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net && 388 to->sat_addr.s_node == ddp->ddp_lsat.sat_addr.s_node) { 389 DDP_UNLOCK(ddp); 390 break; 391 } 392 393 /* 0.255 to socket on receiving interface */ 394 if (to->sat_addr.s_node == ATADDR_BCAST && 395 (to->sat_addr.s_net == 0 || 396 to->sat_addr.s_net == ddp->ddp_lsat.sat_addr.s_net) && 397 ddp->ddp_lsat.sat_addr.s_net == 398 AA_SAT(aa)->sat_addr.s_net) { 399 DDP_UNLOCK(ddp); 400 break; 401 } 402 403 /* XXXX.0 to socket on destination interface */ 404 if (to->sat_addr.s_net == aa->aa_firstnet && 405 to->sat_addr.s_node == 0 && 406 ntohs(ddp->ddp_lsat.sat_addr.s_net) >= 407 ntohs(aa->aa_firstnet) && 408 ntohs(ddp->ddp_lsat.sat_addr.s_net) <= 409 ntohs(aa->aa_lastnet)) { 410 DDP_UNLOCK(ddp); 411 break; 412 } 413 DDP_UNLOCK(ddp); 414 } 415 return (ddp); 416} 417