ddp_usrreq.c revision 156817
1/*- 2 * Copyright (c) 2004-2005 Robert N. M. Watson 3 * Copyright (c) 1990,1994 Regents of The University of Michigan. 4 * All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and distribute this software and 7 * its documentation for any purpose and without fee is hereby granted, 8 * provided that the above copyright notice appears in all copies and 9 * that both that copyright notice and this permission notice appear 10 * in supporting documentation, and that the name of The University 11 * of Michigan not be used in advertising or publicity pertaining to 12 * distribution of the software without specific, written prior 13 * permission. This software is supplied as is without expressed or 14 * implied warranties of any kind. 15 * 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 19 * Research Systems Unix Group 20 * The University of Michigan 21 * c/o Wesley Craig 22 * 535 W. William Street 23 * Ann Arbor, Michigan 24 * +1-313-764-2278 25 * netatalk@umich.edu 26 * 27 * $FreeBSD: head/sys/netatalk/ddp_usrreq.c 156817 2006-03-17 20:40:17Z rwatson $ 28 */ 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/malloc.h> 33#include <sys/mbuf.h> 34#include <sys/socket.h> 35#include <sys/socketvar.h> 36#include <sys/protosw.h> 37#include <net/if.h> 38#include <net/route.h> 39#include <net/netisr.h> 40 41#include <netatalk/at.h> 42#include <netatalk/at_var.h> 43#include <netatalk/ddp_var.h> 44#include <netatalk/ddp_pcb.h> 45#include <netatalk/at_extern.h> 46 47static u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */ 48static u_long ddp_recvspace = 10 * (587 + sizeof(struct sockaddr_at)); 49 50static struct ifqueue atintrq1, atintrq2, aarpintrq; 51 52static int 53ddp_attach(struct socket *so, int proto, struct thread *td) 54{ 55 struct ddpcb *ddp; 56 int error = 0; 57 58 ddp = sotoddpcb(so); 59 KASSERT(ddp == NULL, ("ddp_attach: ddp != NULL")); 60 61 /* 62 * Allocate socket buffer space first so that it's present 63 * before first use. 64 */ 65 error = soreserve(so, ddp_sendspace, ddp_recvspace); 66 if (error) 67 return (error); 68 69 DDP_LIST_XLOCK(); 70 error = at_pcballoc(so); 71 DDP_LIST_XUNLOCK(); 72 return (error); 73} 74 75static int 76ddp_detach(struct socket *so) 77{ 78 struct ddpcb *ddp; 79 80 ddp = sotoddpcb(so); 81 KASSERT(ddp != NULL, ("ddp_detach: ddp == NULL")); 82 83 DDP_LIST_XLOCK(); 84 DDP_LOCK(ddp); 85 at_pcbdetach(so, ddp); 86 DDP_LIST_XUNLOCK(); 87 return (0); 88} 89 90static int 91ddp_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 92{ 93 struct ddpcb *ddp; 94 int error = 0; 95 96 ddp = sotoddpcb(so); 97 KASSERT(ddp != NULL, ("ddp_bind: ddp == NULL")); 98 DDP_LIST_XLOCK(); 99 DDP_LOCK(ddp); 100 error = at_pcbsetaddr(ddp, nam, td); 101 DDP_UNLOCK(ddp); 102 DDP_LIST_XUNLOCK(); 103 return (error); 104} 105 106static int 107ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 108{ 109 struct ddpcb *ddp; 110 int error = 0; 111 112 ddp = sotoddpcb(so); 113 KASSERT(ddp != NULL, ("ddp_connect: ddp == NULL")); 114 DDP_LIST_XLOCK(); 115 DDP_LOCK(ddp); 116 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 117 DDP_UNLOCK(ddp); 118 DDP_LIST_XUNLOCK(); 119 return (EISCONN); 120 } 121 122 error = at_pcbconnect( ddp, nam, td ); 123 DDP_UNLOCK(ddp); 124 DDP_LIST_XUNLOCK(); 125 if (error == 0) 126 soisconnected(so); 127 return (error); 128} 129 130static int 131ddp_disconnect(struct socket *so) 132{ 133 134 struct ddpcb *ddp; 135 136 ddp = sotoddpcb(so); 137 KASSERT(ddp != NULL, ("ddp_disconnect: ddp == NULL")); 138 DDP_LOCK(ddp); 139 if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) { 140 DDP_UNLOCK(ddp); 141 return (ENOTCONN); 142 } 143 144 at_pcbdisconnect(ddp); 145 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 146 DDP_UNLOCK(ddp); 147 soisdisconnected(so); 148 return (0); 149} 150 151static int 152ddp_shutdown(struct socket *so) 153{ 154 struct ddpcb *ddp; 155 156 ddp = sotoddpcb(so); 157 KASSERT(ddp != NULL, ("ddp_shutdown: ddp == NULL")); 158 socantsendmore(so); 159 return (0); 160} 161 162static int 163ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 164 struct mbuf *control, struct thread *td) 165{ 166 struct ddpcb *ddp; 167 int error = 0; 168 169 ddp = sotoddpcb(so); 170 KASSERT(ddp != NULL, ("ddp_send: ddp == NULL")); 171 172 if (control && control->m_len) { 173 return (EINVAL); 174 } 175 176 if (addr != NULL) { 177 DDP_LIST_XLOCK(); 178 DDP_LOCK(ddp); 179 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 180 error = EISCONN; 181 goto out; 182 } 183 184 error = at_pcbconnect(ddp, addr, td); 185 if (error == 0) { 186 error = ddp_output(m, so); 187 at_pcbdisconnect(ddp); 188 } 189out: 190 DDP_UNLOCK(ddp); 191 DDP_LIST_XUNLOCK(); 192 } else { 193 DDP_LOCK(ddp); 194 if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) 195 error = ENOTCONN; 196 else 197 error = ddp_output(m, so); 198 DDP_UNLOCK(ddp); 199 } 200 return (error); 201} 202 203static int 204ddp_abort(struct socket *so) 205{ 206 struct ddpcb *ddp; 207 208 ddp = sotoddpcb(so); 209 KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL")); 210 DDP_LIST_XLOCK(); 211 DDP_LOCK(ddp); 212 at_pcbdetach(so, ddp); 213 DDP_LIST_XUNLOCK(); 214 /* XXXRW: Should be calling sotryfree() here? */ 215 return (0); 216} 217 218void 219ddp_init(void) 220{ 221 atintrq1.ifq_maxlen = IFQ_MAXLEN; 222 atintrq2.ifq_maxlen = IFQ_MAXLEN; 223 aarpintrq.ifq_maxlen = IFQ_MAXLEN; 224 mtx_init(&atintrq1.ifq_mtx, "at1_inq", NULL, MTX_DEF); 225 mtx_init(&atintrq2.ifq_mtx, "at2_inq", NULL, MTX_DEF); 226 mtx_init(&aarpintrq.ifq_mtx, "aarp_inq", NULL, MTX_DEF); 227 DDP_LIST_LOCK_INIT(); 228 netisr_register(NETISR_ATALK1, at1intr, &atintrq1, NETISR_MPSAFE); 229 netisr_register(NETISR_ATALK2, at2intr, &atintrq2, NETISR_MPSAFE); 230 netisr_register(NETISR_AARP, aarpintr, &aarpintrq, NETISR_MPSAFE); 231} 232 233#if 0 234static void 235ddp_clean(void) 236{ 237 struct ddpcb *ddp; 238 239 for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next) { 240 at_pcbdetach(ddp->ddp_socket, ddp); 241 } 242 DDP_LIST_LOCK_DESTROY(); 243} 244#endif 245 246static int 247at_setpeeraddr(struct socket *so, struct sockaddr **nam) 248{ 249 return (EOPNOTSUPP); 250} 251 252static int 253at_setsockaddr(struct socket *so, struct sockaddr **nam) 254{ 255 struct ddpcb *ddp; 256 257 ddp = sotoddpcb(so); 258 if (ddp == NULL) { 259 return (EINVAL); 260 } 261 DDP_LOCK(ddp); 262 at_sockaddr(ddp, nam); 263 DDP_UNLOCK(ddp); 264 return (0); 265} 266 267struct pr_usrreqs ddp_usrreqs = { 268 .pru_abort = ddp_abort, 269 .pru_attach = ddp_attach, 270 .pru_bind = ddp_bind, 271 .pru_connect = ddp_connect, 272 .pru_control = at_control, 273 .pru_detach = ddp_detach, 274 .pru_disconnect = ddp_disconnect, 275 .pru_peeraddr = at_setpeeraddr, 276 .pru_send = ddp_send, 277 .pru_shutdown = ddp_shutdown, 278 .pru_sockaddr = at_setsockaddr, 279}; 280