ddp_usrreq.c revision 160549
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 160549 2006-07-21 17:11:15Z 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 void 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} 88 89static int 90ddp_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 91{ 92 struct ddpcb *ddp; 93 int error = 0; 94 95 ddp = sotoddpcb(so); 96 KASSERT(ddp != NULL, ("ddp_bind: ddp == NULL")); 97 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 115 DDP_LIST_XLOCK(); 116 DDP_LOCK(ddp); 117 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 118 DDP_UNLOCK(ddp); 119 DDP_LIST_XUNLOCK(); 120 return (EISCONN); 121 } 122 123 error = at_pcbconnect( ddp, nam, td ); 124 DDP_UNLOCK(ddp); 125 DDP_LIST_XUNLOCK(); 126 if (error == 0) 127 soisconnected(so); 128 return (error); 129} 130 131static int 132ddp_disconnect(struct socket *so) 133{ 134 135 struct ddpcb *ddp; 136 137 ddp = sotoddpcb(so); 138 KASSERT(ddp != NULL, ("ddp_disconnect: ddp == NULL")); 139 140 DDP_LOCK(ddp); 141 if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) { 142 DDP_UNLOCK(ddp); 143 return (ENOTCONN); 144 } 145 146 at_pcbdisconnect(ddp); 147 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 148 DDP_UNLOCK(ddp); 149 soisdisconnected(so); 150 return (0); 151} 152 153static int 154ddp_shutdown(struct socket *so) 155{ 156 struct ddpcb *ddp; 157 158 ddp = sotoddpcb(so); 159 KASSERT(ddp != NULL, ("ddp_shutdown: ddp == NULL")); 160 161 socantsendmore(so); 162 return (0); 163} 164 165static int 166ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 167 struct mbuf *control, struct thread *td) 168{ 169 struct ddpcb *ddp; 170 int error = 0; 171 172 ddp = sotoddpcb(so); 173 KASSERT(ddp != NULL, ("ddp_send: ddp == NULL")); 174 175 if (control && control->m_len) 176 return (EINVAL); 177 178 if (addr != NULL) { 179 DDP_LIST_XLOCK(); 180 DDP_LOCK(ddp); 181 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 182 error = EISCONN; 183 goto out; 184 } 185 186 error = at_pcbconnect(ddp, addr, td); 187 if (error == 0) { 188 error = ddp_output(m, so); 189 at_pcbdisconnect(ddp); 190 } 191out: 192 DDP_UNLOCK(ddp); 193 DDP_LIST_XUNLOCK(); 194 } else { 195 DDP_LOCK(ddp); 196 if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) 197 error = ENOTCONN; 198 else 199 error = ddp_output(m, so); 200 DDP_UNLOCK(ddp); 201 } 202 return (error); 203} 204 205/* 206 * XXXRW: This is never called because we only invoke abort on stream 207 * protocols. 208 */ 209static void 210ddp_abort(struct socket *so) 211{ 212 struct ddpcb *ddp; 213 214 ddp = sotoddpcb(so); 215 KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL")); 216 217 DDP_LOCK(ddp); 218 at_pcbdisconnect(ddp); 219 DDP_UNLOCK(ddp); 220} 221 222static void 223ddp_close(struct socket *so) 224{ 225 struct ddpcb *ddp; 226 227 ddp = sotoddpcb(so); 228 KASSERT(ddp != NULL, ("ddp_close: ddp == NULL")); 229 230 DDP_LOCK(ddp); 231 at_pcbdisconnect(ddp); 232 DDP_UNLOCK(ddp); 233} 234 235void 236ddp_init(void) 237{ 238 atintrq1.ifq_maxlen = IFQ_MAXLEN; 239 atintrq2.ifq_maxlen = IFQ_MAXLEN; 240 aarpintrq.ifq_maxlen = IFQ_MAXLEN; 241 mtx_init(&atintrq1.ifq_mtx, "at1_inq", NULL, MTX_DEF); 242 mtx_init(&atintrq2.ifq_mtx, "at2_inq", NULL, MTX_DEF); 243 mtx_init(&aarpintrq.ifq_mtx, "aarp_inq", NULL, MTX_DEF); 244 DDP_LIST_LOCK_INIT(); 245 netisr_register(NETISR_ATALK1, at1intr, &atintrq1, NETISR_MPSAFE); 246 netisr_register(NETISR_ATALK2, at2intr, &atintrq2, NETISR_MPSAFE); 247 netisr_register(NETISR_AARP, aarpintr, &aarpintrq, NETISR_MPSAFE); 248} 249 250#if 0 251static void 252ddp_clean(void) 253{ 254 struct ddpcb *ddp; 255 256 for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next) { 257 at_pcbdetach(ddp->ddp_socket, ddp); 258 } 259 DDP_LIST_LOCK_DESTROY(); 260} 261#endif 262 263static int 264at_setpeeraddr(struct socket *so, struct sockaddr **nam) 265{ 266 return (EOPNOTSUPP); 267} 268 269static int 270at_setsockaddr(struct socket *so, struct sockaddr **nam) 271{ 272 struct ddpcb *ddp; 273 274 ddp = sotoddpcb(so); 275 KASSERT(ddp != NULL, ("at_setsockaddr: ddp == NULL")); 276 277 DDP_LOCK(ddp); 278 at_sockaddr(ddp, nam); 279 DDP_UNLOCK(ddp); 280 return (0); 281} 282 283struct pr_usrreqs ddp_usrreqs = { 284 .pru_abort = ddp_abort, 285 .pru_attach = ddp_attach, 286 .pru_bind = ddp_bind, 287 .pru_connect = ddp_connect, 288 .pru_control = at_control, 289 .pru_detach = ddp_detach, 290 .pru_disconnect = ddp_disconnect, 291 .pru_peeraddr = at_setpeeraddr, 292 .pru_send = ddp_send, 293 .pru_shutdown = ddp_shutdown, 294 .pru_sockaddr = at_setsockaddr, 295 .pru_close = ddp_close, 296}; 297