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