net/rds/bind.c

Source file repositories/reference/linux-study-clean/net/rds/bind.c

File Facts

System
Linux kernel
Corpus path
net/rds/bind.c
Extension
.c
Size
7900 bytes
Lines
284
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

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;

out:
	release_sock(sk);
	return ret;
}

void rds_bind_lock_destroy(void)
{
	rhashtable_destroy(&bind_hash_table);
}

int rds_bind_lock_init(void)
{
	return rhashtable_init(&bind_hash_table, &ht_parms);
}

Annotation

Implementation Notes