ddp_usrreq.c revision 157370
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 157370 2006-04-01 15:42:02Z 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 DDP_LIST_XLOCK(); 98 DDP_LOCK(ddp); 99 error = at_pcbsetaddr(ddp, nam, td); 100 DDP_UNLOCK(ddp); 101 DDP_LIST_XUNLOCK(); 102 return (error); 103} 104 105static int 106ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 107{ 108 struct ddpcb *ddp; 109 int error = 0; 110 111 ddp = sotoddpcb(so); 112 KASSERT(ddp != NULL, ("ddp_connect: ddp == NULL")); 113 DDP_LIST_XLOCK(); 114 DDP_LOCK(ddp); 115 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 116 DDP_UNLOCK(ddp); 117 DDP_LIST_XUNLOCK(); 118 return (EISCONN); 119 } 120 121 error = at_pcbconnect( ddp, nam, td ); 122 DDP_UNLOCK(ddp); 123 DDP_LIST_XUNLOCK(); 124 if (error == 0) 125 soisconnected(so); 126 return (error); 127} 128 129static int 130ddp_disconnect(struct socket *so) 131{ 132 133 struct ddpcb *ddp; 134 135 ddp = sotoddpcb(so); 136 KASSERT(ddp != NULL, ("ddp_disconnect: ddp == NULL")); 137 DDP_LOCK(ddp); 138 if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) { 139 DDP_UNLOCK(ddp); 140 return (ENOTCONN); 141 } 142 143 at_pcbdisconnect(ddp); 144 ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE; 145 DDP_UNLOCK(ddp); 146 soisdisconnected(so); 147 return (0); 148} 149 150static int 151ddp_shutdown(struct socket *so) 152{ 153 struct ddpcb *ddp; 154 155 ddp = sotoddpcb(so); 156 KASSERT(ddp != NULL, ("ddp_shutdown: ddp == NULL")); 157 socantsendmore(so); 158 return (0); 159} 160 161static int 162ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, 163 struct mbuf *control, struct thread *td) 164{ 165 struct ddpcb *ddp; 166 int error = 0; 167 168 ddp = sotoddpcb(so); 169 KASSERT(ddp != NULL, ("ddp_send: ddp == NULL")); 170 171 if (control && control->m_len) { 172 return (EINVAL); 173 } 174 175 if (addr != NULL) { 176 DDP_LIST_XLOCK(); 177 DDP_LOCK(ddp); 178 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) { 179 error = EISCONN; 180 goto out; 181 } 182 183 error = at_pcbconnect(ddp, addr, td); 184 if (error == 0) { 185 error = ddp_output(m, so); 186 at_pcbdisconnect(ddp); 187 } 188out: 189 DDP_UNLOCK(ddp); 190 DDP_LIST_XUNLOCK(); 191 } else { 192 DDP_LOCK(ddp); 193 if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT) 194 error = ENOTCONN; 195 else 196 error = ddp_output(m, so); 197 DDP_UNLOCK(ddp); 198 } 199 return (error); 200} 201 202static void 203ddp_abort(struct socket *so) 204{ 205 struct ddpcb *ddp; 206 207 ddp = sotoddpcb(so); 208 KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL")); 209 DDP_LIST_XLOCK(); 210 DDP_LOCK(ddp); 211 at_pcbdetach(so, ddp); 212 DDP_LIST_XUNLOCK(); 213} 214 215void 216ddp_init(void) 217{ 218 atintrq1.ifq_maxlen = IFQ_MAXLEN; 219 atintrq2.ifq_maxlen = IFQ_MAXLEN; 220 aarpintrq.ifq_maxlen = IFQ_MAXLEN; 221 mtx_init(&atintrq1.ifq_mtx, "at1_inq", NULL, MTX_DEF); 222 mtx_init(&atintrq2.ifq_mtx, "at2_inq", NULL, MTX_DEF); 223 mtx_init(&aarpintrq.ifq_mtx, "aarp_inq", NULL, MTX_DEF); 224 DDP_LIST_LOCK_INIT(); 225 netisr_register(NETISR_ATALK1, at1intr, &atintrq1, NETISR_MPSAFE); 226 netisr_register(NETISR_ATALK2, at2intr, &atintrq2, NETISR_MPSAFE); 227 netisr_register(NETISR_AARP, aarpintr, &aarpintrq, NETISR_MPSAFE); 228} 229 230#if 0 231static void 232ddp_clean(void) 233{ 234 struct ddpcb *ddp; 235 236 for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next) { 237 at_pcbdetach(ddp->ddp_socket, ddp); 238 } 239 DDP_LIST_LOCK_DESTROY(); 240} 241#endif 242 243static int 244at_setpeeraddr(struct socket *so, struct sockaddr **nam) 245{ 246 return (EOPNOTSUPP); 247} 248 249static int 250at_setsockaddr(struct socket *so, struct sockaddr **nam) 251{ 252 struct ddpcb *ddp; 253 254 ddp = sotoddpcb(so); 255 KASSERT(ddp != NULL, ("at_setsockaddr: ddp == NULL")); 256 257 DDP_LOCK(ddp); 258 at_sockaddr(ddp, nam); 259 DDP_UNLOCK(ddp); 260 return (0); 261} 262 263struct pr_usrreqs ddp_usrreqs = { 264 .pru_abort = ddp_abort, 265 .pru_attach = ddp_attach, 266 .pru_bind = ddp_bind, 267 .pru_connect = ddp_connect, 268 .pru_control = at_control, 269 .pru_detach = ddp_detach, 270 .pru_disconnect = ddp_disconnect, 271 .pru_peeraddr = at_setpeeraddr, 272 .pru_send = ddp_send, 273 .pru_shutdown = ddp_shutdown, 274 .pru_sockaddr = at_setsockaddr, 275}; 276