5acb9c715cdfd3132d3a8d6eaaf7fcf6e85638fd
[dragonfly.git] / sys / net / raw_usrreq.c
1 /*
2  * Copyright (c) 1980, 1986, 1993
3  *      The Regents of the University of California.  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  * 3. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *      @(#)raw_usrreq.c        8.1 (Berkeley) 6/10/93
30  * $FreeBSD: src/sys/net/raw_usrreq.c,v 1.18 1999/08/28 00:48:28 peter Exp $
31  */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/mbuf.h>
36 #include <sys/proc.h>
37 #include <sys/priv.h>
38 #include <sys/protosw.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41
42 #include <sys/socketvar2.h>
43 #include <sys/msgport2.h>
44
45 #include <net/raw_cb.h>
46
47 struct lock raw_lock = LOCK_INITIALIZER("rawlk", 0, 0);
48
49 /*
50  * Initialize raw connection block q.
51  */
52 void
53 raw_init(void)
54 {
55         LIST_INIT(&rawcb_list);
56 }
57
58 /************************************************************************
59  *                       RAW PROTOCOL INTERFACE                         *
60  ************************************************************************/
61
62 /*
63  * Raw protocol input routine.  Find the socket associated with the packet(s)
64  * and move them over.  If nothing exists for this packet, drop it.  This
65  * routine is indirect called via rts_input() and will be serialized on
66  * cpu 0.
67  *
68  * Most other raw protocol interface functions are also serialized XXX.
69  */
70 void
71 raw_input(struct mbuf *m0, const struct sockproto *proto,
72           const struct sockaddr *src, const struct sockaddr *dst,
73           const struct rawcb *skip)
74 {
75         struct rawcb *rp;
76         struct mbuf *m = m0;
77         struct socket *last;
78
79         lockmgr(&raw_lock, LK_SHARED);
80         last = NULL;
81
82         LIST_FOREACH(rp, &rawcb_list, list) {
83                 if (rp == skip)
84                         continue;
85                 if (rp->rcb_proto.sp_family != proto->sp_family)
86                         continue;
87                 if (rp->rcb_proto.sp_protocol  &&
88                     rp->rcb_proto.sp_protocol != proto->sp_protocol)
89                         continue;
90                 /*
91                  * We assume the lower level routines have
92                  * placed the address in a canonical format
93                  * suitable for a structure comparison.
94                  *
95                  * Note that if the lengths are not the same
96                  * the comparison will fail at the first byte.
97                  */
98                 if (rp->rcb_laddr && !sa_equal(rp->rcb_laddr, dst))
99                         continue;
100                 if (rp->rcb_faddr && !sa_equal(rp->rcb_faddr, src))
101                         continue;
102                 if (last) {
103                         struct mbuf *n;
104
105                         n = m_copypacket(m, M_NOWAIT);
106                         if (n != NULL) {
107                                 lwkt_gettoken(&last->so_rcv.ssb_token);
108                                 if (ssb_appendaddr(&last->so_rcv, src, n,
109                                                  NULL) == 0) {
110                                         m_freem(n);
111                                         soroverflow(last);
112                                 } else {
113                                         sorwakeup(last);
114                                 }
115                                 lwkt_reltoken(&last->so_rcv.ssb_token);
116                         }
117                 }
118                 last = rp->rcb_socket;
119         }
120         if (last) {
121                 lwkt_gettoken(&last->so_rcv.ssb_token);
122                 if (ssb_appendaddr(&last->so_rcv, src, m, NULL) == 0) {
123                         m_freem(m);
124                         soroverflow(last);
125                 } else
126                         sorwakeup(last);
127                 lwkt_reltoken(&last->so_rcv.ssb_token);
128         } else {
129                 m_freem(m);
130         }
131         lockmgr(&raw_lock, LK_RELEASE);
132 }
133
134 /*
135  * nm_cmd, nm_arg, nm_extra
136  */
137 void
138 raw_ctlinput(netmsg_t msg)
139 {
140         int error = 0;
141
142         if (msg->ctlinput.nm_cmd < 0 || msg->ctlinput.nm_cmd > PRC_NCMDS) {
143                 ; /* no-op */
144         }
145         lwkt_replymsg(&msg->lmsg, error);
146 }
147
148 /*
149  * NOTE: (so) is referenced from soabort*() and netmsg_pru_abort()
150  *       will sofree() it when we return.
151  */
152 static void
153 raw_uabort(netmsg_t msg)
154 {
155         struct rawcb *rp = sotorawcb(msg->base.nm_so);
156         int error;
157
158         if (rp) {
159                 raw_disconnect(rp);
160                 soisdisconnected(msg->base.nm_so);
161                 error = 0;
162         } else {
163                 error = EINVAL;
164         }
165         lwkt_replymsg(&msg->lmsg, error);
166 }
167
168 /* pru_accept is EOPNOTSUPP */
169
170 static void
171 raw_uattach(netmsg_t msg)
172 {
173         struct socket *so = msg->base.nm_so;
174         int proto = msg->attach.nm_proto;
175         struct pru_attach_info *ai = msg->attach.nm_ai;
176         struct rawcb *rp;
177         int error;
178
179         rp = sotorawcb(so);
180         if (rp) {
181                 error = priv_check_cred(ai->p_ucred, PRIV_ROOT, NULL_CRED_OKAY);
182                 if (error == 0)
183                         error = raw_attach(so, proto, ai->sb_rlimit);
184         } else {
185                 error = EINVAL;
186         }
187         lwkt_replymsg(&msg->lmsg, error);
188 }
189
190 static void
191 raw_ubind(netmsg_t msg)
192 {
193         lwkt_replymsg(&msg->lmsg, EINVAL);
194 }
195
196 static void
197 raw_uconnect(netmsg_t msg)
198 {
199         lwkt_replymsg(&msg->lmsg, EINVAL);
200 }
201
202 /* pru_connect2 is EOPNOTSUPP */
203 /* pru_control is EOPNOTSUPP */
204
205 static void
206 raw_udetach(netmsg_t msg)
207 {
208         struct rawcb *rp = sotorawcb(msg->base.nm_so);
209         int error;
210
211         if (rp) {
212                 raw_detach(rp);
213                 error = 0;
214         } else {
215                 error = EINVAL;
216         }
217         lwkt_replymsg(&msg->lmsg, error);
218 }
219
220 static void
221 raw_udisconnect(netmsg_t msg)
222 {
223         struct socket *so = msg->base.nm_so;
224         struct rawcb *rp;
225         int error;
226
227         rp = sotorawcb(so);
228         if (rp == NULL) {
229                 error = EINVAL;
230         } else if (rp->rcb_faddr == NULL) {
231                 error = ENOTCONN;
232         } else {
233                 soreference(so);
234                 raw_disconnect(rp);
235                 soisdisconnected(so);
236                 sofree(so);
237                 error = 0;
238         }
239         lwkt_replymsg(&msg->lmsg, error);
240 }
241
242 /* pru_listen is EOPNOTSUPP */
243
244 static void
245 raw_upeeraddr(netmsg_t msg)
246 {
247         struct rawcb *rp = sotorawcb(msg->base.nm_so);
248         int error;
249
250         if (rp == NULL) {
251                 error = EINVAL;
252         } else if (rp->rcb_faddr == NULL) {
253                 error = ENOTCONN;
254         } else {
255                 *msg->peeraddr.nm_nam = dup_sockaddr(rp->rcb_faddr);
256                 error = 0;
257         }
258         lwkt_replymsg(&msg->lmsg, error);
259 }
260
261 /* pru_rcvd is EOPNOTSUPP */
262 /* pru_rcvoob is EOPNOTSUPP */
263
264 static void
265 raw_usend(netmsg_t msg)
266 {
267         struct socket *so = msg->base.nm_so;
268         struct mbuf *m = msg->send.nm_m;
269         struct mbuf *control = msg->send.nm_control;
270         struct rawcb *rp = sotorawcb(so);
271         struct pr_output_info oi;
272         int flags = msg->send.nm_flags;
273         int error;
274
275         if (rp == NULL) {
276                 error = EINVAL;
277                 goto release;
278         }
279
280         if (flags & PRUS_OOB) {
281                 error = EOPNOTSUPP;
282                 goto release;
283         }
284
285         if (control && control->m_len) {
286                 error = EOPNOTSUPP;
287                 goto release;
288         }
289         if (msg->send.nm_addr) {
290                 if (rp->rcb_faddr) {
291                         error = EISCONN;
292                         goto release;
293                 }
294                 rp->rcb_faddr = msg->send.nm_addr;
295         } else if (rp->rcb_faddr == NULL) {
296                 error = ENOTCONN;
297                 goto release;
298         }
299         oi.p_pid = msg->send.nm_td->td_proc->p_pid;
300         error = (*so->so_proto->pr_output)(m, so, &oi);
301         m = NULL;
302         if (msg->send.nm_addr)
303                 rp->rcb_faddr = NULL;
304 release:
305         if (m != NULL)
306                 m_freem(m);
307         lwkt_replymsg(&msg->lmsg, error);
308 }
309
310 /* pru_sense is null */
311
312 static void
313 raw_ushutdown(netmsg_t msg)
314 {
315         struct rawcb *rp = sotorawcb(msg->base.nm_so);
316         int error;
317
318         if (rp) {
319                 socantsendmore(msg->base.nm_so);
320                 error = 0;
321         } else {
322                 error = EINVAL;
323         }
324         lwkt_replymsg(&msg->lmsg, error);
325 }
326
327 static void
328 raw_usockaddr(netmsg_t msg)
329 {
330         struct rawcb *rp = sotorawcb(msg->base.nm_so);
331         int error;
332
333         if (rp == NULL) {
334                 error = EINVAL;
335         } else if (rp->rcb_laddr == NULL) {
336                 error = EINVAL;
337         } else {
338                 *msg->sockaddr.nm_nam = dup_sockaddr(rp->rcb_laddr);
339                 error = 0;
340         }
341         lwkt_replymsg(&msg->lmsg, error);
342 }
343
344 struct pr_usrreqs raw_usrreqs = {
345         .pru_abort = raw_uabort,
346         .pru_accept = pr_generic_notsupp,
347         .pru_attach = raw_uattach,
348         .pru_bind = raw_ubind,
349         .pru_connect = raw_uconnect,
350         .pru_connect2 = pr_generic_notsupp,
351         .pru_control = pr_generic_notsupp,
352         .pru_detach = raw_udetach, 
353         .pru_disconnect = raw_udisconnect,
354         .pru_listen = pr_generic_notsupp,
355         .pru_peeraddr = raw_upeeraddr,
356         .pru_rcvd = pr_generic_notsupp,
357         .pru_rcvoob = pr_generic_notsupp,
358         .pru_send = raw_usend,
359         .pru_sense = pru_sense_null,
360         .pru_shutdown = raw_ushutdown,
361         .pru_sockaddr = raw_usockaddr,
362         .pru_sosend = sosend,
363         .pru_soreceive = soreceive
364 };