xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rdsv3/bind.c (revision 72b703890acc1682901e7ab4df40758e3c4399d8)
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 	uint64_t	needle = ((uint64_t)addr << 32) | port;
50 
51 	rs = avl_find(&rdsv3_bind_tree, &needle, &where);
52 	if ((rs == NULL) && (insert != NULL)) {
53 		insert->rs_bound_addr = addr;
54 		insert->rs_bound_port = port;
55 		avl_insert(&rdsv3_bind_tree, insert, where);
56 	}
57 
58 	return (rs);
59 }
60 
61 /*
62  * Return the rdsv3_sock bound at the given local address.
63  *
64  * The rx path can race with rdsv3_release.  We notice if rdsv3_release() has
65  * marked this socket and don't return a rs ref to the rx path.
66  */
67 struct rdsv3_sock *
68 rdsv3_find_bound(uint32_be_t addr, uint16_be_t port)
69 {
70 	struct rdsv3_sock *rs;
71 
72 	RDSV3_DPRINTF4("rdsv3_find_bound", "Enter(port: %x)", port);
73 
74 	mutex_enter(&rdsv3_bind_lock);
75 	rs = rdsv3_bind_tree_walk(addr, port, NULL);
76 	if (rs && !rdsv3_sk_sock_flag(rdsv3_rs_to_sk(rs), SOCK_DEAD))
77 		rdsv3_sock_addref(rs);
78 	else
79 		rs = NULL;
80 	mutex_exit(&rdsv3_bind_lock);
81 
82 	RDSV3_DPRINTF5("rdsv3_find_bound", "returning rs %p for %u.%u.%u.%u:%x",
83 	    rs, NIPQUAD(addr), port);
84 
85 	return (rs);
86 }
87 
88 /* returns -ve errno or +ve port */
89 static int
90 rdsv3_add_bound(struct rdsv3_sock *rs, uint32_be_t addr, uint16_be_t *port)
91 {
92 	int ret = -EADDRINUSE;
93 	uint16_t rover, last;
94 
95 	RDSV3_DPRINTF4("rdsv3_add_bound", "Enter(port: %x)", *port);
96 
97 	if (*port != 0) {
98 		rover = ntohs(*port);
99 		last = rover;
100 	} else {
101 		(void) random_get_pseudo_bytes((uint8_t *)&rover,
102 		    sizeof (uint16_t));
103 		rover = MAX(rover, 2);
104 		last = rover - 1;
105 	}
106 
107 	mutex_enter(&rdsv3_bind_lock);
108 
109 	do {
110 		if (rover == 0)
111 			rover++;
112 
113 		if (rdsv3_bind_tree_walk(addr, htons(rover), rs) == NULL) {
114 			*port = htons(rover);
115 			ret = 0;
116 			break;
117 		}
118 	} while (rover++ != last);
119 
120 	if (ret == 0)  {
121 		rs->rs_bound_addr = addr;
122 		rs->rs_bound_port = *port;
123 		rdsv3_sock_addref(rs);
124 
125 		RDSV3_DPRINTF5("rdsv3_add_bound",
126 		    "rs %p binding to %u.%u.%u.%u:%x",
127 		    rs, NIPQUAD(addr), *port);
128 	}
129 
130 	mutex_exit(&rdsv3_bind_lock);
131 
132 	RDSV3_DPRINTF4("rdsv3_add_bound", "Return(port: %x)", *port);
133 
134 	return (ret);
135 }
136 
137 void
138 rdsv3_remove_bound(struct rdsv3_sock *rs)
139 {
140 	RDSV3_DPRINTF4("rdsv3_remove_bound", "Enter(rs: %p)", rs);
141 
142 	mutex_enter(&rdsv3_bind_lock);
143 
144 	if (rs->rs_bound_addr) {
145 		RDSV3_DPRINTF5("rdsv3_remove_bound",
146 		    "rs %p unbinding from %u.%u.%u.%u:%x",
147 		    rs, NIPQUAD(rs->rs_bound_addr), rs->rs_bound_port);
148 		avl_remove(&rdsv3_bind_tree, rs);
149 		rdsv3_sock_put(rs);
150 		rs->rs_bound_addr = 0;
151 	}
152 
153 	mutex_exit(&rdsv3_bind_lock);
154 
155 	RDSV3_DPRINTF4("rdsv3_remove_bound", "Return(rs: %p)", rs);
156 }
157 
158 /* ARGSUSED */
159 int
160 rdsv3_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa,
161     socklen_t len, cred_t *cr)
162 {
163 	struct rsock	*sk = (struct rsock *)proto_handle;
164 	sin_t		*sin = (sin_t *)sa;
165 	struct rdsv3_sock	*rs = rdsv3_sk_to_rs(sk);
166 	int		ret;
167 
168 	if (len != sizeof (sin_t) || (sin == NULL) ||
169 	    !OK_32PTR((char *)sin)) {
170 		RDSV3_DPRINTF2("rdsv3_bind", "address to bind not specified");
171 		return (EINVAL);
172 	}
173 
174 	RDSV3_DPRINTF4("rdsv3_bind", "Enter(rs: %p, addr: 0x%x, port: %x)",
175 	    rs, ntohl(sin->sin_addr.s_addr), htons(sin->sin_port));
176 
177 	if (sin->sin_addr.s_addr == INADDR_ANY) {
178 		RDSV3_DPRINTF2("rdsv3_bind", "Invalid address");
179 		return (EINVAL);
180 	}
181 
182 	/* We don't allow multiple binds */
183 	if (rs->rs_bound_addr) {
184 		RDSV3_DPRINTF2("rdsv3_bind", "Multiple binds not allowed");
185 		return (EINVAL);
186 	}
187 
188 	ret = rdsv3_add_bound(rs, sin->sin_addr.s_addr, &sin->sin_port);
189 	if (ret) {
190 		return (ret);
191 	}
192 
193 	rs->rs_transport = rdsv3_trans_get_preferred(sin->sin_addr.s_addr);
194 	if (!rs->rs_transport) {
195 		rdsv3_remove_bound(rs);
196 		if (rdsv3_printk_ratelimit()) {
197 			RDSV3_DPRINTF1("rdsv3_bind",
198 			    "RDS: rdsv3_bind() could not find a transport.\n");
199 		}
200 		return (EADDRNOTAVAIL);
201 	}
202 
203 	RDSV3_DPRINTF4("rdsv3_bind", "Return: Assigned port: %x to sock: %p",
204 	    sin->sin_port, rs);
205 
206 	return (0);
207 }
208