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