/* * accept an incoming call that needs peer, transport and/or connection setting * up */ static int rxrpc_accept_incoming_call(struct rxrpc_local *local, struct rxrpc_sock *rx, struct sk_buff *skb, struct sockaddr_rxrpc *srx) { struct rxrpc_connection *conn; struct rxrpc_transport *trans; struct rxrpc_skb_priv *sp, *nsp; struct rxrpc_peer *peer; struct rxrpc_call *call; struct sk_buff *notification; int ret; _enter(""); sp = rxrpc_skb(skb); /* get a notification message to send to the server app */ notification = alloc_skb(0, GFP_NOFS); rxrpc_new_skb(notification); notification->mark = RXRPC_SKB_MARK_NEW_CALL; peer = rxrpc_get_peer(srx, GFP_NOIO); if (IS_ERR(peer)) { _debug("no peer"); ret = -EBUSY; goto error; } trans = rxrpc_get_transport(local, peer, GFP_NOIO); rxrpc_put_peer(peer); if (!trans) { _debug("no trans"); ret = -EBUSY; goto error; } conn = rxrpc_incoming_connection(trans, &sp->hdr, GFP_NOIO); rxrpc_put_transport(trans); if (IS_ERR(conn)) { _debug("no conn"); ret = PTR_ERR(conn); goto error; } call = rxrpc_incoming_call(rx, conn, &sp->hdr, GFP_NOIO); rxrpc_put_connection(conn); if (IS_ERR(call)) { _debug("no call"); ret = PTR_ERR(call); goto error; } /* attach the call to the socket */ read_lock_bh(&local->services_lock); if (rx->sk.sk_state == RXRPC_CLOSE) goto invalid_service; write_lock(&rx->call_lock); if (!test_and_set_bit(RXRPC_CALL_INIT_ACCEPT, &call->flags)) { rxrpc_get_call(call); spin_lock(&call->conn->state_lock); if (sp->hdr.securityIndex > 0 && call->conn->state == RXRPC_CONN_SERVER_UNSECURED) { _debug("await conn sec"); list_add_tail(&call->accept_link, &rx->secureq); call->conn->state = RXRPC_CONN_SERVER_CHALLENGING; atomic_inc(&call->conn->usage); set_bit(RXRPC_CONN_CHALLENGE, &call->conn->events); rxrpc_queue_conn(call->conn); } else { _debug("conn ready"); call->state = RXRPC_CALL_SERVER_ACCEPTING; list_add_tail(&call->accept_link, &rx->acceptq); rxrpc_get_call(call); nsp = rxrpc_skb(notification); nsp->call = call; ASSERTCMP(atomic_read(&call->usage), >=, 3); _debug("notify"); spin_lock(&call->lock); ret = rxrpc_queue_rcv_skb(call, notification, true, false); spin_unlock(&call->lock); notification = NULL; if (ret < 0) BUG(); } spin_unlock(&call->conn->state_lock); _debug("queued"); }
/* * Allocate a new incoming call from the prealloc pool, along with a connection * and a peer as necessary. */ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx, struct rxrpc_local *local, struct rxrpc_connection *conn, struct sk_buff *skb) { struct rxrpc_backlog *b = rx->backlog; struct rxrpc_peer *peer, *xpeer; struct rxrpc_call *call; unsigned short call_head, conn_head, peer_head; unsigned short call_tail, conn_tail, peer_tail; unsigned short call_count, conn_count; /* #calls >= #conns >= #peers must hold true. */ call_head = smp_load_acquire(&b->call_backlog_head); call_tail = b->call_backlog_tail; call_count = CIRC_CNT(call_head, call_tail, RXRPC_BACKLOG_MAX); conn_head = smp_load_acquire(&b->conn_backlog_head); conn_tail = b->conn_backlog_tail; conn_count = CIRC_CNT(conn_head, conn_tail, RXRPC_BACKLOG_MAX); ASSERTCMP(conn_count, >=, call_count); peer_head = smp_load_acquire(&b->peer_backlog_head); peer_tail = b->peer_backlog_tail; ASSERTCMP(CIRC_CNT(peer_head, peer_tail, RXRPC_BACKLOG_MAX), >=, conn_count); if (call_count == 0) return NULL; if (!conn) { /* No connection. We're going to need a peer to start off * with. If one doesn't yet exist, use a spare from the * preallocation set. We dump the address into the spare in * anticipation - and to save on stack space. */ xpeer = b->peer_backlog[peer_tail]; if (rxrpc_extract_addr_from_skb(&xpeer->srx, skb) < 0) return NULL; peer = rxrpc_lookup_incoming_peer(local, xpeer); if (peer == xpeer) { b->peer_backlog[peer_tail] = NULL; smp_store_release(&b->peer_backlog_tail, (peer_tail + 1) & (RXRPC_BACKLOG_MAX - 1)); } /* Now allocate and set up the connection */ conn = b->conn_backlog[conn_tail]; b->conn_backlog[conn_tail] = NULL; smp_store_release(&b->conn_backlog_tail, (conn_tail + 1) & (RXRPC_BACKLOG_MAX - 1)); rxrpc_get_local(local); conn->params.local = local; conn->params.peer = peer; rxrpc_see_connection(conn); rxrpc_new_incoming_connection(rx, conn, skb); } else { rxrpc_get_connection(conn); } /* And now we can allocate and set up a new call */ call = b->call_backlog[call_tail]; b->call_backlog[call_tail] = NULL; smp_store_release(&b->call_backlog_tail, (call_tail + 1) & (RXRPC_BACKLOG_MAX - 1)); rxrpc_see_call(call); call->conn = conn; call->peer = rxrpc_get_peer(conn->params.peer); call->cong_cwnd = call->peer->cong_cwnd; return call; }