/* * We need both a handshake_req -> sock mapping, and a sock -> * handshake_req mapping. Both are one-to-one. * * To avoid adding another pointer field to struct sock, net/handshake * maintains a hash table, indexed by the memory address of @sock, to * find the struct handshake_req outstanding for that socket. The * reverse direction uses a simple pointer field in the handshake_req * struct.
*/
/* * Returns %true if the request was found on @net's pending list, * otherwise %false. * * If @req was on a pending list, it has not yet been accepted.
*/ staticbool remove_pending(struct handshake_net *hn, struct handshake_req *req)
{ bool ret = false;
spin_lock(&hn->hn_lock); if (!list_empty(&req->hr_list)) {
__remove_pending_locked(hn, req);
ret = true;
}
spin_unlock(&hn->hn_lock);
/** * handshake_req_submit - Submit a handshake request * @sock: open socket on which to perform the handshake * @req: handshake arguments * @flags: memory allocation flags * * Return values: * %0: Request queued * %-EINVAL: Invalid argument * %-EBUSY: A handshake is already under way for this socket * %-ESRCH: No handshake agent is available * %-EAGAIN: Too many pending handshake requests * %-ENOMEM: Failed to allocate memory * %-EMSGSIZE: Failed to construct notification message * %-EOPNOTSUPP: Handshake module not initialized * * A zero return value from handshake_req_submit() means that * exactly one subsequent completion callback is guaranteed. * * A negative return value from handshake_req_submit() means that * no completion callback will be done and that @req has been * destroyed.
*/ int handshake_req_submit(struct socket *sock, struct handshake_req *req,
gfp_t flags)
{ struct handshake_net *hn; struct net *net; int ret;
ret = -EOPNOTSUPP;
net = sock_net(req->hr_sk);
hn = handshake_pernet(net); if (!hn) goto out_err;
ret = -EAGAIN; if (READ_ONCE(hn->hn_pending) >= hn->hn_pending_max) goto out_err;
spin_lock(&hn->hn_lock);
ret = -EOPNOTSUPP; if (test_bit(HANDSHAKE_F_NET_DRAINING, &hn->hn_flags)) goto out_unlock;
ret = -EBUSY; if (!handshake_req_hash_add(req)) goto out_unlock; if (!__add_pending_locked(hn, req)) goto out_unlock;
spin_unlock(&hn->hn_lock);
ret = handshake_genl_notify(net, req->hr_proto, flags); if (ret) {
trace_handshake_notify_err(net, req, req->hr_sk, ret); if (remove_pending(hn, req)) goto out_err;
}
/* Prevent socket release while a handshake request is pending */
sock_hold(req->hr_sk);
/* Handshake request is no longer pending */
sock_put(sk);
}
}
EXPORT_SYMBOL_IF_KUNIT(handshake_complete);
/** * handshake_req_cancel - Cancel an in-progress handshake * @sk: socket on which there is an ongoing handshake * * Request cancellation races with request completion. To determine * who won, callers examine the return value from this function. * * Return values: * %true - Uncompleted handshake request was canceled * %false - Handshake request already completed or not found
*/ bool handshake_req_cancel(struct sock *sk)
{ struct handshake_req *req; struct handshake_net *hn; struct net *net;
net = sock_net(sk);
req = handshake_req_hash_lookup(sk); if (!req) {
trace_handshake_cancel_none(net, req, sk); returnfalse;
}
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.