1*5111Swnj /* tcp_subr.c 4.4 81/11/29 */ 25068Swnj 35068Swnj #include "../h/param.h" 45068Swnj #include "../h/systm.h" 55068Swnj #include "../h/mbuf.h" 65068Swnj #include "../h/socket.h" 75068Swnj #include "../h/socketvar.h" 85068Swnj #include "../h/protosw.h" 95089Swnj #include "../net/in.h" 105089Swnj #include "../net/in_pcb.h" 115089Swnj #include "../net/in_systm.h" 125068Swnj #include "../net/if.h" 135068Swnj #include "../net/ip.h" 145068Swnj #include "../net/ip_var.h" 155068Swnj #include "../net/tcp.h" 165068Swnj #define TCPFSTAB 175068Swnj #include "../net/tcp_fsm.h" 185089Swnj #include "../net/tcp_seq.h" 195089Swnj #include "../net/tcp_timer.h" 205068Swnj #include "../net/tcp_var.h" 215089Swnj #include "../net/tcpip.h" 22*5111Swnj #include "../errno.h" 235068Swnj 245068Swnj /* 255068Swnj * Tcp initialization 265068Swnj */ 275068Swnj tcp_init() 285068Swnj { 295068Swnj 305089Swnj COUNT(TCP_INIT); 315068Swnj tcp_iss = 1; /* wrong */ 325068Swnj tcb.inp_next = tcb.inp_prev = &tcb; 335068Swnj } 345068Swnj 355068Swnj /* 365068Swnj * Create template to be used to send tcp packets on a connection. 375068Swnj * Call after host entry created, allocates an mbuf and fills 385068Swnj * in a skeletal tcp/ip header, minimizing the amount of work 395068Swnj * necessary when the connection is used. 405068Swnj */ 415068Swnj struct tcpiphdr * 425068Swnj tcp_template(tp) 435068Swnj struct tcpcb *tp; 445068Swnj { 455068Swnj register struct inpcb *inp = tp->t_inpcb; 465068Swnj register struct mbuf *m; 475068Swnj register struct tcpiphdr *n; 485068Swnj 495068Swnj COUNT(TCP_TEMPLATE); 505068Swnj m = m_get(1); 515068Swnj if (m == 0) 525068Swnj return (0); 535068Swnj m->m_off = MMAXOFF - sizeof (struct tcpiphdr); 545068Swnj m->m_len = sizeof (struct tcpiphdr); 555068Swnj n = mtod(m, struct tcpiphdr *); 565068Swnj n->ti_next = n->ti_prev = 0; 575068Swnj n->ti_x1 = 0; 585068Swnj n->ti_pr = IPPROTO_TCP; 595068Swnj n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); 605068Swnj n->ti_src = inp->inp_laddr; 615068Swnj n->ti_dst = inp->inp_faddr; 625068Swnj n->ti_sport = inp->inp_lport; 635068Swnj n->ti_dport = inp->inp_fport; 645068Swnj n->ti_seq = 0; 655089Swnj n->ti_ack = 0; 665068Swnj n->ti_x2 = 0; 675068Swnj n->ti_off = 5; 685068Swnj n->ti_flags = 0; 695068Swnj n->ti_win = 0; 705068Swnj n->ti_sum = 0; 715068Swnj n->ti_urp = 0; 725068Swnj return (n); 735068Swnj } 745068Swnj 755068Swnj /* 765089Swnj * Send a reset message back to send of TCP segment ti, 775068Swnj * with ack, seq and flags fields as specified by parameters. 785068Swnj */ 795089Swnj tcp_respond(ti, ack, seq, flags) 805068Swnj register struct tcpiphdr *ti; 815089Swnj tcp_seq ack, seq; 825068Swnj int flags; 835068Swnj { 845089Swnj struct mbuf *m = dtom(ti); 855068Swnj 865089Swnj COUNT(TCP_RESPOND); 875068Swnj m_freem(m->m_next); 885068Swnj m->m_next = 0; 895068Swnj m->m_len = sizeof(struct tcpiphdr); 905089Swnj #define xchg(a,b,type) { type t; t=a; a=b; b=t; } 915089Swnj xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_long); 925089Swnj xchg(ti->ti_dport, ti->ti_sport, u_short); 935068Swnj #undef xchg 945089Swnj ti->ti_next = ti->ti_prev = 0; 955089Swnj ti->ti_x1 = 0; 965089Swnj ti->ti_len = htons(sizeof (struct tcphdr)); 975089Swnj ti->ti_seq = htonl(seq); 985068Swnj ti->ti_ack = htonl(ack); 995089Swnj ti->ti_x2 = 0; 1005089Swnj ti->ti_off = sizeof (struct tcphdr) >> 2; 1015068Swnj ti->ti_flags = flags; 1025089Swnj ti->ti_win = ti->ti_urp = 0; 1035089Swnj ti->ti_sum = in_cksum(m, sizeof(struct tcpiphdr)); 1045068Swnj ((struct ip *)ti)->ip_len = sizeof(struct tcpiphdr); 1055089Swnj ((struct ip *)ti)->ip_ttl = TCP_TTL; 106*5111Swnj (void) ip_output(m, (struct mbuf *)0); 1075068Swnj } 1085075Swnj 1095089Swnj /* 1105089Swnj * Create a new TCP control block, making an 1115089Swnj * empty reassembly queue and hooking it to the argument 1125089Swnj * protocol control block. 1135089Swnj */ 1145075Swnj struct tcpcb * 1155075Swnj tcp_newtcpcb(inp) 1165075Swnj struct inpcb *inp; 1175075Swnj { 1185075Swnj struct mbuf *m = m_getclr(0); 1195075Swnj register struct tcpcb *tp; 1205075Swnj COUNT(TCP_NEWTCPCB); 1215075Swnj 1225075Swnj if (m == 0) 1235075Swnj return (0); 1245075Swnj tp = mtod(m, struct tcpcb *); 1255075Swnj tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; 1265089Swnj tp->t_maxseg = 1024; 1275075Swnj tp->t_inpcb = inp; 1285075Swnj inp->inp_ppcb = (caddr_t)tp; 1295075Swnj return (tp); 1305075Swnj } 1315075Swnj 1325089Swnj /* 1335089Swnj * Drop a TCP connection, reporting 1345089Swnj * the specified error. If connection is synchronized, 1355089Swnj * then send a RST to peer. 1365089Swnj */ 1375075Swnj tcp_drop(tp, errno) 1385075Swnj struct tcpcb *tp; 1395075Swnj int errno; 1405075Swnj { 1415075Swnj struct socket *so = tp->t_inpcb->inp_socket; 1425075Swnj 1435075Swnj COUNT(TCP_DROP); 1445075Swnj if (TCPS_HAVERCVDSYN(tp->t_state) && 1455089Swnj TCPS_OURFINNOTACKED(tp->t_state)) { 1465075Swnj tp->t_state = TCPS_CLOSED; 1475075Swnj tcp_output(tp); 1485075Swnj } 1495075Swnj so->so_error = errno; 1505075Swnj tcp_close(tp); 1515075Swnj } 1525075Swnj 1535089Swnj /* 1545089Swnj * Close a TCP control block: 1555089Swnj * discard all space held by the tcp 1565089Swnj * discard internet protocol block 1575089Swnj * wake up any sleepers 1585089Swnj */ 1595075Swnj tcp_close(tp) 1605075Swnj register struct tcpcb *tp; 1615075Swnj { 1625075Swnj register struct tcpiphdr *t; 1635089Swnj struct socket *so = tp->t_inpcb->inp_socket; 1645075Swnj 1655075Swnj COUNT(TCP_CLOSE); 1665075Swnj t = tp->seg_next; 1675075Swnj for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next) 1685075Swnj m_freem(dtom(t)); 1695089Swnj if (tp->t_template) 1705075Swnj (void) m_free(dtom(tp->t_template)); 1715089Swnj if (tp->t_tcpopt) 1725089Swnj (void) m_free(dtom(tp->t_tcpopt)); 1735089Swnj if (tp->t_ipopt) 1745089Swnj (void) m_free(dtom(tp->t_ipopt)); 1755075Swnj in_pcbfree(tp->t_inpcb); 1765075Swnj (void) m_free(dtom(tp)); 1775089Swnj socantrcvmore(so); 1785089Swnj socantsendmore(so); 1795075Swnj } 1805075Swnj 1815075Swnj tcp_drain() 1825075Swnj { 1835075Swnj 1845075Swnj COUNT(TCP_DRAIN); 1855075Swnj } 1865075Swnj 1875075Swnj tcp_ctlinput(m) 1885075Swnj struct mbuf *m; 1895075Swnj { 1905075Swnj 1915075Swnj COUNT(TCP_CTLINPUT); 1925075Swnj m_freem(m); 1935075Swnj } 194