xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rdsv3/bind.c (revision b1d7ec75953cd517f5b7c3d9cb427ff8ec5d7d07)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <sys/types.h>
26 #include <sys/sysmacros.h>
27 #include <sys/random.h>
28 #include <sys/rds.h>
29 
30 #include <sys/ib/clients/rdsv3/rdsv3.h>
31 #include <sys/ib/clients/rdsv3/rdsv3_debug.h>
32 
33 /*
34  * XXX this probably still needs more work.. no INADDR_ANY, and rbtrees aren't
35  * particularly zippy.
36  *
37  * This is now called for every incoming frame so we arguably care much more
38  * about it than we used to.
39  */
40 kmutex_t	rdsv3_bind_lock;
41 avl_tree_t	rdsv3_bind_tree;
42 
43 static struct rdsv3_sock *
44 rdsv3_bind_tree_walk(uint32_be_t addr, uint16_be_t port,
45     struct rdsv3_sock *insert)
46 {
47 	struct rdsv3_sock *rs;
48 	avl_index_t	where;
49 
50 	rs = avl_find(&rdsv3_bind_tree, &port, &where);
51 	if ((rs == NULL) && (insert != NULL)) {
52 		insert->rs_bound_addr = addr;
53 		insert->rs_bound_port = port;
54 		avl_insert(&rdsv3_bind_tree, insert, where);
55 	}
56 
57 	return (rs);
58 }
59 
60 /*
61  * Return the rdsv3_sock bound at the given local address.
62  *
63  * The rx path can race with rdsv3_release.  We notice if rdsv3_release() has
64  * marked this socket and don't return a rs ref to the rx path.
65  */
66 struct rdsv3_sock *
67 rdsv3_find_bound(uint32_be_t addr, uint16_be_t port)
68 {
69 	struct rdsv3_sock *rs;
70 
71 	RDSV3_DPRINTF4("rdsv3_find_bound", "Enter(port: %x)", port);
72 
73 	mutex_enter(&rdsv3_bind_lock);
74 	rs = rdsv3_bind_tree_walk(addr, port, NULL);
75 	if (rs && !rdsv3_sk_sock_flag(rdsv3_rs_to_sk(rs), SOCK_DEAD))
76 		rdsv3_sock_addref(rs);
77 	else
78 		rs = NULL;
79 	mutex_exit(&rdsv3_bind_lock);
80 
81 	RDSV3_DPRINTF5("rdsv3_find_bound", "returning rs %p for %u.%u.%u.%u:%x",
82 	    rs, NIPQUAD(addr), port);
83 
84 	return (rs);
85 }
86 
87 /* returns -ve errno or +ve port */
88 static int
89 rdsv3_add_bound(struct rdsv3_sock *rs, uint32_be_t addr, uint16_be_t *port)
90 {
91 	int ret = -EADDRINUSE;
92 	uint16_t rover, last;
93 
94 	RDSV3_DPRINTF4("rdsv3_add_bound", "Enter(port: %x)", *port);
95 
96 	if (*port != 0) {
97 		rover = ntohs(*port);
98 		last = rover;
99 	} else {
100 		(void) random_get_pseudo_bytes((uint8_t *)&rover,
101 		    sizeof (uint16_t));
102 		rover = MAX(rover, 2);
103 		last = rover - 1;
104 	}
105 
106 	mutex_enter(&rdsv3_bind_lock);
107 
108 	do {
109 		if (rover == 0)
110 			rover++;
111 		if (rdsv3_bind_tree_walk(addr, htons(rover), rs) == NULL) {
112 			*port = htons(rover);
113 			ret = 0;
114 			break;
115 		}
116 	} while (rover++ != last);
117 
118 	if (ret == 0)  {
119 		rs->rs_bound_addr = addr;
120 		rs->rs_bound_port = *port;
121 		rdsv3_sock_addref(rs);
122 
123 		RDSV3_DPRINTF5("rdsv3_add_bound",
124 		    "rs %p binding to %u.%u.%u.%u:%x",
125 		    rs, NIPQUAD(addr), *port);
126 	}
127 
128 	mutex_exit(&rdsv3_bind_lock);
129 
130 	RDSV3_DPRINTF4("rdsv3_add_bound", "Return(port: %x)", *port);
131 
132 	return (ret);
133 }
134 
135 void
136 rdsv3_remove_bound(struct rdsv3_sock *rs)
137 {
138 	RDSV3_DPRINTF4("rdsv3_remove_bound", "Enter(rs: %p)", rs);
139 
140 	mutex_enter(&rdsv3_bind_lock);
141 
142 	if (rs->rs_bound_addr) {
143 		RDSV3_DPRINTF5("rdsv3_remove_bound",
144 		    "rs %p unbinding from %u.%u.%u.%u:%x",
145 		    rs, NIPQUAD(rs->rs_bound_addr), rs->rs_bound_port);
146 		avl_remove(&rdsv3_bind_tree, rs);
147 		rdsv3_sock_put(rs);
148 		rs->rs_bound_addr = 0;
149 	}
150 
151 	mutex_exit(&rdsv3_bind_lock);
152 
153 	RDSV3_DPRINTF4("rdsv3_remove_bound", "Return(rs: %p)", rs);
154 }
155 
156 /* ARGSUSED */
157 int
158 rdsv3_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa,
159     socklen_t len, cred_t *cr)
160 {
161 	struct rsock	*sk = (struct rsock *)proto_handle;
162 	sin_t		*sin = (sin_t *)sa;
163 	struct rdsv3_sock	*rs = rdsv3_sk_to_rs(sk);
164 	int		ret;
165 
166 	if (len != sizeof (sin_t) || (sin == NULL) ||
167 	    !OK_32PTR((char *)sin)) {
168 		RDSV3_DPRINTF2("rdsv3_bind", "address to bind not specified");
169 		return (EINVAL);
170 	}
171 
172 	RDSV3_DPRINTF4("rdsv3_bind", "Enter(rs: %p, addr: 0x%x, port: %x)",
173 	    rs, ntohl(sin->sin_addr.s_addr), htons(sin->sin_port));
174 
175 	if (sin->sin_addr.s_addr == INADDR_ANY) {
176 		RDSV3_DPRINTF2("rdsv3_bind", "Invalid address");
177 		return (EINVAL);
178 	}
179 
180 	/* We don't allow multiple binds */
181 	if (rs->rs_bound_addr) {
182 		RDSV3_DPRINTF2("rdsv3_bind", "Multiple binds not allowed");
183 		return (EINVAL);
184 	}
185 
186 	ret = rdsv3_add_bound(rs, sin->sin_addr.s_addr, &sin->sin_port);
187 	if (ret) {
188 		return (ret);
189 	}
190 
191 	rs->rs_transport = rdsv3_trans_get_preferred(sin->sin_addr.s_addr);
192 	if (rs->rs_transport == NULL) {
193 		rdsv3_remove_bound(rs);
194 		if (rdsv3_printk_ratelimit()) {
195 			RDSV3_DPRINTF1("rdsv3_bind",
196 			    "RDS: rdsv3_bind() could not find a transport.\n");
197 		}
198 		return (EADDRNOTAVAIL);
199 	}
200 
201 	RDSV3_DPRINTF4("rdsv3_bind", "Return: Assigned port: %x to sock: %p",
202 	    sin->sin_port, rs);
203 
204 	return (0);
205 }
206