diff options
-rw-r--r-- | Documentation/networking/rxrpc.txt | 4 | ||||
-rw-r--r-- | net/rxrpc/af_rxrpc.c | 62 | ||||
-rw-r--r-- | net/rxrpc/ar-internal.h | 2 | ||||
-rw-r--r-- | net/rxrpc/call_accept.c | 3 | ||||
-rw-r--r-- | net/rxrpc/local_object.c | 1 | ||||
-rw-r--r-- | net/rxrpc/security.c | 3 |
6 files changed, 51 insertions, 24 deletions
diff --git a/Documentation/networking/rxrpc.txt b/Documentation/networking/rxrpc.txt index 1b63bbc6b94f..b7115ec55e04 100644 --- a/Documentation/networking/rxrpc.txt +++ b/Documentation/networking/rxrpc.txt | |||
@@ -600,6 +600,10 @@ A server would be set up to accept operations in the following manner: | |||
600 | }; | 600 | }; |
601 | bind(server, &srx, sizeof(srx)); | 601 | bind(server, &srx, sizeof(srx)); |
602 | 602 | ||
603 | More than one service ID may be bound to a socket, provided the transport | ||
604 | parameters are the same. The limit is currently two. To do this, bind() | ||
605 | should be called twice. | ||
606 | |||
603 | (3) The server is then set to listen out for incoming calls: | 607 | (3) The server is then set to listen out for incoming calls: |
604 | 608 | ||
605 | listen(server, 100); | 609 | listen(server, 100); |
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 1e4ac889ec00..3b982bca7d22 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c | |||
@@ -144,31 +144,48 @@ static int rxrpc_bind(struct socket *sock, struct sockaddr *saddr, int len) | |||
144 | 144 | ||
145 | lock_sock(&rx->sk); | 145 | lock_sock(&rx->sk); |
146 | 146 | ||
147 | if (rx->sk.sk_state != RXRPC_UNBOUND) { | 147 | switch (rx->sk.sk_state) { |
148 | ret = -EINVAL; | 148 | case RXRPC_UNBOUND: |
149 | goto error_unlock; | 149 | rx->srx = *srx; |
150 | } | 150 | local = rxrpc_lookup_local(sock_net(&rx->sk), &rx->srx); |
151 | 151 | if (IS_ERR(local)) { | |
152 | memcpy(&rx->srx, srx, sizeof(rx->srx)); | 152 | ret = PTR_ERR(local); |
153 | goto error_unlock; | ||
154 | } | ||
153 | 155 | ||
154 | local = rxrpc_lookup_local(sock_net(&rx->sk), &rx->srx); | 156 | if (service_id) { |
155 | if (IS_ERR(local)) { | 157 | write_lock(&local->services_lock); |
156 | ret = PTR_ERR(local); | 158 | if (rcu_access_pointer(local->service)) |
157 | goto error_unlock; | 159 | goto service_in_use; |
158 | } | 160 | rx->local = local; |
161 | rcu_assign_pointer(local->service, rx); | ||
162 | write_unlock(&local->services_lock); | ||
163 | |||
164 | rx->sk.sk_state = RXRPC_SERVER_BOUND; | ||
165 | } else { | ||
166 | rx->local = local; | ||
167 | rx->sk.sk_state = RXRPC_CLIENT_BOUND; | ||
168 | } | ||
169 | break; | ||
159 | 170 | ||
160 | if (service_id) { | 171 | case RXRPC_SERVER_BOUND: |
161 | write_lock(&local->services_lock); | 172 | ret = -EINVAL; |
162 | if (rcu_access_pointer(local->service)) | 173 | if (service_id == 0) |
163 | goto service_in_use; | 174 | goto error_unlock; |
164 | rx->local = local; | 175 | ret = -EADDRINUSE; |
165 | rcu_assign_pointer(local->service, rx); | 176 | if (service_id == rx->srx.srx_service) |
166 | write_unlock(&local->services_lock); | 177 | goto error_unlock; |
178 | ret = -EINVAL; | ||
179 | srx->srx_service = rx->srx.srx_service; | ||
180 | if (memcmp(srx, &rx->srx, sizeof(*srx)) != 0) | ||
181 | goto error_unlock; | ||
182 | rx->second_service = service_id; | ||
183 | rx->sk.sk_state = RXRPC_SERVER_BOUND2; | ||
184 | break; | ||
167 | 185 | ||
168 | rx->sk.sk_state = RXRPC_SERVER_BOUND; | 186 | default: |
169 | } else { | 187 | ret = -EINVAL; |
170 | rx->local = local; | 188 | goto error_unlock; |
171 | rx->sk.sk_state = RXRPC_CLIENT_BOUND; | ||
172 | } | 189 | } |
173 | 190 | ||
174 | release_sock(&rx->sk); | 191 | release_sock(&rx->sk); |
@@ -205,6 +222,7 @@ static int rxrpc_listen(struct socket *sock, int backlog) | |||
205 | ret = -EADDRNOTAVAIL; | 222 | ret = -EADDRNOTAVAIL; |
206 | break; | 223 | break; |
207 | case RXRPC_SERVER_BOUND: | 224 | case RXRPC_SERVER_BOUND: |
225 | case RXRPC_SERVER_BOUND2: | ||
208 | ASSERT(rx->local != NULL); | 226 | ASSERT(rx->local != NULL); |
209 | max = READ_ONCE(rxrpc_max_backlog); | 227 | max = READ_ONCE(rxrpc_max_backlog); |
210 | ret = -EINVAL; | 228 | ret = -EINVAL; |
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index de98a49adb35..781fbc253b5a 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h | |||
@@ -61,6 +61,7 @@ enum { | |||
61 | RXRPC_CLIENT_UNBOUND, /* Unbound socket used as client */ | 61 | RXRPC_CLIENT_UNBOUND, /* Unbound socket used as client */ |
62 | RXRPC_CLIENT_BOUND, /* client local address bound */ | 62 | RXRPC_CLIENT_BOUND, /* client local address bound */ |
63 | RXRPC_SERVER_BOUND, /* server local address bound */ | 63 | RXRPC_SERVER_BOUND, /* server local address bound */ |
64 | RXRPC_SERVER_BOUND2, /* second server local address bound */ | ||
64 | RXRPC_SERVER_LISTENING, /* server listening for connections */ | 65 | RXRPC_SERVER_LISTENING, /* server listening for connections */ |
65 | RXRPC_SERVER_LISTEN_DISABLED, /* server listening disabled */ | 66 | RXRPC_SERVER_LISTEN_DISABLED, /* server listening disabled */ |
66 | RXRPC_CLOSE, /* socket is being closed */ | 67 | RXRPC_CLOSE, /* socket is being closed */ |
@@ -142,6 +143,7 @@ struct rxrpc_sock { | |||
142 | u32 min_sec_level; /* minimum security level */ | 143 | u32 min_sec_level; /* minimum security level */ |
143 | #define RXRPC_SECURITY_MAX RXRPC_SECURITY_ENCRYPT | 144 | #define RXRPC_SECURITY_MAX RXRPC_SECURITY_ENCRYPT |
144 | bool exclusive; /* Exclusive connection for a client socket */ | 145 | bool exclusive; /* Exclusive connection for a client socket */ |
146 | u16 second_service; /* Additional service bound to the endpoint */ | ||
145 | sa_family_t family; /* Protocol family created with */ | 147 | sa_family_t family; /* Protocol family created with */ |
146 | struct sockaddr_rxrpc srx; /* local address */ | 148 | struct sockaddr_rxrpc srx; /* local address */ |
147 | struct sockaddr_rxrpc connect_srx; /* Default client address from connect() */ | 149 | struct sockaddr_rxrpc connect_srx; /* Default client address from connect() */ |
diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c index a8515b0d4717..544df53ccf79 100644 --- a/net/rxrpc/call_accept.c +++ b/net/rxrpc/call_accept.c | |||
@@ -341,7 +341,8 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local, | |||
341 | 341 | ||
342 | /* Get the socket providing the service */ | 342 | /* Get the socket providing the service */ |
343 | rx = rcu_dereference(local->service); | 343 | rx = rcu_dereference(local->service); |
344 | if (rx && service_id == rx->srx.srx_service) | 344 | if (rx && (service_id == rx->srx.srx_service || |
345 | service_id == rx->second_service)) | ||
345 | goto found_service; | 346 | goto found_service; |
346 | 347 | ||
347 | trace_rxrpc_abort("INV", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, | 348 | trace_rxrpc_abort("INV", sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, |
diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c index 17d79fd73ade..38b99db30e54 100644 --- a/net/rxrpc/local_object.c +++ b/net/rxrpc/local_object.c | |||
@@ -94,6 +94,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet, | |||
94 | rwlock_init(&local->services_lock); | 94 | rwlock_init(&local->services_lock); |
95 | local->debug_id = atomic_inc_return(&rxrpc_debug_id); | 95 | local->debug_id = atomic_inc_return(&rxrpc_debug_id); |
96 | memcpy(&local->srx, srx, sizeof(*srx)); | 96 | memcpy(&local->srx, srx, sizeof(*srx)); |
97 | local->srx.srx_service = 0; | ||
97 | } | 98 | } |
98 | 99 | ||
99 | _leave(" = %p", local); | 100 | _leave(" = %p", local); |
diff --git a/net/rxrpc/security.c b/net/rxrpc/security.c index b9f5dbbe0b8b..e9f428351293 100644 --- a/net/rxrpc/security.c +++ b/net/rxrpc/security.c | |||
@@ -133,7 +133,8 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn) | |||
133 | read_lock(&local->services_lock); | 133 | read_lock(&local->services_lock); |
134 | rx = rcu_dereference_protected(local->service, | 134 | rx = rcu_dereference_protected(local->service, |
135 | lockdep_is_held(&local->services_lock)); | 135 | lockdep_is_held(&local->services_lock)); |
136 | if (rx && rx->srx.srx_service == conn->service_id) | 136 | if (rx && (rx->srx.srx_service == conn->service_id || |
137 | rx->second_service == conn->service_id)) | ||
137 | goto found_service; | 138 | goto found_service; |
138 | 139 | ||
139 | /* the service appears to have died */ | 140 | /* the service appears to have died */ |