xref: /illumos-gate/usr/src/uts/common/io/ib/clients/rdsv3/bind.c (revision c0dd49bdd68c0d758a67d56f07826f3b45cfc664)
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 	return (rs);
84 }
85 
86 /* returns -ve errno or +ve port */
87 static int
88 rdsv3_add_bound(struct rdsv3_sock *rs, uint32_be_t addr, uint16_be_t *port)
89 {
90 	int ret = -EADDRINUSE;
91 	uint16_t rover, last;
92 
93 	RDSV3_DPRINTF4("rdsv3_add_bound", "Enter(port: %x)", *port);
94 
95 	if (*port != 0) {
96 		rover = ntohs(*port);
97 		last = rover;
98 	} else {
99 		(void) random_get_pseudo_bytes((uint8_t *)&rover,
100 		    sizeof (uint16_t));
101 		rover = MAX(rover, 2);
102 		last = rover - 1;
103 	}
104 
105 	mutex_enter(&rdsv3_bind_lock);
106 
107 	do {
108 		if (rover == 0)
109 			rover++;
110 		if (rdsv3_bind_tree_walk(addr, htons(rover), rs) == NULL) {
111 			*port = htons(rover);
112 			ret = 0;
113 			break;
114 		}
115 	} while (rover++ != last);
116 
117 	if (ret == 0)  {
118 		rs->rs_bound_addr = addr;
119 		rs->rs_bound_port = *port;
120 		rdsv3_sock_addref(rs);
121 
122 		RDSV3_DPRINTF5("rdsv3_add_bound",
123 		    "rs %p binding to %u.%u.%u.%u:%x",
124 		    rs, NIPQUAD(addr), *port);
125 
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 
147 		avl_remove(&rdsv3_bind_tree, rs);
148 		rdsv3_sock_put(rs);
149 		rs->rs_bound_addr = 0;
150 	}
151 
152 	mutex_exit(&rdsv3_bind_lock);
153 
154 	RDSV3_DPRINTF4("rdsv3_remove_bound", "Return(rs: %p)", rs);
155 }
156 
157 /* ARGSUSED */
158 int
159 rdsv3_bind(sock_lower_handle_t proto_handle, struct sockaddr *sa,
160     socklen_t len, cred_t *cr)
161 {
162 	struct rsock	*sk = (struct rsock *)proto_handle;
163 	sin_t		*sin = (sin_t *)sa;
164 	struct rdsv3_sock	*rs = rdsv3_sk_to_rs(sk);
165 	int		ret;
166 
167 	if (len != sizeof (sin_t) || (sin == NULL) ||
168 	    !OK_32PTR((char *)sin)) {
169 		RDSV3_DPRINTF2("rdsv3_bind", "address to bind not specified");
170 		return (EINVAL);
171 	}
172 
173 	RDSV3_DPRINTF4("rdsv3_bind", "Enter(rs: %p, addr: 0x%x, port: %x)",
174 	    rs, ntohl(sin->sin_addr.s_addr), htons(sin->sin_port));
175 
176 	if (sin->sin_addr.s_addr == INADDR_ANY) {
177 		RDSV3_DPRINTF2("rdsv3_bind", "Invalid address");
178 		return (EINVAL);
179 	}
180 
181 	/* We don't allow multiple binds */
182 	if (rs->rs_bound_addr) {
183 		RDSV3_DPRINTF2("rdsv3_bind", "Multiple binds not allowed");
184 		return (EINVAL);
185 	}
186 
187 	ret = rdsv3_add_bound(rs, sin->sin_addr.s_addr, &sin->sin_port);
188 	if (ret) {
189 		return (ret);
190 	}
191 
192 	rs->rs_transport = rdsv3_trans_get_preferred(sin->sin_addr.s_addr);
193 	if (rs->rs_transport == NULL) {
194 		rdsv3_remove_bound(rs);
195 		return (EADDRNOTAVAIL);
196 	}
197 
198 	RDSV3_DPRINTF4("rdsv3_bind", "Return: Assigned port: %x to sock: %p",
199 	    sin->sin_port, rs);
200 
201 	return (0);
202 }
203