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 * 50 * $FreeBSD$ 51 */ 52 53#include <sys/param.h> 54#include <sys/systm.h> 55#include <sys/malloc.h> 56#include <sys/mbuf.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 70static u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ 71static u_long ddp_recvspace = 10 * (587 + sizeof(struct sockaddr_at)); 72 73static const struct netisr_handler atalk1_nh = { 74 .nh_name = "atalk1", 75 .nh_handler = at1intr, 76 .nh_proto = NETISR_ATALK1, 77 .nh_policy = NETISR_POLICY_SOURCE, 78}; 79 80static const struct netisr_handler atalk2_nh = { 81 .nh_name = "atalk2", 82 .nh_handler = at2intr, 83 .nh_proto = NETISR_ATALK2, 84 .nh_policy = NETISR_POLICY_SOURCE, 85}; 86 87static const struct netisr_handler aarp_nh = { 88 .nh_name = "aarp", 89 .nh_handler = aarpintr, 90 .nh_proto = NETISR_AARP, 91 .nh_policy = NETISR_POLICY_SOURCE, 92}; 93 94static int 95ddp_attach(struct socket *so, int proto, struct thread *td) 96{ 97 int error = 0; 98 99 KASSERT(sotoddpcb(so) == NULL, ("ddp_attach: ddp != NULL")); 100 101 /* 102 * Allocate socket buffer space first so that it's present 103 * before first use. 104 */ 105 error = soreserve(so, ddp_sendspace, ddp_recvspace); 106 if (error) 107 return (error); 108 109 DDP_LIST_XLOCK(); 110 error = at_pcballoc(so); 111 DDP_LIST_XUNLOCK(); 112 return (error); 113} 114 115static void 116ddp_detach(struct socket *so) 117{ 118 struct ddpcb *ddp; 119 120 ddp = sotoddpcb(so); 121 KASSERT(ddp != NULL, ("ddp_detach: ddp == NULL")); 122 123 DDP_LIST_XLOCK(); 124 DDP_LOCK(ddp); 125 at_pcbdetach(so, ddp); 126 DDP_LIST_XUNLOCK(); 127} 128 129static int 130ddp_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 131{ 132 struct ddpcb *ddp; 133 int error = 0; 134 135 ddp = sotoddpcb(so); 136 KASSERT(ddp != NULL, ("ddp_bind: ddp == NULL")); 137 138 DDP_LIST_XLOCK(); 139 DDP_LOCK(ddp); 140 error = at_pcbsetaddr(ddp, nam, td); 141 DDP_UNLOCK(ddp); 142 DDP_LIST_XUNLOCK(); 143 return (error); 144} 145 146static int 147ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 148{ 149 struct ddpcb *ddp; 150 int error = 0; 151 152 ddp = sotoddpcb(so); 153 KASSERT(ddp != NULL, ("ddp_connect: ddp == NULL")); 154 155 DDP_LIST_XLOCK(); 156 DDP_LOCK(ddp); 157 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 158 DDP_UNLOCK(ddp); 159 DDP_LIST_XUNLOCK(); 160 return (EISCONN); 161 } 162 163 error = at_pcbconnect( ddp, nam, td ); 164 DDP_UNLOCK(ddp); 165 DDP_LIST_XUNLOCK(); 166 if (error == 0) 167 soisconnected(so); 168 return (error); 169} 170 171static int 172ddp_disconnect(struct socket *so) 173{ 174 struct ddpcb *ddp; 175 176 ddp = sotoddpcb(so); 177 KASSERT(ddp != NULL, ("ddp_disconnect: ddp == NULL")); 178 179 DDP_LOCK(ddp); 180 if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) { 181 DDP_UNLOCK(ddp); 182 return (ENOTCONN); 183 } 184 185 at_pcbdisconnect(ddp); 186 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 187 DDP_UNLOCK(ddp); 188 soisdisconnected(so); 189 return (0); 190} 191 192static int 193ddp_shutdown(struct socket *so) 194{ 195 196 KASSERT(sotoddpcb(so) != NULL, ("ddp_shutdown: ddp == NULL")); 197 198 socantsendmore(so); 199 return (0); 200} 201 202static int 203ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 204 struct mbuf *control, struct thread *td) 205{ 206 struct ddpcb *ddp; 207 int error = 0; 208 209 ddp = sotoddpcb(so); 210 KASSERT(ddp != NULL, ("ddp_send: ddp == NULL")); 211 212 if (control && control->m_len) 213 return (EINVAL); 214 215 if (addr != NULL) { 216 DDP_LIST_XLOCK(); 217 DDP_LOCK(ddp); 218 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 219 error = EISCONN; 220 goto out; 221 } 222 223 error = at_pcbconnect(ddp, addr, td); 224 if (error == 0) { 225 error = ddp_output(m, so); 226 at_pcbdisconnect(ddp); 227 } 228out: 229 DDP_UNLOCK(ddp); 230 DDP_LIST_XUNLOCK(); 231 } else { 232 DDP_LOCK(ddp); 233 if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) 234 error = ENOTCONN; 235 else 236 error = ddp_output(m, so); 237 DDP_UNLOCK(ddp); 238 } 239 return (error); 240} 241 242/* 243 * XXXRW: This is never called because we only invoke abort on stream 244 * protocols. 245 */ 246static void 247ddp_abort(struct socket *so) 248{ 249 struct ddpcb *ddp; 250 251 ddp = sotoddpcb(so); 252 KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL")); 253 254 DDP_LOCK(ddp); 255 at_pcbdisconnect(ddp); 256 DDP_UNLOCK(ddp); 257 soisdisconnected(so); 258} 259 260static void 261ddp_close(struct socket *so) 262{ 263 struct ddpcb *ddp; 264 265 ddp = sotoddpcb(so); 266 KASSERT(ddp != NULL, ("ddp_close: ddp == NULL")); 267 268 DDP_LOCK(ddp); 269 at_pcbdisconnect(ddp); 270 DDP_UNLOCK(ddp); 271 soisdisconnected(so); 272} 273 274void 275ddp_init(void) 276{ 277 278 DDP_LIST_LOCK_INIT(); 279 TAILQ_INIT(&at_ifaddrhead); 280 netisr_register(&atalk1_nh); 281 netisr_register(&atalk2_nh); 282 netisr_register(&aarp_nh); 283} 284 285#if 0 286static void 287ddp_clean(void) 288{ 289 struct ddpcp *ddp; 290 291 for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next) 292 at_pcbdetach(ddp->ddp_socket, ddp); 293 DDP_LIST_LOCK_DESTROY(); 294} 295#endif 296 297static int 298at_getpeeraddr(struct socket *so, struct sockaddr **nam) 299{ 300 301 return (EOPNOTSUPP); 302} 303 304static int 305at_getsockaddr(struct socket *so, struct sockaddr **nam) 306{ 307 struct ddpcb *ddp; 308 309 ddp = sotoddpcb(so); 310 KASSERT(ddp != NULL, ("at_getsockaddr: ddp == NULL")); 311 312 DDP_LOCK(ddp); 313 at_sockaddr(ddp, nam); 314 DDP_UNLOCK(ddp); 315 return (0); 316} 317 318struct pr_usrreqs ddp_usrreqs = { 319 .pru_abort = ddp_abort, 320 .pru_attach = ddp_attach, 321 .pru_bind = ddp_bind, 322 .pru_connect = ddp_connect, 323 .pru_control = at_control, 324 .pru_detach = ddp_detach, 325 .pru_disconnect = ddp_disconnect, 326 .pru_peeraddr = at_getpeeraddr, 327 .pru_send = ddp_send, 328 .pru_shutdown = ddp_shutdown, 329 .pru_sockaddr = at_getsockaddr, 330 .pru_close = ddp_close, 331}; 332