_HIGH-SPEED NETWORKING_ by William F. Jolitz [LISTING ONE] From file /sys/netinet/in_pcb.c: /* Find a internet protocol control block associated with a given session. * Session is determined as a match between foriegn (faddr, fport) and local * (laddr, lport) source/destionation identifiers. Allows wildcard matches * when some but not all of the parameters are known. */ struct inpcb * in_pcblookup(head, faddr, fport, laddr, lport, flags) struct inpcb *head; struct in_addr faddr, laddr; u_short fport, lport; int flags; { register struct inpcb *inp, *match = 0; int matchwild = 3, wildcard; for (inp = head->inp_next; inp != head; inp = inp->inp_next) { if (inp->inp_lport != lport) continue; wildcard = 0; if (inp->inp_laddr.s_addr != INADDR_ANY) { if (laddr.s_addr == INADDR_ANY) wildcard++; else if (inp->inp_laddr.s_addr != laddr.s_addr) continue; } else { if (laddr.s_addr != INADDR_ANY) wildcard++; } if (inp->inp_faddr.s_addr != INADDR_ANY) { if (faddr.s_addr == INADDR_ANY) wildcard++; else if (inp->inp_faddr.s_addr != faddr.s_addr || inp->inp_fport != fport) continue; } else { if (faddr.s_addr != INADDR_ANY) wildcard++; } if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) continue; if (wildcard < matchwild) { match = inp; matchwild = wildcard; if (matchwild == 0) break; } } return (match); } [LISTING TWO] From file:/sys/netinet/tcp_input.c ... /* * Locate pcb for segment. * */ findpcb: inp = tcp_last_inpcb; /* first, see if this segment looks familiar */ if (inp->inp_lport != ti->ti_dport || inp->inp_fport != ti->ti_sport || inp->inp_faddr.s_addr != ti->ti_src.s_addr || inp->inp_laddr.s_addr != ti->ti_dst.s_addr) { inp = in_pcblookup(&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD); if (inp) tcp_last_inpcb = inp; ++tcppcbcachemiss; } ... [LISTING THREE] From file:/sys/netinet/tcp_input.c: ... /* Header prediction: check for the two common cases of a unidirectional * data xfer. If the packet has no control flags, is in-sequence, the window * didn't change and we're not retransmitting, it's a candidate. If the length * is zero and the ack moved forward, we're the sender side of the xfer. Just * free the data acked & wake any higher level process that was blocked * waiting for space. If length is non-zero and the ack didn't move, we're the * receiver side. If we get packets in-order (the reassembly queue is empty), * add data to the socket buffer and note that we need a delayed ack. */ if (tp->t_state == TCPS_ESTABLISHED && (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && ti->ti_seq == tp->rcv_nxt && ti->ti_win && ti->ti_win == tp->snd_wnd && tp->snd_nxt == tp->snd_max) { if (ti->ti_len == 0) { if (SEQ_GT(ti->ti_ack, tp->snd_una) && SEQ_LEQ(ti->ti_ack, tp->snd_max) && tp->snd_cwnd >= tp->snd_wnd) { /* this is a pure ack for outstanding data. */ ++tcppredack; /* need to update round trip timers */ if (tp->t_rtt && SEQ_GT(ti->ti_ack,tp->t_rtseq)) tcp_xmit_timer(tp); /* free sent data that was acknowledged */ acked = ti->ti_ack - tp->snd_una; tcpstat.tcps_rcvackpack++; tcpstat.tcps_rcvackbyte += acked; sbdrop(&so->so_snd, acked); tp->snd_una = ti->ti_ack; /* free this packet */ m_freem(m); /* If all outstanding data are acked, stop * retransmit timer, otherwise restart timer * using current (possibly backed-off) value. * If process is waiting for space, * wakeup/selwakeup/signal. If data are ready * to send, let tcp_output decide between more * output or persist. */ if (tp->snd_una == tp->snd_max) tp->t_timer[TCPT_REXMT] = 0; else if (tp->t_timer[TCPT_PERSIST] == 0) tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; if (so->so_snd.sb_flags & SB_NOTIFY) sowwakeup(so); if (so->so_snd.sb_cc) (void) tcp_output(tp); return; } } else /* This is a pure, in-sequence data packet with nothing on the * reassembly queue; we have enough buffer space to take it. */ if (ti->ti_ack == tp->snd_una && tp->seg_next == (struct tcpiphdr *)tp && ti->ti_len <= sbspace(&so->so_rcv)) { /* update received state and statistics */ tp->rcv_nxt += ti->ti_len; ++tcppreddat; tcpstat.tcps_rcvpack++; tcpstat.tcps_rcvbyte += ti->ti_len; /* Deliver data by dropping TCP and IP headers, then * add data to application's socket buffer, and wakeup * application if necessary. */ m->m_data += sizeof(struct tcpiphdr); m->m_len -= sizeof(struct tcpiphdr); sbappend(&so->so_rcv, m); sorwakeup(so); /* request that a acknowledgement be sent with next * data packet outbound -- we delay in hopes of * "piggy backing" on top of a data packet. tp->t_flags |= TF_DELACK; return; } } ...