/* * Copyright (c) 2006, 2019 Oracle and/or its affiliates. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *
*/ #include <linux/kernel.h> #include <net/sock.h> #include <linux/in.h> #include <linux/ipv6.h> #include <linux/if_arp.h> #include <linux/jhash.h> #include <linux/ratelimit.h> #include"rds.h"
/* Create a key for the bind hash table manipulation. Port is in network byte * order.
*/ staticinlinevoid __rds_create_bind_key(u8 *key, conststruct in6_addr *addr,
__be16 port, __u32 scope_id)
{
memcpy(key, addr, sizeof(*addr));
key += sizeof(*addr);
memcpy(key, &port, sizeof(port));
key += sizeof(port);
memcpy(key, &scope_id, sizeof(scope_id));
}
/* * Return the rds_sock bound at the given local address. * * The rx path can race with rds_release. We notice if rds_release() has * marked this socket and don't return a rs ref to the rx path.
*/ struct rds_sock *rds_find_bound(conststruct in6_addr *addr, __be16 port,
__u32 scope_id)
{
u8 key[RDS_BOUND_KEY_LEN]; struct rds_sock *rs;
int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{ struct sock *sk = sock->sk; struct rds_sock *rs = rds_sk_to_rs(sk); struct in6_addr v6addr, *binding_addr; struct rds_transport *trans;
__u32 scope_id = 0; int ret = 0;
__be16 port;
/* We allow an RDS socket to be bound to either IPv4 or IPv6 * address.
*/ if (addr_len < offsetofend(struct sockaddr, sa_family)) return -EINVAL; if (uaddr->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
if (addr_len < sizeof(struct sockaddr_in6)) return -EINVAL;
addr_type = ipv6_addr_type(&sin6->sin6_addr); if (!(addr_type & IPV6_ADDR_UNICAST)) {
__be32 addr4;
if (!(addr_type & IPV6_ADDR_MAPPED)) return -EINVAL;
/* It is a mapped address. Need to do some sanity * checks.
*/
addr4 = sin6->sin6_addr.s6_addr32[3]; if (addr4 == htonl(INADDR_ANY) ||
addr4 == htonl(INADDR_BROADCAST) ||
ipv4_is_multicast(addr4)) return -EINVAL;
} /* The scope ID must be specified for link local address. */ if (addr_type & IPV6_ADDR_LINKLOCAL) { if (sin6->sin6_scope_id == 0) return -EINVAL;
scope_id = sin6->sin6_scope_id;
}
binding_addr = &sin6->sin6_addr;
port = sin6->sin6_port; #endif
} else { return -EINVAL;
}
lock_sock(sk);
/* RDS socket does not allow re-binding. */ if (!ipv6_addr_any(&rs->rs_bound_addr)) {
ret = -EINVAL; goto out;
} /* Socket is connected. The binding address should have the same * scope ID as the connected address, except the case when one is * non-link local address (scope_id is 0).
*/ if (!ipv6_addr_any(&rs->rs_conn_addr) && scope_id &&
rs->rs_bound_scope_id &&
scope_id != rs->rs_bound_scope_id) {
ret = -EINVAL; goto out;
}
/* The transport can be set using SO_RDS_TRANSPORT option before the * socket is bound.
*/ if (rs->rs_transport) {
trans = rs->rs_transport; if (!trans->laddr_check ||
trans->laddr_check(sock_net(sock->sk),
binding_addr, scope_id) != 0) {
ret = -ENOPROTOOPT; goto out;
}
} else {
trans = rds_trans_get_preferred(sock_net(sock->sk),
binding_addr, scope_id); if (!trans) {
ret = -EADDRNOTAVAIL;
pr_info_ratelimited("RDS: %s could not find a transport for %pI6c, load rds_tcp or rds_rdma?\n",
__func__, binding_addr); goto out;
}
rs->rs_transport = trans;
}
sock_set_flag(sk, SOCK_RCU_FREE);
ret = rds_add_bound(rs, binding_addr, &port, scope_id); if (ret)
rs->rs_transport = NULL;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.