dccp6_usrreq.c revision 1.6 1 /* $KAME: dccp6_usrreq.c,v 1.13 2005/07/27 08:42:56 nishida Exp $ */
2 /* $NetBSD: dccp6_usrreq.c,v 1.6 2015/05/02 17:18:03 rtr Exp $ */
3
4 /*
5 * Copyright (C) 2003 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: dccp6_usrreq.c,v 1.6 2015/05/02 17:18:03 rtr Exp $");
35
36 #include "opt_inet.h"
37 #include "opt_dccp.h"
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/domain.h>
42 #include <sys/kernel.h>
43 #include <sys/pool.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/mbuf.h>
47 #include <sys/proc.h>
48 #include <sys/protosw.h>
49 #include <sys/signalvar.h>
50 #include <sys/socket.h>
51 #include <sys/socketvar.h>
52 #include <sys/mutex.h>
53 #include <sys/sysctl.h>
54 #include <sys/syslog.h>
55 #include <sys/queue.h>
56
57 #include <net/if.h>
58 #include <net/route.h>
59
60 #include <netinet/in.h>
61 #include <netinet/in_systm.h>
62 #include <netinet/ip.h>
63 #include <netinet/in_pcb.h>
64 #include <netinet/in_var.h>
65 #include <netinet/ip6.h>
66 #include <netinet/ip_icmp.h>
67 #include <netinet/icmp_var.h>
68 #include <netinet/ip_var.h>
69 #include <netinet6/in6_pcb.h>
70 #include <netinet6/ip6_var.h>
71 #include <netinet6/nd6.h>
72 #include <netinet/dccp.h>
73 #include <netinet/dccp_var.h>
74 #include <netinet6/dccp6_var.h>
75 #include <netinet/dccp_cc_sw.h>
76
77 #if !defined(__FreeBSD__) || __FreeBSD_version < 500000
78 #define INP_INFO_LOCK_INIT(x,y)
79 #define INP_INFO_WLOCK(x)
80 #define INP_INFO_WUNLOCK(x)
81 #define INP_INFO_RLOCK(x)
82 #define INP_INFO_RUNLOCK(x)
83 #define INP_LOCK(x)
84 #define INP_UNLOCK(x)
85 #endif
86
87 #define PULLDOWN_TEST
88
89 int
90 dccp6_input(struct mbuf **mp, int *offp, int proto)
91 {
92 struct mbuf *m = *mp;
93 DCCP_DEBUG((LOG_INFO, "In dccp6_input!\n"));
94 #ifndef PULLDOWN_TEST
95 IP6_EXTHDR_CHECK(m, *offp, sizeof(struct dccphdr), IPPROTO_DONE);
96 #endif
97
98 dccp_input(m, *offp);
99 return IPPROTO_DONE;
100 }
101
102 void *
103 dccp6_ctlinput(int cmd, const struct sockaddr *sa, void *d)
104 {
105 if (sa->sa_family != AF_INET6 ||
106 sa->sa_len != sizeof(struct sockaddr_in6))
107 return NULL;
108
109 /* FIX LATER */
110 return NULL;
111 }
112
113 int
114 dccp6_bind(struct socket *so, struct sockaddr *nam, struct lwp *td)
115 {
116 struct in6pcb *in6p;
117 int error;
118 struct sockaddr_in6 *sin6p = (struct sockaddr_in6 *)nam;
119
120 DCCP_DEBUG((LOG_INFO, "Entering dccp6_bind!\n"));
121 INP_INFO_WLOCK(&dccpbinfo);
122 in6p = sotoin6pcb(so);
123 if (in6p == 0) {
124 INP_INFO_WUNLOCK(&dccpbinfo);
125 DCCP_DEBUG((LOG_INFO, "dccp6_bind: in6p == 0!\n"));
126 return EINVAL;
127 }
128 /* Do not bind to multicast addresses! */
129 if (sin6p->sin6_family == AF_INET6 &&
130 IN6_IS_ADDR_MULTICAST(&sin6p->sin6_addr)) {
131 INP_INFO_WUNLOCK(&dccpbinfo);
132 return EAFNOSUPPORT;
133 }
134 INP_LOCK(inp);
135
136 in6todccpcb(in6p)->inp_vflag &= ~INP_IPV4;
137 in6todccpcb(in6p)->inp_vflag |= INP_IPV6;
138
139 error = in6_pcbbind(in6p, sin6p, td);
140 INP_UNLOCK(inp);
141 INP_INFO_WUNLOCK(&dccpbinfo);
142 return error;
143 }
144
145 int
146 dccp6_connect(struct socket *so, struct sockaddr *nam, struct lwp *l)
147 {
148 struct in6pcb *in6p;
149 struct dccpcb *dp;
150 int error;
151 struct sockaddr_in6 *sin6;
152 char test[2];
153
154 DCCP_DEBUG((LOG_INFO, "Entering dccp6_connect!\n"));
155
156 #ifndef __NetBSD__
157 INP_INFO_WLOCK(&dccpbinfo);
158 inp = sotoinpcb(so);
159 if (inp == 0) {
160 INP_INFO_WUNLOCK(&dccpbinfo);
161 return EINVAL;
162 }
163 INP_LOCK(inp);
164 if (inp->inp_faddr.s_addr != INADDR_ANY) {
165 INP_UNLOCK(inp);
166 INP_INFO_WUNLOCK(&dccpbinfo);
167 return EISCONN;
168 }
169
170 dp = (struct dccpcb *)inp->inp_ppcb;
171 #else
172 in6p = sotoin6pcb(so);
173 if (in6p == 0) {
174 return EINVAL;
175 }
176 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) {
177 return EISCONN;
178 }
179
180 dp = (struct dccpcb *)in6p->in6p_ppcb;
181 #endif
182 if (dp->state == DCCPS_ESTAB) {
183 DCCP_DEBUG((LOG_INFO, "Why are we in connect when we already have a established connection?\n"));
184 }
185
186 dp->who = DCCP_CLIENT;
187 dp->seq_snd = (((u_int64_t)random() << 32) | random()) % 281474976710656LL;
188
189 sin6 = (struct sockaddr_in6 *)nam;
190 if (sin6->sin6_family == AF_INET6
191 && IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
192 error = EAFNOSUPPORT;
193 goto bad;
194 }
195
196 dp->inp_vflag &= ~INP_IPV4;
197 dp->inp_vflag |= INP_IPV6;
198
199 error = dccp_doconnect(so, nam, l, 1);
200
201 if (error != 0)
202 goto bad;
203
204 callout_reset(&dp->retrans_timer, dp->retrans, dccp_retrans_t, dp);
205 callout_reset(&dp->connect_timer, DCCP_CONNECT_TIMER, dccp_connect_t, dp);
206
207 test[0] = dp->pref_cc;
208 #if 0
209 /* FIX THIS LATER */
210 if (dp->pref_cc == 2) {
211 test[1] = 3;
212 } else {
213 test[1] = 2;
214 }
215 dccp_add_feature(dp, DCCP_OPT_CHANGE, DCCP_FEATURE_CC, test, 2);
216 dccp_add_feature(dp, DCCP_OPT_PREFER, DCCP_FEATURE_CC, test, 2);
217 #else
218 /* we only support CCID2 at this moment */
219 dccp_add_feature(dp, DCCP_OPT_CHANGE_R, DCCP_FEATURE_CC, test, 1);
220 #endif
221
222 error = dccp_output(dp, 0);
223
224 bad:
225 INP_UNLOCK(inp);
226 INP_INFO_WUNLOCK(&dccpbinfo);
227 return error;
228 }
229
230
231 int
232 dccp6_listen(struct socket *so, struct lwp *l)
233 {
234 struct in6pcb *in6p;
235 struct dccpcb *dp;
236 int error = 0;
237
238 DCCP_DEBUG((LOG_INFO, "Entering dccp6_listen!\n"));
239
240 INP_INFO_RLOCK(&dccpbinfo);
241 in6p = sotoin6pcb(so);
242 if (in6p == 0) {
243 INP_INFO_RUNLOCK(&dccpbinfo);
244 return EINVAL;
245 }
246 INP_LOCK(inp);
247 INP_INFO_RUNLOCK(&dccpbinfo);
248 dp = in6todccpcb(in6p);
249 DCCP_DEBUG((LOG_INFO, "Checking in6p->in6p_lport!\n"));
250 if (in6p->in6p_lport == 0) {
251 error = in6_pcbbind(in6p, NULL, l);
252 }
253 if (error == 0) {
254 dp->state = DCCPS_LISTEN;
255 dp->who = DCCP_LISTENER;
256 dp->seq_snd = 512;
257 }
258 INP_UNLOCK(inp);
259 return error;
260 }
261
262 int
263 dccp6_accept(struct socket *so, struct sockaddr *nam)
264 {
265 struct in6pcb *in6p = NULL;
266 int error = 0;
267
268 DCCP_DEBUG((LOG_INFO, "Entering dccp6_accept!\n"));
269 if (nam == NULL) {
270 return EINVAL;
271 }
272 if (so->so_state & SS_ISDISCONNECTED) {
273 DCCP_DEBUG((LOG_INFO, "so_state && SS_ISDISCONNECTED!, so->state = %i\n", so->so_state));
274 return ECONNABORTED;
275 }
276
277 INP_INFO_RLOCK(&dccpbinfo);
278 in6p = sotoin6pcb(so);
279 if (in6p == 0) {
280 INP_INFO_RUNLOCK(&dccpbinfo);
281 return EINVAL;
282 }
283 INP_LOCK(inp);
284 INP_INFO_RUNLOCK(&dccpbinfo);
285 in6_setpeeraddr(in6p, (struct sockaddr_in6 *)nam);
286
287 INP_UNLOCK(inp);
288 return error;
289 }
290
291 static int
292 dccp6_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp)
293 {
294 int error = 0;
295 int family;
296
297 family = so->so_proto->pr_domain->dom_family;
298 switch (family) {
299 case PF_INET6:
300 error = in6_control(so, cmd, nam, ifp);
301 break;
302 default:
303 error = EAFNOSUPPORT;
304 }
305 return (error);
306 }
307
308 static int
309 dccp6_stat(struct socket *so, struct stat *ub)
310 {
311 return 0;
312 }
313
314 static int
315 dccp6_purgeif(struct socket *so, struct ifnet *ifp)
316 {
317 int s;
318
319 s = splsoftnet();
320 mutex_enter(softnet_lock);
321 in6_pcbpurgeif0(&dccpbtable, ifp);
322 in6_purgeif(ifp);
323 in6_pcbpurgeif(&dccpbtable, ifp);
324 mutex_exit(softnet_lock);
325 splx(s);
326
327 return 0;
328 }
329
330 static int
331 dccp6_attach(struct socket *so, int proto)
332 {
333 return dccp_attach(so, proto);
334 }
335
336 static int
337 dccp6_detach(struct socket *so)
338 {
339 return dccp_detach(so);
340 }
341
342 static int
343 dccp6_connect2(struct socket *so, struct socket *so2)
344 {
345 KASSERT(solocked(so));
346
347 return EOPNOTSUPP;
348 }
349
350 static int
351 dccp6_disconnect(struct socket *so)
352 {
353 return dccp_disconnect(so);
354 }
355
356 static int
357 dccp6_shutdown(struct socket *so)
358 {
359 return dccp_shutdown(so);
360 }
361
362 static int
363 dccp6_abort(struct socket *so)
364 {
365 return dccp_abort(so);
366 }
367
368
369 static int
370 dccp6_peeraddr(struct socket *so, struct sockaddr *nam)
371 {
372 KASSERT(solocked(so));
373 KASSERT(sotoinpcb(so) != NULL);
374 KASSERT(nam != NULL);
375
376 in6_setpeeraddr(sotoin6pcb(so), (struct sockaddr_in6 *)nam);
377 return 0;
378 }
379
380 static int
381 dccp6_sockaddr(struct socket *so, struct sockaddr *nam)
382 {
383 KASSERT(solocked(so));
384 KASSERT(sotoinpcb(so) != NULL);
385 KASSERT(nam != NULL);
386
387 in6_setsockaddr(sotoin6pcb(so), (struct sockaddr_in6 *)nam);
388 return 0;
389 }
390
391 static int
392 dccp6_recvoob(struct socket *so, struct mbuf *m, int flags)
393 {
394 KASSERT(solocked(so));
395
396 return EOPNOTSUPP;
397 }
398
399 static int
400 dccp6_rcvd(struct socket *so, int flags, struct lwp *l)
401 {
402 KASSERT(solocked(so));
403
404 return EOPNOTSUPP;
405 }
406
407 static int
408 dccp6_send(struct socket *so, struct mbuf *m, struct sockaddr *nam,
409 struct mbuf *control, struct lwp *l)
410 {
411 return dccp_send(so, m, nam, control, l);
412 }
413
414 static int
415 dccp6_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control)
416 {
417 KASSERT(solocked(so));
418
419 m_freem(m);
420 m_freem(control);
421
422 return EOPNOTSUPP;
423 }
424
425
426 PR_WRAP_USRREQS(dccp6)
427 #define dccp6_attach dccp6_attach_wrapper
428 #define dccp6_detach dccp6_detach_wrapper
429 #define dccp6_accept dccp6_accept_wrapper
430 #define dccp6_bind dccp6_bind_wrapper
431 #define dccp6_listen dccp6_listen_wrapper
432 #define dccp6_connect dccp6_connect_wrapper
433 #define dccp6_connect2 dccp6_connect2_wrapper
434 #define dccp6_disconnect dccp6_disconnect_wrapper
435 #define dccp6_shutdown dccp6_shutdown_wrapper
436 #define dccp6_abort dccp6_abort_wrapper
437 #define dccp6_ioctl dccp6_ioctl_wrapper
438 #define dccp6_stat dccp6_stat_wrapper
439 #define dccp6_peeraddr dccp6_peeraddr_wrapper
440 #define dccp6_sockaddr dccp6_sockaddr_wrapper
441 #define dccp6_rcvd dccp6_rcvd_wrapper
442 #define dccp6_recvoob dccp6_recvoob_wrapper
443 #define dccp6_send dccp6_send_wrapper
444 #define dccp6_sendoob dccp6_sendoob_wrapper
445 #define dccp6_purgeif dccp6_purgeif_wrapper
446
447 const struct pr_usrreqs dccp6_usrreqs = {
448 .pr_attach = dccp6_attach,
449 .pr_detach = dccp6_detach,
450 .pr_accept = dccp6_accept,
451 .pr_bind = dccp6_bind,
452 .pr_listen = dccp6_listen,
453 .pr_connect = dccp6_connect,
454 .pr_connect2 = dccp6_connect2,
455 .pr_disconnect = dccp6_disconnect,
456 .pr_shutdown = dccp6_shutdown,
457 .pr_abort = dccp6_abort,
458 .pr_ioctl = dccp6_ioctl,
459 .pr_stat = dccp6_stat,
460 .pr_peeraddr = dccp6_peeraddr,
461 .pr_sockaddr = dccp6_sockaddr,
462 .pr_rcvd = dccp6_rcvd,
463 .pr_recvoob = dccp6_recvoob,
464 .pr_send = dccp6_send,
465 .pr_sendoob = dccp6_sendoob,
466 .pr_purgeif = dccp6_purgeif,
467 };
468