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: releng/6.0/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
47 static u_long ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */
48 static u_long ddp_recvspace = 10 * (587 + sizeof(struct sockaddr_at));
49
50 static struct ifqueue atintrq1, atintrq2, aarpintrq;
51
52 static int
53 ddp_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
76 static int
77 ddp_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
92 static int
93 ddp_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
110 static int
111 ddp_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
137 static int
138 ddp_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
160 static int
161 ddp_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
173 static int
174 ddp_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 }
202 out:
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
216 static int
217 ddp_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
232 void
233 ddp_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
248 static void
249 ddp_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
260 static int
261 at_setpeeraddr(struct socket *so, struct sockaddr **nam)
262 {
263 return (EOPNOTSUPP);
264 }
265
266 static int
267 at_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
281 struct 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 };
Cache object: 17b9fe27bee2862fbf38a3caeae03b8e
|