/* data has been encrypted before */ static gint packet_send_out(PurpleConnection *gc, guint16 cmd, guint16 seq, guint8 *data, gint data_len) { qq_data *qd; guint8 *buf; gint buf_len; gint bytes_sent; g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, -1); qd = (qq_data *)gc->proto_data; g_return_val_if_fail(data != NULL && data_len > 0, -1); buf = g_newa(guint8, MAX_PACKET_SIZE); memset(buf, 0, MAX_PACKET_SIZE); /* encapsulate */ buf_len = packet_encap(qd, buf, MAX_PACKET_SIZE, cmd, seq, data, data_len); if (buf_len <= 0) { return -1; } qd->net_stat.sent++; if (qd->use_tcp) { bytes_sent = tcp_send_out(gc, buf, buf_len); } else { bytes_sent = udp_send_out(gc, buf, buf_len); } return bytes_sent; }
int tcp_send_text(struct tcp_sock *tsk, void *buf, int len) { struct pkbuf *pkb; int slen = 0; int segsize = tsk->sk.sk_dst->rt_dev->net_mtu - IP_HRD_SZ - TCP_HRD_SZ; len = min(len, (int)tsk->snd_wnd); while (slen < len) { /* TODO: handle silly window syndrome */ segsize = min(segsize, len - slen); pkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + TCP_HRD_SZ + segsize); tcp_init_text(tsk, pkb, buf + slen, segsize); slen += segsize; if (slen >= len) pkb2tcp(pkb)->psh = 1; tcp_send_out(tsk, pkb, NULL); } /* zero window: request window update */ if (!slen) { /* TODO: persist timer */ tcp_send_ack(tsk, NULL); slen = -1; } return slen; }
/* * Reset algorithm is not stated directly in RFC 793, * but we can conclude it according to all reset generation. * NOTE: maybe @tsk is NULL */ void tcp_send_reset(struct tcp_sock *tsk, struct tcp_segment *seg) { struct tcp *otcp, *tcphdr = seg->tcphdr; struct pkbuf *opkb; if (tcphdr->rst) return; opkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + TCP_HRD_SZ); /* fill tcp head */ otcp = (struct tcp *)pkb2ip(opkb)->ip_data; otcp->src = tcphdr->dst; otcp->dst = tcphdr->src; if (tcphdr->ack) { /* * Should we set ack? * -Yes for xinu, it always set ack to seq+len * +No for Linux * +No for tapip */ otcp->seq = tcphdr->ackn; } else { otcp->ackn = _htonl(seg->seq + seg->len); otcp->ack = 1; } otcp->doff = TCP_HRD_DOFF; otcp->rst = 1; tcpdbg("send RESET from "IPFMT":%d to "IPFMT":%d", ipfmt(seg->iphdr->ip_dst), _ntohs(otcp->src), ipfmt(seg->iphdr->ip_src), _ntohs(otcp->dst)); tcp_send_out(NULL, opkb, seg); }
void tcp_send_fin(struct tcp_sock *tsk) { struct tcp *otcp; struct pkbuf *opkb; opkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + TCP_HRD_SZ); /* fill tcp head */ otcp = (struct tcp *)pkb2ip(opkb)->ip_data; otcp->src = tsk->sk.sk_sport; otcp->dst = tsk->sk.sk_dport; otcp->doff = TCP_HRD_DOFF; otcp->seq = _htonl(tsk->snd_nxt); otcp->window = _htons(tsk->rcv_wnd); otcp->fin = 1; /* * Should we send an ACK? * Yes, tcp stack will drop packet if it has no ACK bit * according to RFC 793 #SEGMENT RECEIVE */ otcp->ackn = _htonl(tsk->rcv_nxt); otcp->ack = 1; tcpdbg("send FIN(%u)/ACK(%u) [WIN %d] to "IPFMT":%d", _ntohl(otcp->seq), _ntohl(otcp->ackn), _ntohs(otcp->window), ipfmt(tsk->sk.sk_daddr), _ntohs(otcp->dst)); tcp_send_out(tsk, opkb, NULL); }
void tcp_send_synack(struct tcp_sock *tsk, struct tcp_segment *seg) { /* * LISTEN : * SYN-SENT: * SEG: SYN, no ACK, no RST * <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK> * (ISS == SND.NXT) */ struct tcp *otcp, *tcphdr = seg->tcphdr; struct pkbuf *opkb; if (tcphdr->rst) return; opkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + TCP_HRD_SZ); /* fill tcp head */ otcp = (struct tcp *)pkb2ip(opkb)->ip_data; otcp->src = tcphdr->dst; otcp->dst = tcphdr->src; otcp->doff = TCP_HRD_DOFF; otcp->seq = _htonl(tsk->iss); otcp->ackn = _htonl(tsk->rcv_nxt); otcp->syn = 1; otcp->ack = 1; otcp->window = _htons(tsk->rcv_wnd); tcpdbg("send SYN(%u)/ACK(%u) [WIN %d] to "IPFMT":%d", _ntohl(otcp->seq), _ntohs(otcp->window), _ntohl(otcp->ackn), ipfmt(seg->iphdr->ip_dst), _ntohs(otcp->dst)); tcp_send_out(tsk, opkb, seg); }
void tcp_send_syn(struct tcp_sock *tsk, struct tcp_segment *seg) { /* * SYN-SENT: */ struct tcp *otcp; struct pkbuf *opkb; opkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + TCP_HRD_SZ); /* fill tcp head */ otcp = (struct tcp *)pkb2ip(opkb)->ip_data; otcp->src = tsk->sk.sk_sport; otcp->dst = tsk->sk.sk_dport; otcp->doff = TCP_HRD_DOFF; otcp->seq = _htonl(tsk->iss); otcp->syn = 1; otcp->window = _htons(tsk->rcv_wnd); tcpdbg("send SYN(%u) [WIN %d] to "IPFMT":%d", _ntohl(otcp->seq), _ntohs(otcp->window), ipfmt(tsk->sk.sk_daddr), _ntohs(otcp->dst)); tcp_send_out(tsk, opkb, seg); }
/* * Acknowledgment algorithm is not stated directly in RFC 793, * but we can conclude it from all acknowledgment situation. */ void tcp_send_ack(struct tcp_sock *tsk, struct tcp_segment *seg) { /* * SYN-SENT : * SEG: SYN, acceptable ACK, no RST (SND.NXT = SEG.SEQ+1) * <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> * SYN-RECEIVED / ESTABLISHED / FIN-WAIT-1 / FIN-WAIT-2 / * CLOSE-WAIT / CLOSING / LAST-ACK / TIME-WAIT : * SEG: no RST, ??ACK, ??SYN (segment is not acceptable) * <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> * ESTABLISHED / FIN-WAIT-1 / FIN-WAIT-2 / process the segment text: * SEG: ACK, no RST * <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> * (This acknowledgment should be piggybacked on a segment being * transmitted if possible without incurring undue delay.) */ struct tcp *otcp, *tcphdr = seg->tcphdr; struct pkbuf *opkb; if (tcphdr->rst) return; opkb = alloc_pkb(ETH_HRD_SZ + IP_HRD_SZ + TCP_HRD_SZ); /* fill tcp head */ otcp = (struct tcp *)pkb2ip(opkb)->ip_data; otcp->src = tcphdr->dst; otcp->dst = tcphdr->src; otcp->doff = TCP_HRD_DOFF; otcp->seq = _htonl(tsk->snd_nxt); otcp->ackn = _htonl(tsk->rcv_nxt); otcp->ack = 1; otcp->window = _htons(tsk->rcv_wnd); tcpdbg("send ACK(%u) [WIN %d] to "IPFMT":%d", _ntohl(otcp->ackn), _ntohs(otcp->window), ipfmt(seg->iphdr->ip_src), _ntohs(otcp->dst)); tcp_send_out(tsk, opkb, seg); }