if (addr->sa_family != AF_MCTP) return -EAFNOSUPPORT;
if (!capable(CAP_NET_BIND_SERVICE)) return -EACCES;
/* it's a valid sockaddr for MCTP, cast and do protocol checks */
smctp = (struct sockaddr_mctp *)addr;
if (!mctp_sockaddr_is_ok(smctp)) return -EINVAL;
lock_sock(sk);
if (sk_hashed(sk)) {
rc = -EADDRINUSE; goto out_release;
}
msk->bind_local_addr = smctp->smctp_addr.s_addr;
/* MCTP_NET_ANY with a specific EID is resolved to the default net * at bind() time. * For bind_addr=MCTP_ADDR_ANY it is handled specially at route * lookup time.
*/ if (smctp->smctp_network == MCTP_NET_ANY &&
msk->bind_local_addr != MCTP_ADDR_ANY) {
msk->bind_net = mctp_default_net(net);
} else {
msk->bind_net = smctp->smctp_network;
}
/* ignore the IC bit */
smctp->smctp_type &= 0x7f;
if (msk->bind_peer_set) { if (msk->bind_type != smctp->smctp_type) { /* Prior connect() had a different type */
rc = -EINVAL; goto out_release;
}
if (msk->bind_net == MCTP_NET_ANY) { /* Restrict to the network passed to connect() */
msk->bind_net = msk->bind_peer_net;
}
if (msk->bind_net != msk->bind_peer_net) { /* connect() had a different net to bind() */
rc = -EINVAL; goto out_release;
}
} else {
msk->bind_type = smctp->smctp_type;
}
rc = sk->sk_prot->hash(sk);
out_release:
release_sock(sk);
return rc;
}
/* Used to set a specific peer prior to bind. Not used for outbound * connections (Tag Owner set) since MCTP is a datagram protocol.
*/ staticint mctp_connect(struct socket *sock, struct sockaddr *addr, int addrlen, int flags)
{ struct sock *sk = sock->sk; struct mctp_sock *msk = container_of(sk, struct mctp_sock, sk); struct net *net = sock_net(&msk->sk); struct sockaddr_mctp *smctp; int rc;
if (addrlen != sizeof(*smctp)) return -EINVAL;
if (addr->sa_family != AF_MCTP) return -EAFNOSUPPORT;
/* It's a valid sockaddr for MCTP, cast and do protocol checks */
smctp = (struct sockaddr_mctp *)addr;
if (!mctp_sockaddr_is_ok(smctp)) return -EINVAL;
/* Can't bind by tag */ if (smctp->smctp_tag) return -EINVAL;
/* IC bit must be unset */ if (smctp->smctp_type & 0x80) return -EINVAL;
if (!hlist_unhashed(&key->hlist)) {
hlist_del_init(&key->hlist);
hlist_del_init(&key->sklist); /* unref for the lists */
mctp_key_unref(key);
}
kfree_skb(skb);
}
staticint mctp_setsockopt(struct socket *sock, int level, int optname,
sockptr_t optval, unsignedint optlen)
{ struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk); int val;
if (level != SOL_MCTP) return -EINVAL;
if (optname == MCTP_OPT_ADDR_EXT) { if (optlen != sizeof(int)) return -EINVAL; if (copy_from_sockptr(&val, optval, sizeof(int))) return -EFAULT;
msk->addr_ext = val; return 0;
}
return -ENOPROTOOPT;
}
staticint mctp_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{ struct mctp_sock *msk = container_of(sock->sk, struct mctp_sock, sk); int len, val;
if (level != SOL_MCTP) return -EINVAL;
if (get_user(len, optlen)) return -EFAULT;
if (optname == MCTP_OPT_ADDR_EXT) { if (len != sizeof(int)) return -EINVAL;
val = !!msk->addr_ext; if (copy_to_user(optval, &val, len)) return -EFAULT; return 0;
}
return -ENOPROTOOPT;
}
/* helpers for reading/writing the tag ioc, handling compatibility across the * two versions, and some basic API error checking
*/ staticint mctp_ioctl_tag_copy_from_user(unsignedlong arg, struct mctp_ioc_tag_ctl2 *ctl, bool tagv2)
{ struct mctp_ioc_tag_ctl ctl_compat; unsignedlong size; void *ptr; int rc;
ctl.tag = tag | MCTP_TAG_OWNER | MCTP_TAG_PREALLOC;
rc = mctp_ioctl_tag_copy_to_user(arg, &ctl, tagv2); if (rc) { unsignedlong fl2; /* Unwind our key allocation: the keys list lock needs to be * taken before the individual key locks, and we need a valid * flags value (fl2) to pass to __mctp_key_remove, hence the * second spin_lock_irqsave() rather than a plain spin_lock().
*/
spin_lock_irqsave(&net->mctp.keys_lock, flags);
spin_lock_irqsave(&key->lock, fl2);
__mctp_key_remove(key, net, fl2, MCTP_TRACE_KEY_DROPPED);
mctp_key_unref(key);
spin_unlock_irqrestore(&net->mctp.keys_lock, flags); return rc;
}
rc = mctp_ioctl_tag_copy_from_user(arg, &ctl, tagv2); if (rc) return rc;
/* Must be a local tag, TO set, preallocated */ if ((ctl.tag & ~MCTP_TAG_MASK) != (MCTP_TAG_OWNER | MCTP_TAG_PREALLOC)) return -EINVAL;
tag = ctl.tag & MCTP_TAG_MASK;
rc = -EINVAL;
if (ctl.peer_addr == MCTP_ADDR_NULL)
ctl.peer_addr = MCTP_ADDR_ANY;
spin_lock_irqsave(&net->mctp.keys_lock, flags);
hlist_for_each_entry_safe(key, tmp, &msk->keys, sklist) { /* we do an irqsave here, even though we know the irq state, * so we have the flags to pass to __mctp_key_remove
*/
spin_lock_irqsave(&key->lock, fl2); if (key->manual_alloc &&
ctl.net == key->net &&
ctl.peer_addr == key->peer_addr &&
tag == key->tag) {
__mctp_key_remove(key, net, fl2,
MCTP_TRACE_KEY_DROPPED);
rc = 0;
} else {
spin_unlock_irqrestore(&key->lock, fl2);
}
}
spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
switch (cmd) { /* These have compatible ptr layouts */ case SIOCMCTPALLOCTAG: case SIOCMCTPDROPTAG: return mctp_ioctl(sock, cmd, (unsignedlong)argp);
}
/* Since there are no more tag allocations (we have removed all of the * keys), stop any pending expiry events. the timer cannot be re-queued * as the sk is no longer observable
*/
timer_delete_sync(&msk->key_expiry);
}
staticint mctp_pf_create(struct net *net, struct socket *sock, int protocol, int kern)
{ conststruct proto_ops *ops; struct proto *proto; struct sock *sk; int rc;
if (protocol) return -EPROTONOSUPPORT;
/* only datagram sockets are supported */ if (sock->type != SOCK_DGRAM) return -ESOCKTNOSUPPORT;
proto = &mctp_proto;
ops = &mctp_dgram_ops;
sock->state = SS_UNCONNECTED;
sock->ops = ops;
sk = sk_alloc(net, PF_MCTP, GFP_KERNEL, proto, kern); if (!sk) return -ENOMEM;
/* ensure our uapi tag definitions match the header format */
BUILD_BUG_ON(MCTP_TAG_OWNER != MCTP_HDR_FLAG_TO);
BUILD_BUG_ON(MCTP_TAG_MASK != MCTP_HDR_TAG_MASK);
pr_info("mctp: management component transport protocol core\n");
rc = sock_register(&mctp_pf); if (rc) return rc;
rc = proto_register(&mctp_proto, 0); if (rc) goto err_unreg_sock;
rc = mctp_routes_init(); if (rc) goto err_unreg_proto;
rc = mctp_neigh_init(); if (rc) goto err_unreg_routes;
rc = mctp_device_init(); if (rc) goto err_unreg_neigh;
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.