+ optlen = 4;
+
+ if ((tp->t_flags & TF_REQ_SCALE) &&
+ ((flags & TH_ACK) == 0 || (tp->t_flags & TF_RCVD_SCALE))) {
+ *((u_long *) (opt + optlen)) = htonl(
+ TCPOPT_NOP<<24 |
+ TCPOPT_WINDOW<<16 |
+ TCPOLEN_WINDOW<<8 |
+ tp->request_r_scale);
+ optlen += 4;
+ }
+
+#ifdef DO_SACK
+ /* Send a SACK_PERMITTED option in the SYN segment. */
+ *((u_long *) (opt + optlen)) = htonl(
+ TCPOPT_NOP<<24 |
+ TCPOPT_NOP<<16 |
+ TCPOPT_SACK_PERMITTED<<8 |
+ TCPOLEN_SACK_PERMITTED);
+ optlen += 4;
+#endif
+ }
+
+ /*
+ * Send a timestamp and echo-reply if this is a SYN and our side
+ * wants to use timestamps (TF_REQ_TSTMP is set) or both our side
+ * and our peer have sent timestamps in our SYN's.
+ */
+ if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
+ (flags & TH_RST) == 0 &&
+ ((flags & (TH_SYN|TH_ACK)) == TH_SYN ||
+ (tp->t_flags & TF_RCVD_TSTMP))) {
+ u_long *lp = (u_long *)(opt + optlen);
+
+ /* Form timestamp option as shown in appendix A of RFC 1323. */
+ *lp++ = htonl(TCPOPT_TSTAMP_HDR);
+ *lp++ = htonl(tcp_now);
+ *lp = htonl(tp->ts_recent);
+ optlen += TCPOLEN_TSTAMP_APPA;
+ }
+
+#ifdef DO_SACK
+ /* Send SACK if needed. Don't tack a SACK onto a non-empty segment. */
+ if (tp->seg_next != (struct tcpiphdr *)tp && len == 0 &&
+ (tp->t_flags & (TF_SACK_PERMIT|TF_NOOPT)) == TF_SACK_PERMIT) {
+
+ register struct tcpiphdr *q = tp->seg_next;
+ register u_long *optl = (u_long *)(opt + optlen) + 1;
+ tcp_seq block_start;
+ u_long block_size;
+ int sack_len = 2;
+
+ /*
+ * Use these to gather runs of received segments.
+ * The first segment in the queue becomes the initial run.
+ */
+ block_start = q->ti_seq;
+ block_size = q->ti_len;
+
+ do {
+ q = (struct tcpiphdr *) q->ti_next;
+ if (q == (struct tcpiphdr *) tp ||
+ block_start + block_size != q->ti_seq) {
+
+ /*
+ * Stick the relative origin and block size
+ * in the SACK option.
+ */
+ *optl++ = htonl(block_start-tp->rcv_nxt);
+ *optl++ = htonl(block_size);
+ sack_len += 8;
+
+ /* If no more will fit into options, quit. */
+ if (sack_len + optlen > MAX_TCPOPTLEN - 8)
+ break;
+
+ if (q != (struct tcpiphdr *) tp) {
+ block_start = q->ti_seq;
+ block_size = q->ti_len;
+ }
+ } else {
+ /*
+ * This segment just accumulates into previous
+ * run.
+ */
+ block_size += q->ti_len;
+ }
+ } while (q != (struct tcpiphdr *) tp);
+
+ *((u_long *) (opt + optlen)) = htonl(TCPOPT_NOP << 24 |
+ TCPOPT_NOP << 16 | TCPOPT_SACK << 8 | sack_len);
+ optlen += sack_len + 2;
+ }
+#endif
+ hdrlen += optlen;
+ /*
+ * Adjust data length if insertion of options will
+ * bump the packet length beyond the t_maxseg length.
+ */
+ if (len > tp->t_maxseg - optlen) {
+ len = tp->t_maxseg - optlen;
+ sendalot = 1;
+ }
+
+