static struct rx_packet
*rxi_ReceiveDataPacket(struct rx_call *call, struct rx_packet *np,
int istack, osi_socket socket,
- afs_uint32 host, u_short port, int *tnop,
- struct rx_call **newcallp);
+ int *tnop, struct rx_call **newcallp);
static struct rx_packet
*rxi_ReceiveAckPacket(struct rx_call *call, struct rx_packet *np,
int istack, int *a_invalid);
MUTEX_ENTER(&rx_quota_mutex);
rxi_dataQuota += rx_extraQuota; /* + extra pkts caller asked to rsrv */
MUTEX_EXIT(&rx_quota_mutex);
- /* *Slightly* random start time for the cid. This is just to help
- * out with the hashing function at the peer */
- rx_nextCid = ((tv.tv_sec ^ tv.tv_usec) << RX_CIDSHIFT);
rx_connHashTable = (struct rx_connection **)htable;
rx_peerHashTable = (struct rx_peer **)ptable;
return pp;
}
+static_inline int
+rxi_ConnectionMatch(struct rx_connection *conn,
+ afs_uint32 host, u_short port, afs_uint32 cid,
+ afs_uint32 epoch, int type, u_int securityIndex,
+ int *a_badSecurityIndex)
+{
+ struct rx_peer *pp;
+ if (conn->type != type) {
+ return 0;
+ }
+ if (conn->cid != (cid & RX_CIDMASK)) {
+ return 0;
+ }
+ if (conn->epoch != epoch) {
+ return 0;
+ }
+ if (conn->securityIndex != securityIndex) {
+ if (a_badSecurityIndex) {
+ *a_badSecurityIndex = 1;
+ }
+ return 0;
+ }
+ pp = conn->peer;
+ if (pp->host == host && pp->port == port) {
+ return 1;
+ }
+ if (type == RX_CLIENT_CONNECTION && pp->port == port) {
+ /* For client conns, we allow packets from any host to be associated
+ * with the conn. */
+ return 1;
+ }
+ if ((conn->epoch & 0x80000000)) {
+ /* If the epoch high bit is set, we ignore the host/port of any packets
+ * coming in for the conn. */
+ return 1;
+ }
+ return 0;
+}
/* Find the connection at (host, port) started at epoch, and with the
* given connection id. Creates the server connection if necessary.
rx_connHashTable[hashindex],
flag = 1);
for (; conn;) {
- if ((conn->type == type) && ((cid & RX_CIDMASK) == conn->cid)
- && (epoch == conn->epoch)) {
- struct rx_peer *pp = conn->peer;
- if (securityIndex != conn->securityIndex) {
- /* this isn't supposed to happen, but someone could forge a packet
- * like this, and there seems to be some CM bug that makes this
- * happen from time to time -- in which case, the fileserver
- * asserts. */
- MUTEX_EXIT(&rx_connHashTable_lock);
- return (struct rx_connection *)0;
- }
- if (pp->host == host && pp->port == port)
- break;
- if (type == RX_CLIENT_CONNECTION && pp->port == port)
- break;
- /* So what happens when it's a callback connection? */
- if ( /*type == RX_CLIENT_CONNECTION && */
- (conn->epoch & 0x80000000))
- break;
+ int bad_sec = 0;
+ if (rxi_ConnectionMatch(conn, host, port, cid, epoch, type,
+ securityIndex, &bad_sec)) {
+ break;
+ }
+ if (bad_sec) {
+ /*
+ * This isn't supposed to happen, but someone could forge a packet
+ * like this, and bugs causing such packets are not unheard of.
+ */
+ MUTEX_EXIT(&rx_connHashTable_lock);
+ return NULL;
}
if (!flag) {
/* the connection rxLastConn that was used the last time is not the
call = conn->call[channel];
if (!call) {
+ if (np->header.type != RX_PACKET_TYPE_DATA) {
+ /*
+ * Clients must send DATA packets at some point to create a new
+ * call. If the first packet we saw for this call channel is
+ * something else, then either the DATA packets got lost/delayed,
+ * or we were restarted and this is an existing call from before we
+ * were restarted. In the latter case, some clients get confused if
+ * we respond to such requests, so just drop the packet to make
+ * things easier for them.
+ */
+ MUTEX_EXIT(&conn->conn_call_lock);
+ if (rx_stats_active)
+ rx_atomic_inc(&rx_stats.spuriousPacketsRead);
+ return NULL;
+ }
+
+ if (np->header.seq > rx_maxReceiveWindow) {
+ /*
+ * This is a DATA packet for further along in the call than is
+ * possible for a new call. This is probably from an existing call
+ * that was in the middle of running when we were restarted; ignore
+ * it to avoid confusing clients. (See above comment about non-DATA
+ * packets.)
+ */
+ MUTEX_EXIT(&conn->conn_call_lock);
+ if (rx_stats_active)
+ rx_atomic_inc(&rx_stats.spuriousPacketsRead);
+ return NULL;
+ }
+
if (rxi_AbortIfServerBusy(socket, conn, np)) {
MUTEX_EXIT(&conn->conn_call_lock);
return NULL;
if (type == RX_CLIENT_CONNECTION && !opr_queue_IsEmpty(&call->tq))
rxi_AckAllInTransmitQueue(call);
- np = rxi_ReceiveDataPacket(call, np, 1, socket, host, port, tnop,
- newcallp);
+ np = rxi_ReceiveDataPacket(call, np, 1, socket, tnop, newcallp);
break;
case RX_PACKET_TYPE_ACK:
/* Respond immediately to ack packets requesting acknowledgement
static struct rx_packet *
rxi_ReceiveDataPacket(struct rx_call *call,
struct rx_packet *np, int istack,
- osi_socket socket, afs_uint32 host, u_short port,
- int *tnop, struct rx_call **newcallp)
+ osi_socket socket, int *tnop, struct rx_call **newcallp)
{
int ackNeeded = 0; /* 0 means no, otherwise ack_reason */
int newPackets = 0;
/* The RX_JUMBO_PACKET is set in all but the last packet in each
* AFS 3.5 jumbogram. */
if (flags & RX_JUMBO_PACKET) {
- tnp = rxi_SplitJumboPacket(np, host, port, isFirst);
+ tnp = rxi_SplitJumboPacket(np);
} else {
tnp = NULL;
}
{
/* Overflow is technically undefined behavior; avoid it. */
if (rx_nextCid > MAX_AFS_INT32 - (1 << RX_CIDSHIFT))
- rx_nextCid = -1 * ((MAX_AFS_INT32 / RX_CIDSHIFT) * RX_CIDSHIFT);
- else
- rx_nextCid += 1 << RX_CIDSHIFT;
+ rx_nextCid = 0;
+ rx_nextCid += 1 << RX_CIDSHIFT;
}
static void