]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/netatalk/ddp_usrreq.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / netatalk / ddp_usrreq.c
1 /*-
2  * Copyright (c) 2004-2009 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * Copyright (c) 1990, 1994 Regents of The University of Michigan.
27  * All Rights Reserved.
28  *
29  * Permission to use, copy, modify, and distribute this software and
30  * its documentation for any purpose and without fee is hereby granted,
31  * provided that the above copyright notice appears in all copies and
32  * that both that copyright notice and this permission notice appear
33  * in supporting documentation, and that the name of The University
34  * of Michigan not be used in advertising or publicity pertaining to
35  * distribution of the software without specific, written prior
36  * permission. This software is supplied as is without expressed or
37  * implied warranties of any kind.
38  *
39  * This product includes software developed by the University of
40  * California, Berkeley and its contributors.
41  *
42  *      Research Systems Unix Group
43  *      The University of Michigan
44  *      c/o Wesley Craig
45  *      535 W. William Street
46  *      Ann Arbor, Michigan
47  *      +1-313-764-2278
48  *      netatalk@umich.edu
49  *
50  * $FreeBSD$
51  */
52
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/malloc.h>
56 #include <sys/mbuf.h>
57 #include <sys/socket.h>
58 #include <sys/socketvar.h>
59 #include <sys/protosw.h>
60 #include <net/if.h>
61 #include <net/route.h>
62 #include <net/netisr.h>
63
64 #include <netatalk/at.h>
65 #include <netatalk/at_var.h>
66 #include <netatalk/ddp_var.h>
67 #include <netatalk/ddp_pcb.h>
68 #include <netatalk/at_extern.h>
69
70 static u_long   ddp_sendspace = DDP_MAXSZ; /* Max ddp size + 1 (ddp_type) */
71 static u_long   ddp_recvspace = 10 * (587 + sizeof(struct sockaddr_at));
72
73 static const struct netisr_handler atalk1_nh = {
74         .nh_name = "atalk1",
75         .nh_handler = at1intr,
76         .nh_proto = NETISR_ATALK1,
77         .nh_policy = NETISR_POLICY_SOURCE,
78 };
79
80 static const struct netisr_handler atalk2_nh = {
81         .nh_name = "atalk2",
82         .nh_handler = at2intr,
83         .nh_proto = NETISR_ATALK2,
84         .nh_policy = NETISR_POLICY_SOURCE,
85 };
86
87 static const struct netisr_handler aarp_nh = {
88         .nh_name = "aarp",
89         .nh_handler = aarpintr,
90         .nh_proto = NETISR_AARP,
91         .nh_policy = NETISR_POLICY_SOURCE,
92 };
93
94 static int
95 ddp_attach(struct socket *so, int proto, struct thread *td)
96 {
97         int error = 0;
98         
99         KASSERT(sotoddpcb(so) == NULL, ("ddp_attach: ddp != NULL"));
100
101         /*
102          * Allocate socket buffer space first so that it's present
103          * before first use.
104          */
105         error = soreserve(so, ddp_sendspace, ddp_recvspace);
106         if (error)
107                 return (error);
108
109         DDP_LIST_XLOCK();
110         error = at_pcballoc(so);
111         DDP_LIST_XUNLOCK();
112         return (error);
113 }
114
115 static void
116 ddp_detach(struct socket *so)
117 {
118         struct ddpcb *ddp;
119         
120         ddp = sotoddpcb(so);
121         KASSERT(ddp != NULL, ("ddp_detach: ddp == NULL"));
122
123         DDP_LIST_XLOCK();
124         DDP_LOCK(ddp);
125         at_pcbdetach(so, ddp);
126         DDP_LIST_XUNLOCK();
127 }
128
129 static int      
130 ddp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
131 {
132         struct ddpcb *ddp;
133         int error = 0;
134         
135         ddp = sotoddpcb(so);
136         KASSERT(ddp != NULL, ("ddp_bind: ddp == NULL"));
137
138         DDP_LIST_XLOCK();
139         DDP_LOCK(ddp);
140         error = at_pcbsetaddr(ddp, nam, td);
141         DDP_UNLOCK(ddp);
142         DDP_LIST_XUNLOCK();
143         return (error);
144 }
145     
146 static int
147 ddp_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
148 {
149         struct ddpcb *ddp;
150         int error = 0;
151         
152         ddp = sotoddpcb(so);
153         KASSERT(ddp != NULL, ("ddp_connect: ddp == NULL"));
154
155         DDP_LIST_XLOCK();
156         DDP_LOCK(ddp);
157         if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
158                 DDP_UNLOCK(ddp);
159                 DDP_LIST_XUNLOCK();
160                 return (EISCONN);
161         }
162
163         error = at_pcbconnect( ddp, nam, td );
164         DDP_UNLOCK(ddp);
165         DDP_LIST_XUNLOCK();
166         if (error == 0)
167                 soisconnected(so);
168         return (error);
169 }
170
171 static int
172 ddp_disconnect(struct socket *so)
173 {
174         struct ddpcb *ddp;
175         
176         ddp = sotoddpcb(so);
177         KASSERT(ddp != NULL, ("ddp_disconnect: ddp == NULL"));
178
179         DDP_LOCK(ddp);
180         if (ddp->ddp_fsat.sat_addr.s_node == ATADDR_ANYNODE) {
181                 DDP_UNLOCK(ddp);
182                 return (ENOTCONN);
183         }
184
185         at_pcbdisconnect(ddp);
186         ddp->ddp_fsat.sat_addr.s_node = ATADDR_ANYNODE;
187         DDP_UNLOCK(ddp);
188         soisdisconnected(so);
189         return (0);
190 }
191
192 static int
193 ddp_shutdown(struct socket *so)
194 {
195
196         KASSERT(sotoddpcb(so) != NULL, ("ddp_shutdown: ddp == NULL"));
197
198         socantsendmore(so);
199         return (0);
200 }
201
202 static int
203 ddp_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
204     struct mbuf *control, struct thread *td)
205 {
206         struct ddpcb *ddp;
207         int error = 0;
208         
209         ddp = sotoddpcb(so);
210         KASSERT(ddp != NULL, ("ddp_send: ddp == NULL"));
211
212         if (control && control->m_len)
213                 return (EINVAL);
214
215         if (addr != NULL) {
216                 DDP_LIST_XLOCK();
217                 DDP_LOCK(ddp);
218                 if (ddp->ddp_fsat.sat_port != ATADDR_ANYPORT) {
219                         error = EISCONN;
220                         goto out;
221                 }
222
223                 error = at_pcbconnect(ddp, addr, td);
224                 if (error == 0) {
225                         error = ddp_output(m, so);
226                         at_pcbdisconnect(ddp);
227                 }
228 out:
229                 DDP_UNLOCK(ddp);
230                 DDP_LIST_XUNLOCK();
231         } else {
232                 DDP_LOCK(ddp);
233                 if (ddp->ddp_fsat.sat_port == ATADDR_ANYPORT)
234                         error = ENOTCONN;
235                 else
236                         error = ddp_output(m, so);
237                 DDP_UNLOCK(ddp);
238         }
239         return (error);
240 }
241
242 /*
243  * XXXRW: This is never called because we only invoke abort on stream
244  * protocols.
245  */
246 static void
247 ddp_abort(struct socket *so)
248 {
249         struct ddpcb    *ddp;
250         
251         ddp = sotoddpcb(so);
252         KASSERT(ddp != NULL, ("ddp_abort: ddp == NULL"));
253
254         DDP_LOCK(ddp);
255         at_pcbdisconnect(ddp);
256         DDP_UNLOCK(ddp);
257         soisdisconnected(so);
258 }
259
260 static void
261 ddp_close(struct socket *so)
262 {
263         struct ddpcb    *ddp;
264         
265         ddp = sotoddpcb(so);
266         KASSERT(ddp != NULL, ("ddp_close: ddp == NULL"));
267
268         DDP_LOCK(ddp);
269         at_pcbdisconnect(ddp);
270         DDP_UNLOCK(ddp);
271         soisdisconnected(so);
272 }
273
274 void 
275 ddp_init(void)
276 {
277
278         DDP_LIST_LOCK_INIT();
279         TAILQ_INIT(&at_ifaddrhead);
280         netisr_register(&atalk1_nh);
281         netisr_register(&atalk2_nh);
282         netisr_register(&aarp_nh);
283 }
284
285 #if 0
286 static void 
287 ddp_clean(void)
288 {
289         struct ddpcp    *ddp;
290
291         for (ddp = ddpcb_list; ddp != NULL; ddp = ddp->ddp_next)
292                 at_pcbdetach(ddp->ddp_socket, ddp);
293         DDP_LIST_LOCK_DESTROY();
294 }
295 #endif
296
297 static int
298 at_getpeeraddr(struct socket *so, struct sockaddr **nam)
299 {
300
301         return (EOPNOTSUPP);
302 }
303
304 static int
305 at_getsockaddr(struct socket *so, struct sockaddr **nam)
306 {
307         struct ddpcb    *ddp;
308
309         ddp = sotoddpcb(so);
310         KASSERT(ddp != NULL, ("at_getsockaddr: ddp == NULL"));
311
312         DDP_LOCK(ddp);
313         at_sockaddr(ddp, nam);
314         DDP_UNLOCK(ddp);
315         return (0);
316 }
317
318 struct pr_usrreqs ddp_usrreqs = {
319         .pru_abort =            ddp_abort,
320         .pru_attach =           ddp_attach,
321         .pru_bind =             ddp_bind,
322         .pru_connect =          ddp_connect,
323         .pru_control =          at_control,
324         .pru_detach =           ddp_detach,
325         .pru_disconnect =       ddp_disconnect,
326         .pru_peeraddr =         at_getpeeraddr,
327         .pru_send =             ddp_send,
328         .pru_shutdown =         ddp_shutdown,
329         .pru_sockaddr =         at_getsockaddr,
330         .pru_close =            ddp_close,
331 };