transport.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 865 行 · 第 1/2 页
C
865 行
_leave(" = 0 #%d", atomic_read(&rxrpc_message_count)); return 0; error: while (!list_empty(msgq)) { msg = list_entry(msgq->next, struct rxrpc_message, link); list_del_init(&msg->link); rxrpc_put_message(msg); } _leave(" = %d", ret); return ret;} /* end rxrpc_incoming_msg() *//*****************************************************************************//* * accept a new call * - called from krxiod in process context */void rxrpc_trans_receive_packet(struct rxrpc_transport *trans){ struct rxrpc_message *msg; struct rxrpc_peer *peer; struct sk_buff *pkt; int ret; __be32 addr; __be16 port; LIST_HEAD(msgq); _enter("%p{%d}", trans, trans->port); for (;;) { /* deal with outstanting errors first */ if (trans->error_rcvd) rxrpc_trans_receive_error_report(trans); /* attempt to receive a packet */ pkt = skb_recv_datagram(trans->socket->sk, 0, 1, &ret); if (!pkt) { if (ret == -EAGAIN) { _leave(" EAGAIN"); return; } /* an icmp error may have occurred */ rxrpc_krxiod_queue_transport(trans); _leave(" error %d\n", ret); return; } /* we'll probably need to checksum it (didn't call * sock_recvmsg) */ if (pkt->ip_summed != CHECKSUM_UNNECESSARY) { if ((unsigned short) csum_fold(skb_checksum(pkt, 0, pkt->len, pkt->csum))) { kfree_skb(pkt); rxrpc_krxiod_queue_transport(trans); _leave(" CSUM failed"); return; } } addr = pkt->nh.iph->saddr; port = pkt->h.uh->source; _net("Rx Received UDP packet from %08x:%04hu", ntohl(addr), ntohs(port)); /* unmarshall the Rx parameters and split jumbo packets */ ret = rxrpc_incoming_msg(trans, pkt, &msgq); if (ret < 0) { kfree_skb(pkt); rxrpc_krxiod_queue_transport(trans); _leave(" bad packet"); return; } BUG_ON(list_empty(&msgq)); msg = list_entry(msgq.next, struct rxrpc_message, link); /* locate the record for the peer from which it * originated */ ret = rxrpc_peer_lookup(trans, addr, &peer); if (ret < 0) { kdebug("Rx No connections from that peer"); rxrpc_trans_immediate_abort(trans, msg, -EINVAL); goto finished_msg; } /* try and find a matching connection */ ret = rxrpc_connection_lookup(peer, msg, &msg->conn); if (ret < 0) { kdebug("Rx Unknown Connection"); rxrpc_trans_immediate_abort(trans, msg, -EINVAL); rxrpc_put_peer(peer); goto finished_msg; } rxrpc_put_peer(peer); /* deal with the first packet of a new call */ if (msg->hdr.flags & RXRPC_CLIENT_INITIATED && msg->hdr.type == RXRPC_PACKET_TYPE_DATA && ntohl(msg->hdr.seq) == 1 ) { _debug("Rx New server call"); rxrpc_trans_receive_new_call(trans, &msgq); goto finished_msg; } /* deal with subsequent packet(s) of call */ _debug("Rx Call packet"); while (!list_empty(&msgq)) { msg = list_entry(msgq.next, struct rxrpc_message, link); list_del_init(&msg->link); ret = rxrpc_conn_receive_call_packet(msg->conn, NULL, msg); if (ret < 0) { rxrpc_trans_immediate_abort(trans, msg, ret); rxrpc_put_message(msg); goto finished_msg; } rxrpc_put_message(msg); } goto finished_msg; /* dispose of the packets */ finished_msg: while (!list_empty(&msgq)) { msg = list_entry(msgq.next, struct rxrpc_message, link); list_del_init(&msg->link); rxrpc_put_message(msg); } kfree_skb(pkt); } _leave("");} /* end rxrpc_trans_receive_packet() *//*****************************************************************************//* * accept a new call from a client trying to connect to one of my services * - called in process context */static int rxrpc_trans_receive_new_call(struct rxrpc_transport *trans, struct list_head *msgq){ struct rxrpc_message *msg; _enter(""); /* only bother with the first packet */ msg = list_entry(msgq->next, struct rxrpc_message, link); list_del_init(&msg->link); rxrpc_krxsecd_queue_incoming_call(msg); rxrpc_put_message(msg); _leave(" = 0"); return 0;} /* end rxrpc_trans_receive_new_call() *//*****************************************************************************//* * perform an immediate abort without connection or call structures */int rxrpc_trans_immediate_abort(struct rxrpc_transport *trans, struct rxrpc_message *msg, int error){ struct rxrpc_header ahdr; struct sockaddr_in sin; struct msghdr msghdr; struct kvec iov[2]; __be32 _error; int len, ret; _enter("%p,%p,%d", trans, msg, error); /* don't abort an abort packet */ if (msg->hdr.type == RXRPC_PACKET_TYPE_ABORT) { _leave(" = 0"); return 0; } _error = htonl(-error); /* set up the message to be transmitted */ memcpy(&ahdr, &msg->hdr, sizeof(ahdr)); ahdr.epoch = msg->hdr.epoch; ahdr.serial = htonl(1); ahdr.seq = 0; ahdr.type = RXRPC_PACKET_TYPE_ABORT; ahdr.flags = RXRPC_LAST_PACKET; ahdr.flags |= ~msg->hdr.flags & RXRPC_CLIENT_INITIATED; iov[0].iov_len = sizeof(ahdr); iov[0].iov_base = &ahdr; iov[1].iov_len = sizeof(_error); iov[1].iov_base = &_error; len = sizeof(ahdr) + sizeof(_error); memset(&sin,0,sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = msg->pkt->h.uh->source; sin.sin_addr.s_addr = msg->pkt->nh.iph->saddr; msghdr.msg_name = &sin; msghdr.msg_namelen = sizeof(sin); msghdr.msg_control = NULL; msghdr.msg_controllen = 0; msghdr.msg_flags = MSG_DONTWAIT; _net("Sending message type %d of %d bytes to %08x:%d", ahdr.type, len, ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port)); /* send the message */ ret = kernel_sendmsg(trans->socket, &msghdr, iov, 2, len); _leave(" = %d", ret); return ret;} /* end rxrpc_trans_immediate_abort() *//*****************************************************************************//* * receive an ICMP error report and percolate it to all connections * heading to the affected host or port */static void rxrpc_trans_receive_error_report(struct rxrpc_transport *trans){ struct rxrpc_connection *conn; struct sockaddr_in sin; struct rxrpc_peer *peer; struct list_head connq, *_p; struct errormsg emsg; struct msghdr msg; __be16 port; int local, err; _enter("%p", trans); for (;;) { trans->error_rcvd = 0; /* try and receive an error message */ msg.msg_name = &sin; msg.msg_namelen = sizeof(sin); msg.msg_control = &emsg; msg.msg_controllen = sizeof(emsg); msg.msg_flags = 0; err = kernel_recvmsg(trans->socket, &msg, NULL, 0, 0, MSG_ERRQUEUE | MSG_DONTWAIT | MSG_TRUNC); if (err == -EAGAIN) { _leave(""); return; } if (err < 0) { printk("%s: unable to recv an error report: %d\n", __FUNCTION__, err); _leave(""); return; } msg.msg_controllen = (char *) msg.msg_control - (char *) &emsg; if (msg.msg_controllen < sizeof(emsg.cmsg) || msg.msg_namelen < sizeof(sin)) { printk("%s: short control message" " (nlen=%u clen=%Zu fl=%x)\n", __FUNCTION__, msg.msg_namelen, msg.msg_controllen, msg.msg_flags); continue; } _net("Rx Received control message" " { len=%Zu level=%u type=%u }", emsg.cmsg.cmsg_len, emsg.cmsg.cmsg_level, emsg.cmsg.cmsg_type); if (sin.sin_family != AF_INET) { printk("Rx Ignoring error report with non-INET address" " (fam=%u)", sin.sin_family); continue; } _net("Rx Received message pertaining to host addr=%x port=%hu", ntohl(sin.sin_addr.s_addr), ntohs(sin.sin_port)); if (emsg.cmsg.cmsg_level != SOL_IP || emsg.cmsg.cmsg_type != IP_RECVERR) { printk("Rx Ignoring unknown error report" " { level=%u type=%u }", emsg.cmsg.cmsg_level, emsg.cmsg.cmsg_type); continue; } if (msg.msg_controllen < sizeof(emsg.cmsg) + sizeof(emsg.ee)) { printk("%s: short error message (%Zu)\n", __FUNCTION__, msg.msg_controllen); _leave(""); return; } port = sin.sin_port; switch (emsg.ee.ee_origin) { case SO_EE_ORIGIN_ICMP: local = 0; switch (emsg.ee.ee_type) { case ICMP_DEST_UNREACH: switch (emsg.ee.ee_code) { case ICMP_NET_UNREACH: _net("Rx Received ICMP Network Unreachable"); port = 0; err = -ENETUNREACH; break; case ICMP_HOST_UNREACH: _net("Rx Received ICMP Host Unreachable"); port = 0; err = -EHOSTUNREACH; break; case ICMP_PORT_UNREACH: _net("Rx Received ICMP Port Unreachable"); err = -ECONNREFUSED; break; case ICMP_NET_UNKNOWN: _net("Rx Received ICMP Unknown Network"); port = 0; err = -ENETUNREACH; break; case ICMP_HOST_UNKNOWN: _net("Rx Received ICMP Unknown Host"); port = 0; err = -EHOSTUNREACH; break; default: _net("Rx Received ICMP DestUnreach { code=%u }", emsg.ee.ee_code); err = emsg.ee.ee_errno; break; } break; case ICMP_TIME_EXCEEDED: _net("Rx Received ICMP TTL Exceeded"); err = emsg.ee.ee_errno; break; default: _proto("Rx Received ICMP error { type=%u code=%u }", emsg.ee.ee_type, emsg.ee.ee_code); err = emsg.ee.ee_errno; break; } break; case SO_EE_ORIGIN_LOCAL: _proto("Rx Received local error { error=%d }", emsg.ee.ee_errno); local = 1; err = emsg.ee.ee_errno; break; case SO_EE_ORIGIN_NONE: case SO_EE_ORIGIN_ICMP6: default: _proto("Rx Received error report { orig=%u }", emsg.ee.ee_origin); local = 0; err = emsg.ee.ee_errno; break; } /* find all the connections between this transport and the * affected destination */ INIT_LIST_HEAD(&connq); if (rxrpc_peer_lookup(trans, sin.sin_addr.s_addr, &peer) == 0) { read_lock(&peer->conn_lock); list_for_each(_p, &peer->conn_active) { conn = list_entry(_p, struct rxrpc_connection, link); if (port && conn->addr.sin_port != port) continue; if (!list_empty(&conn->err_link)) continue; rxrpc_get_connection(conn); list_add_tail(&conn->err_link, &connq); } read_unlock(&peer->conn_lock); /* service all those connections */ while (!list_empty(&connq)) { conn = list_entry(connq.next, struct rxrpc_connection, err_link); list_del(&conn->err_link); rxrpc_conn_handle_error(conn, local, err); rxrpc_put_connection(conn); } rxrpc_put_peer(peer); } } _leave(""); return;} /* end rxrpc_trans_receive_error_report() */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?