/* * 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"); }
/* * Rx I/O daemon */ static int rxrpc_krxiod(void *arg) { DECLARE_WAITQUEUE(krxiod,current); printk("Started krxiod %d\n",current->pid); daemonize("krxiod"); /* loop around waiting for work to do */ do { /* wait for work or to be told to exit */ _debug("### Begin Wait"); if (!atomic_read(&rxrpc_krxiod_qcount)) { set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&rxrpc_krxiod_sleepq, &krxiod); for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (atomic_read(&rxrpc_krxiod_qcount) || rxrpc_krxiod_die || signal_pending(current)) break; schedule(); } remove_wait_queue(&rxrpc_krxiod_sleepq, &krxiod); set_current_state(TASK_RUNNING); } _debug("### End Wait"); /* do work if been given some to do */ _debug("### Begin Work"); /* see if there's a transport in need of attention */ if (!list_empty(&rxrpc_krxiod_transportq)) { struct rxrpc_transport *trans = NULL; spin_lock_irq(&rxrpc_krxiod_transportq_lock); if (!list_empty(&rxrpc_krxiod_transportq)) { trans = list_entry( rxrpc_krxiod_transportq.next, struct rxrpc_transport, krxiodq_link); list_del_init(&trans->krxiodq_link); atomic_dec(&rxrpc_krxiod_qcount); /* make sure it hasn't gone away and doesn't go * away */ if (atomic_read(&trans->usage)>0) rxrpc_get_transport(trans); else trans = NULL; } spin_unlock_irq(&rxrpc_krxiod_transportq_lock); if (trans) { rxrpc_trans_receive_packet(trans); rxrpc_put_transport(trans); } } /* see if there's a call in need of attention */ if (!list_empty(&rxrpc_krxiod_callq)) { struct rxrpc_call *call = NULL; spin_lock_irq(&rxrpc_krxiod_callq_lock); if (!list_empty(&rxrpc_krxiod_callq)) { call = list_entry(rxrpc_krxiod_callq.next, struct rxrpc_call, rcv_krxiodq_lk); list_del_init(&call->rcv_krxiodq_lk); atomic_dec(&rxrpc_krxiod_qcount); /* make sure it hasn't gone away and doesn't go * away */ if (atomic_read(&call->usage) > 0) { _debug("@@@ KRXIOD" " Begin Attend Call %p", call); rxrpc_get_call(call); } else { call = NULL; } } spin_unlock_irq(&rxrpc_krxiod_callq_lock); if (call) { rxrpc_call_do_stuff(call); rxrpc_put_call(call); _debug("@@@ KRXIOD End Attend Call %p", call); } }