+ ti = mtod(m, struct tcpiphdr *);
+ }
+
+ /*
+ * Checksum extended TCP header and data.
+ */
+ tlen = ((struct ip *)ti)->ip_len;
+ len = sizeof (struct ip) + tlen;
+ if (tcpcksum) {
+ ti->ti_next = ti->ti_prev = 0;
+ ti->ti_x1 = 0;
+ ti->ti_len = (u_short)tlen;
+ ti->ti_len = htons((u_short)ti->ti_len);
+ if (ti->ti_sum = in_cksum(m, len)) {
+ tcpstat.tcps_badsum++;
+ if (tcpprintfs)
+ printf("tcp cksum %x\n", ti->ti_sum);
+ goto drop;
+ }
+ }
+
+ /*
+ * Check that TCP offset makes sense,
+ * pull out TCP options and adjust length.
+ */
+ off = ti->ti_off << 2;
+ if (off < sizeof (struct tcphdr) || off > tlen) {
+ tcpstat.tcps_badoff++;
+ goto drop;
+ }
+ tlen -= off;
+ ti->ti_len = tlen;
+ if (off > sizeof (struct tcphdr)) {
+ if ((m = m_pullup(m, sizeof (struct ip) + off)) == 0) {
+ tcpstat.tcps_hdrops++;
+ goto drop;
+ }
+ ti = mtod(m, struct tcpiphdr *);
+ om = m_get(M_DONTWAIT, MT_DATA);
+ if (om == 0)
+ goto drop;
+ om->m_len = off - sizeof (struct tcphdr);
+ { caddr_t op = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
+ bcopy(op, mtod(om, caddr_t), (unsigned)om->m_len);
+ m->m_len -= om->m_len;
+ bcopy(op+om->m_len, op,
+ (unsigned)(m->m_len-sizeof (struct tcpiphdr)));
+ }
+ }
+ tiflags = ti->ti_flags;
+
+ /*
+ * Drop TCP and IP headers.
+ */
+ off += sizeof (struct ip);
+ m->m_off += off;
+ m->m_len -= off;
+
+ /*
+ * Convert TCP protocol specific fields to host format.
+ */
+ ti->ti_seq = ntohl(ti->ti_seq);
+ ti->ti_ack = ntohl(ti->ti_ack);
+ ti->ti_win = ntohs(ti->ti_win);
+ ti->ti_urp = ntohs(ti->ti_urp);
+
+ /*
+ * Locate pcb for segment.
+ */
+ inp = in_pcblookup
+ (&tcb, ti->ti_src, ti->ti_sport, ti->ti_dst, ti->ti_dport,
+ INPLOOKUP_WILDCARD);
+
+ /*
+ * If the state is CLOSED (i.e., TCB does not exist) then
+ * all data in the incoming segment is discarded.
+ */
+ if (inp == 0)
+ goto dropwithreset;
+ tp = intotcpcb(inp);
+ if (tp == 0)
+ goto dropwithreset;
+ so = inp->inp_socket;
+ if (so->so_options & SO_DEBUG) {
+ ostate = tp->t_state;
+ tcp_saveti = *ti;
+ }
+ if (so->so_options & SO_ACCEPTCONN) {
+ so = sonewconn(so);
+ if (so == 0)
+ goto drop;
+ /*
+ * This is ugly, but ....
+ *
+ * Mark socket as temporary until we're
+ * committed to keeping it. The code at
+ * ``drop'' and ``dropwithreset'' check the
+ * flag dropsocket to see if the temporary
+ * socket created here should be discarded.
+ * We mark the socket as discardable until
+ * we're committed to it below in TCPS_LISTEN.
+ */
+ dropsocket++;
+ inp = (struct inpcb *)so->so_pcb;
+ inp->inp_laddr = ti->ti_dst;
+ inp->inp_lport = ti->ti_dport;
+ tp = intotcpcb(inp);
+ tp->t_state = TCPS_LISTEN;