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 *scopeIDastheconnectedaddress,exceptthecasewhenoneis *non-linklocaladdress(scope_idis0).
*/ 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 *socketisbound.
*/ 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.