ddp_usrreq.c revision 142041
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 142041 2005-02-18 10:53:00Z 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 if (ddp != NULL) 60 return (EINVAL); 61 62 /* 63 * Allocate socket buffer space first so that it's present 64 * before first use. 65 */ 66 error = soreserve(so, ddp_sendspace, ddp_recvspace); 67 if (error) 68 return (error); 69 70 DDP_LIST_XLOCK(); 71 error = at_pcballoc(so); 72 DDP_LIST_XUNLOCK(); 73 return (error); 74} 75 76static int 77ddp_detach(struct socket *so) 78{ 79 struct ddpcb *ddp; 80 81 ddp = sotoddpcb(so); 82 if (ddp == NULL) 83 return (EINVAL); 84 85 DDP_LIST_XLOCK(); 86 DDP_LOCK(ddp); 87 at_pcbdetach(so, ddp); 88 DDP_LIST_XUNLOCK(); 89 return (0); 90} 91 92static int 93ddp_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 94{ 95 struct ddpcb *ddp; 96 int error = 0; 97 98 ddp = sotoddpcb(so); 99 if (ddp == NULL) { 100 return (EINVAL); 101 } 102 DDP_LIST_XLOCK(); 103 DDP_LOCK(ddp); 104 error = at_pcbsetaddr(ddp, nam, td); 105 DDP_UNLOCK(ddp); 106 DDP_LIST_XUNLOCK(); 107 return (error); 108} 109 110static int 111ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 112{ 113 struct ddpcb *ddp; 114 int error = 0; 115 116 ddp = sotoddpcb(so); 117 if (ddp == NULL) { 118 return (EINVAL); 119 } 120 121 DDP_LIST_XLOCK(); 122 DDP_LOCK(ddp); 123 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 124 DDP_UNLOCK(ddp); 125 DDP_LIST_XUNLOCK(); 126 return (EISCONN); 127 } 128 129 error = at_pcbconnect( ddp, nam, td ); 130 DDP_UNLOCK(ddp); 131 DDP_LIST_XUNLOCK(); 132 if (error == 0) 133 soisconnected(so); 134 return (error); 135} 136 137static int 138ddp_disconnect(struct socket *so) 139{ 140 141 struct ddpcb *ddp; 142 143 ddp = sotoddpcb(so); 144 if (ddp == NULL) { 145 return (EINVAL); 146 } 147 DDP_LOCK(ddp); 148 if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) { 149 DDP_UNLOCK(ddp); 150 return (ENOTCONN); 151 } 152 153 at_pcbdisconnect(ddp); 154 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 155 DDP_UNLOCK(ddp); 156 soisdisconnected(so); 157 return (0); 158} 159 160static int 161ddp_shutdown(struct socket *so) 162{ 163 struct ddpcb *ddp; 164 165 ddp = sotoddpcb(so); 166 if (ddp == NULL) { 167 return (EINVAL); 168 } 169 socantsendmore(so); 170 return (0); 171} 172 173static int 174ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 175 struct mbuf *control, struct thread *td) 176{ 177 struct ddpcb *ddp; 178 int error = 0; 179 180 ddp = sotoddpcb(so); 181 if (ddp == NULL) { 182 return (EINVAL); 183 } 184 185 if (control && control->m_len) { 186 return (EINVAL); 187 } 188 189 if (addr != NULL) { 190 DDP_LIST_XLOCK(); 191 DDP_LOCK(ddp); 192 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 193 error = EISCONN; 194 goto out; 195 } 196 197 error = at_pcbconnect(ddp, addr, td); 198 if (error == 0) { 199 error = ddp_output(m, so); 200 at_pcbdisconnect(ddp); 201 } 202out: 203 DDP_UNLOCK(ddp); 204 DDP_LIST_XUNLOCK(); 205 } else { 206 DDP_LOCK(ddp); 207 if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) 208 error = ENOTCONN; 209 else 210 error = ddp_output(m, so); 211 DDP_UNLOCK(ddp); 212 } 213 return (error); 214} 215 216static int 217ddp_abort(struct socket *so) 218{ 219 struct ddpcb *ddp; 220 221 ddp = sotoddpcb(so); 222 if (ddp == NULL) { 223 return (EINVAL); 224 } 225 DDP_LIST_XLOCK(); 226 DDP_LOCK(ddp); 227 at_pcbdetach(so, ddp); 228 DDP_LIST_XUNLOCK(); 229 return (0); 230} 231 232void 233ddp_init(void) 234{ 235 atintrq1.ifq_maxlen = IFQ_MAXLEN; 236 atintrq2.ifq_maxlen = IFQ_MAXLEN; 237 aarpintrq.ifq_maxlen = IFQ_MAXLEN; 238 mtx_init(&atintrq1.ifq_mtx, "at1_inq", NULL, MTX_DEF); 239 mtx_init(&atintrq2.ifq_mtx, "at2_inq", NULL, MTX_DEF); 240 mtx_init(&aarpintrq.ifq_mtx, "aarp_inq", NULL, MTX_DEF); 241 DDP_LIST_LOCK_INIT(); 242 netisr_register(NETISR_ATALK1, at1intr, &atintrq1, NETISR_MPSAFE); 243 netisr_register(NETISR_ATALK2, at2intr, &atintrq2, NETISR_MPSAFE); 244 netisr_register(NETISR_AARP, aarpintr, &aarpintrq, NETISR_MPSAFE); 245} 246 247#if 0 248static void 249ddp_clean(void) 250{ 251 struct ddpcb *ddp; 252 253 for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next) { 254 at_pcbdetach(ddp->ddp_socket, ddp); 255 } 256 DDP_LIST_LOCK_DESTROY(); 257} 258#endif 259 260static int 261at_setpeeraddr(struct socket *so, struct sockaddr **nam) 262{ 263 return (EOPNOTSUPP); 264} 265 266static int 267at_setsockaddr(struct socket *so, struct sockaddr **nam) 268{ 269 struct ddpcb *ddp; 270 271 ddp = sotoddpcb(so); 272 if (ddp == NULL) { 273 return (EINVAL); 274 } 275 DDP_LOCK(ddp); 276 at_sockaddr(ddp, nam); 277 DDP_UNLOCK(ddp); 278 return (0); 279} 280 281struct pr_usrreqs ddp_usrreqs = { 282 .pru_abort = ddp_abort, 283 .pru_attach = ddp_attach, 284 .pru_bind = ddp_bind, 285 .pru_connect = ddp_connect, 286 .pru_control = at_control, 287 .pru_detach = ddp_detach, 288 .pru_disconnect = ddp_disconnect, 289 .pru_peeraddr = at_setpeeraddr, 290 .pru_send = ddp_send, 291 .pru_shutdown = ddp_shutdown, 292 .pru_sockaddr = at_setsockaddr, 293}; 294