// TCP tapset
// Copyright (C) 2006 IBM Corp.
// Copyright (C) 2006 Intel Corporation.
// Copyright (C) 2007, 2010, 2012 Red Hat, Inc.
//
// This file is part of systemtap, and is free software.  You can
// redistribute it and/or modify it under the terms of the GNU General
// Public License (GPL); either version 2, or (at your option) any
// later version.
// <tapsetdescription>
// This family of probe points is used to probe events that occur in the TCP layer, 
// </tapsetdescription>
%{
#include <linux/version.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <net/ip.h>
#include <linux/skbuff.h>
%}

// Get retransmission timeout in usecs. RTO is initialized from default
// retransmission time, but can be adjusted (increased) each time we 
// retransmit. It should always be less than the max value of TCP retransmission 
// timeout (TCP_RTO_MAX)
function tcp_get_info_rto:long(sock:long)
%{ /* pure */
	struct sock *sk = (struct sock *)(long) STAP_ARG_sock;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
	struct tcp_opt *tp = tcp_sk(sk);
	STAP_RETVALUE = (int64_t) jiffies_to_usecs(kread(&(tp->rto)));
#else
	const struct inet_connection_sock *icsk = inet_csk(sk);
	STAP_RETVALUE = (int64_t) jiffies_to_usecs(kread(&(icsk->icsk_rto)));
#endif
	CATCH_DEREF_FAULT();
%}

//Get congestion window segment size. Initial value of congestion window size 
//typically set to one segment (i.e., slow start algorithm, each segment can be 512 bytes).
//This congestion window size can be dynamically increased based on whether TCP
//is performing slow start or congestion avoidance. 
function tcp_get_info_snd_cwnd:long(sock:long)
%{ /* pure */
	struct sock *sk = (struct sock *)(long) STAP_ARG_sock;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
	struct tcp_opt *tp = tcp_sk(sk);
#else
	struct tcp_sock *tp = tcp_sk(sk);
#endif
	STAP_RETVALUE = (int64_t) kread(&(tp->snd_cwnd));
	CATCH_DEREF_FAULT();
%}

//
//Definitions of the TCP protocol sk_state field listed below.
//
//     TCP_ESTABLISHED = 1,   Normal data transfer
//     TCP_SYN_SENT   = 2,   App. has started to open a connection
//     TCP_SYN_RECV   = 3,   A connection request has arrived; wait for ACK
//     TCP_FIN_WAIT1  = 4,   App. has said it is finished
//     TCP_FIN_WAIT2  = 5,   The other side has agreed to close
//     TCP_TIME_WAIT  = 6,   Wait for all packets to die off
//     TCP_CLOSE      = 7,   No connection is active or pending 
//     TCP_CLOSE_WAIT = 8,   The other side has initiated a release
//     TCP_LAST_ACK   = 9,   Last ACK, wait for all packets to die off
//     TCP_LISTEN     = 10,  Waiting for incoming call
//     TCP_CLOSING    = 11,  Both sides have tried to close simultaneously
//     TCP_MAX_STATES = 12   Max states number
// 
function tcp_ts_get_info_state:long(sock:long)
%{ /* pure */
	struct sock *sk = (struct sock *)(long) STAP_ARG_sock;
	STAP_RETVALUE = (int64_t) kread(&(sk->sk_state));
	CATCH_DEREF_FAULT();
%}

/* return the TCP destination port for a given sock */
function __tcp_sock_dport:long (sock:long)
{
  port = @choose_defined(@cast(sock, "inet_sock", "kernel<net/inet_sock.h>")->sk->__sk_common->skc_dport, # kernel >= 3.8
          @choose_defined(@cast(sock, "inet_sock")->inet_dport, # kernel >= 2.6.33
           @choose_defined(@cast(sock, "inet_sock", "kernel")->dport, # kernel >= 2.6.11
                           @cast(sock, "inet_sock", "kernel<net/ip.h>")->inet->dport)))
  return ntohs(port)
}

/* returns the TCP header for recent (<2.6.21) kernel */
function __get_skb_tcphdr_new:long(skb:long)
%{ /* pure */
	struct sk_buff *skb;
	skb = (struct sk_buff *)(long)STAP_ARG_skb;
	/* as done by skb_transport_header() */
	#ifdef NET_SKBUFF_DATA_USES_OFFSET
		STAP_RETVALUE = (long)(kread(&(skb->head)) + kread(&(skb->transport_header)));
	#else
		STAP_RETVALUE = (long)kread(&(skb->transport_header));
	#endif
	CATCH_DEREF_FAULT();
%}

/* returns the TCP header for a given sk_buff structure */
function __get_skb_tcphdr:long(skb:long)
{
%( kernel_v < "2.6.21" %?
	tcphdr = @cast(skb, "sk_buff")->h->raw
	return tcphdr
%:
	return __get_skb_tcphdr_new(skb)
%)
}

/* returns TCP URG flag for a given sk_buff structure */
function __tcp_skb_urg:long (tcphdr:long)
{
	return @cast(tcphdr, "tcphdr")->urg
}

/* returns TCP ACK flag for a given sk_buff structure */
function __tcp_skb_ack:long (tcphdr:long)
{
	return @cast(tcphdr, "tcphdr")->ack
}

/* returns TCP PSH flag for a given sk_buff structure */
function __tcp_skb_psh:long (tcphdr:long)
{
	return @cast(tcphdr, "tcphdr")->psh
}

/* returns TCP RST flag for a given sk_buff structure */
function __tcp_skb_rst:long (tcphdr:long)
{
	return @cast(tcphdr, "tcphdr")->rst
}

/* returns TCP SYN flag for a given sk_buff structure */
function __tcp_skb_syn:long (tcphdr:long)
{
	return @cast(tcphdr, "tcphdr")->syn
}

/* returns TCP FIN flag for a given sk_buff structure */
function __tcp_skb_fin:long (tcphdr:long)
{
	return @cast(tcphdr, "tcphdr")->fin
}

/* returns TCP source port for a given sk_buff structure */
function __tcp_skb_sport:long (tcphdr:long)
{
	return ntohs(@cast(tcphdr, "tcphdr")->source)
}

/* returns TCP destination port for a given sk_buff structure */
function __tcp_skb_dport:long (tcphdr:long){
	return ntohs(@cast(tcphdr, "tcphdr")->dest)
}

/* return the TCP source port for a given sock */
function __tcp_sock_sport:long (sock:long)
{
    port = @choose_defined(@cast(sock, "inet_sock")->inet_sport, # kernel >= 2.6.33
	    @choose_defined(@cast(sock, "inet_sock", "kernel")->sport, # kernel >= 2.6.11
		@cast(sock, "inet_sock", "kernel<net/ip.h>")->inet->sport))
    return ntohs(port)
}

global sockstate[13], sockstate_init_p
function tcp_sockstate_str:string (state:long) {
	if (! sockstate_init_p) {
		sockstate_init_p = 1
		sockstate[1] = "TCP_ESTABLISHED"
		sockstate[2] = "TCP_SYN_SENT"
		sockstate[3] = "TCP_SYN_RECV"
		sockstate[4] = "TCP_FIN_WAIT1"
		sockstate[5] = "TCP_FIN_WAIT2"
		sockstate[6] = "TCP_TIME_WAIT"
		sockstate[7] = "TCP_CLOSE"
		sockstate[8] = "TCP_CLOSE_WAIT"
		sockstate[9] = "TCP_LAST_ACK"
		sockstate[10] = "TCP_LISTEN"
		sockstate[11] = "TCP_CLOSING"
		sockstate[12] = "TCP_MAX_STATES"
	}
	return (state in sockstate ? sockstate[state] : "UNDEF")
}

// Get slow start threshold size.  If cwnd size is less than or equal to
// threshold size, then TCP is in slow start; otherwise TCP is in congestion
// avoidance.
function tcp_ts_get_info_snd_ssthresh:long(sock:long)
%{ /* pure */
	struct sock *sk = (struct sock *)(long) STAP_ARG_sock;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
	struct tcp_opt *tp = tcp_sk(sk);
#else
	struct tcp_sock *tp = tcp_sk(sk);
#endif
	STAP_RETVALUE = (int64_t) kread(&(tp->snd_ssthresh));
	CATCH_DEREF_FAULT();
%}

// Get receiver's advertised segment size.  TCP typically never sends more
// than what receiver can accept.
function tcp_ts_get_info_rcv_mss:long(sock:long)
%{ /* pure */
	struct sock *sk = (struct sock *)(long) STAP_ARG_sock;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
	struct tcp_opt *tp = tcp_sk(sk);
	STAP_RETVALUE = (int64_t) kread(&(tp->ack.rcv_mss));
#else
	const struct inet_connection_sock *icsk = inet_csk(sk);
	STAP_RETVALUE = (int64_t) kread(&(icsk->icsk_ack.rcv_mss));
#endif
	CATCH_DEREF_FAULT();
%}

%{
// Define newer IPv4 sockopt constants for older kernels.
#ifndef TCP_CONGESTION
#define TCP_CONGESTION 0
#endif
#ifndef TCP_MD5SIG
#define TCP_MD5SIG 0
#endif
#ifndef TCP_COOKIE_TRANSACTIONS
#define TCP_COOKIE_TRANSACTIONS 0
#endif
#ifndef TCP_THIN_LINEAR_TIMEOUTS
#define TCP_THIN_LINEAR_TIMEOUTS 0
#endif
#ifndef TCP_THIN_DUPACK
#define TCP_THIN_DUPACK 0
#endif
#ifndef TCP_USER_TIMEOUT
#define TCP_USER_TIMEOUT 0
#endif
%}

global __sockopt, __sockopt_init_p
function tcp_sockopt_str:string (optname:long)
{
	if (!__sockopt_init_p) {
		__sockopt_init_p = 1
		__sockopt[%{/* pure */TCP_NODELAY%}] = "TCP_NODELAY"
		__sockopt[%{/* pure */TCP_MAXSEG%}] = "TCP_MAXSEG"
		__sockopt[%{/* pure */TCP_CORK%}] = "TCP_CORK"
		__sockopt[%{/* pure */TCP_KEEPIDLE%}] = "TCP_KEEPIDLE"
		__sockopt[%{/* pure */TCP_KEEPINTVL%}] = "TCP_KEEPINTVL"
		__sockopt[%{/* pure */TCP_KEEPCNT%}] = "TCP_KEEPCNT"
		__sockopt[%{/* pure */TCP_SYNCNT%}] = "TCP_SYNCNT"
		__sockopt[%{/* pure */TCP_LINGER2%}] = "TCP_LINGER2"
		__sockopt[%{/* pure */TCP_DEFER_ACCEPT%}] = "TCP_DEFER_ACCEPT"
		__sockopt[%{/* pure */TCP_WINDOW_CLAMP%}] = "TCP_WINDOW_CLAMP"
		__sockopt[%{/* pure */TCP_INFO%}] = "TCP_INFO"
		__sockopt[%{/* pure */TCP_QUICKACK%}] = "TCP_QUICKACK"
		if (%{/* pure */TCP_CONGESTION%} > 0)
			__sockopt[%{/* pure */TCP_CONGESTION%}]
				= "TCP_CONGESTION"
		if (%{/* pure */TCP_MD5SIG%} > 0)
			__sockopt[%{/* pure */TCP_MD5SIG%}] = "TCP_MD5SIG"
		if (%{/* pure */TCP_COOKIE_TRANSACTIONS%} > 0)
			__sockopt[%{/* pure */TCP_COOKIE_TRANSACTIONS%}]
				= "TCP_COOKIE_TRANSACTIONS"
		if (%{/* pure */TCP_THIN_LINEAR_TIMEOUTS%} > 0)
			__sockopt[%{/* pure */TCP_THIN_LINEAR_TIMEOUTS%}]
				= "TCP_THIN_LINEAR_TIMEOUTS"
		if (%{/* pure */TCP_THIN_DUPACK%} > 0)
			__sockopt[%{/* pure */TCP_THIN_DUPACK%}]
				= "TCP_THIN_DUPACK"
		if (%{/* pure */TCP_USER_TIMEOUT%} > 0)
			__sockopt[%{/* pure */TCP_USER_TIMEOUT%}]
				= "TCP_USER_TIMEOUT"
	}
	return (optname in __sockopt ? __sockopt[optname]
		: sprintf("UNDEF_SOCKOPT(%d)", optname))
}

%{
// Define newer IPv6 sockopt constants for older kernels.
#include <linux/in6.h>
#ifndef IPV6_2292PKTINFO
#define IPV6_2292PKTINFO 0
#endif
#ifndef IPV6_2292HOPOPTS
#define IPV6_2292HOPOPTS 0
#endif
#ifndef IPV6_2292DSTOPTS
#define IPV6_2292DSTOPTS 0
#endif
#ifndef IPV6_2292RTHDR
#define IPV6_2292RTHDR 0
#endif
#ifndef IPV6_2292PKTOPTIONS
#define IPV6_2292PKTOPTIONS 0
#endif
#ifndef IPV6_2292HOPLIMIT
#define IPV6_2292HOPLIMIT 0
#endif
#ifndef IPV6_RECVPKTINFO
#define IPV6_RECVPKTINFO 0
#endif
#ifndef IPV6_RECVHOPLIMIT
#define IPV6_RECVHOPLIMIT 0
#endif
#ifndef IPV6_RECVHOPOPTS
#define IPV6_RECVHOPOPTS 0
#endif
#ifndef IPV6_RTHDRDSTOPTS
#define IPV6_RTHDRDSTOPTS 0
#endif
#ifndef IPV6_RECVRTHDR
#define IPV6_RECVRTHDR 0
#endif
#ifndef IPV6_RECVDSTOPTS
#define IPV6_RECVDSTOPTS 0
#endif
#ifndef IPV6_RECVPATHMTU
#define IPV6_RECVPATHMTU 0
#endif
#ifndef IPV6_PATHMTU
#define IPV6_PATHMTU 0
#endif
#ifndef IPV6_DONTFRAG
#define IPV6_DONTFRAG 0
#endif
#ifndef IPV6_ADDR_PREFERENCES
#define IPV6_ADDR_PREFERENCES 0
#endif
#ifndef IPV6_MINHOPCOUNT
#define IPV6_MINHOPCOUNT 0
#endif
#ifndef IPV6_RECVORIGDSTADDR
#define IPV6_RECVORIGDSTADDR 0
#endif
#ifndef IPV6_TRANSPARENT
#define IPV6_TRANSPARENT 0
#endif
%}

global __ipv6_sockopt, __ipv6_sockopt_init_p
function tcp_ipv6_sockopt_str:string (optname:long)
{
	if (!__ipv6_sockopt_init_p) {
		__ipv6_sockopt_init_p = 1
		__ipv6_sockopt[%{/* pure */IPV6_ADDRFORM%}] = "IPV6_ADDRFORM"
		if (%{/* pure */IPV6_2292PKTINFO%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_2292PKTINFO%}]
				= "IPV6_2292PKTINFO"
		if (%{/* pure */IPV6_2292HOPOPTS%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_2292HOPOPTS%}]
				= "IPV6_2292HOPOPTS"
		if (%{/* pure */IPV6_2292DSTOPTS%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_2292DSTOPTS%}]
				= "IPV6_2292DSTOPTS"
		if (%{/* pure */IPV6_2292RTHDR%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_2292RTHDR%}]
				= "IPV6_2292RTHDR"
		if (%{/* pure */IPV6_2292PKTOPTIONS%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_2292PKTOPTIONS%}]
				= "IPV6_2292PKTOPTIONS"
		__ipv6_sockopt[%{/* pure */IPV6_CHECKSUM%}] = "IPV6_CHECKSUM"
		if (%{/* pure */IPV6_2292HOPLIMIT%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_2292HOPLIMIT%}]
				= "IPV6_2292HOPLIMIT"
		__ipv6_sockopt[%{/* pure */IPV6_NEXTHOP%}] = "IPV6_NEXTHOP"
		__ipv6_sockopt[%{/* pure */IPV6_AUTHHDR%}] = "IPV6_AUTHHDR"
		__ipv6_sockopt[%{/* pure */IPV6_FLOWINFO%}] = "IPV6_FLOWINFO"
		__ipv6_sockopt[%{/* pure */IPV6_UNICAST_HOPS%}]
			= "IPV6_UNICAST_HOPS"
		__ipv6_sockopt[%{/* pure */IPV6_MULTICAST_IF%}]
			= "IPV6_MULTICAST_IF"
		__ipv6_sockopt[%{/* pure */IPV6_MULTICAST_HOPS%}]
			= "IPV6_MULTICAST_HOPS"
		__ipv6_sockopt[%{/* pure */IPV6_MULTICAST_LOOP%}]
			= "IPV6_MULTICAST_LOOP"
		__ipv6_sockopt[%{/* pure */IPV6_ADD_MEMBERSHIP%}]
			= "IPV6_ADD_MEMBERSHIP"
		__ipv6_sockopt[%{/* pure */IPV6_DROP_MEMBERSHIP%}]
			= "IPV6_DROP_MEMBERSHIP"
		__ipv6_sockopt[%{/* pure */IPV6_ROUTER_ALERT%}]
			= "IPV6_ROUTER_ALERT"
		__ipv6_sockopt[%{/* pure */IPV6_MTU_DISCOVER%}]
			= "IPV6_MTU_DISCOVER"
		__ipv6_sockopt[%{/* pure */IPV6_MTU%}] = "IPV6_MTU"
		__ipv6_sockopt[%{/* pure */IPV6_RECVERR%}] = "IPV6_RECVERR"
		__ipv6_sockopt[%{/* pure */IPV6_V6ONLY%}] = "IPV6_V6ONLY"
		__ipv6_sockopt[%{/* pure */IPV6_JOIN_ANYCAST%}]
			= "IPV6_JOIN_ANYCAST"
		__ipv6_sockopt[%{/* pure */IPV6_LEAVE_ANYCAST%}]
			= "IPV6_LEAVE_ANYCAST"
		__ipv6_sockopt[%{/* pure */IPV6_FLOWLABEL_MGR%}]
			= "IPV6_FLOWLABEL_MGR"
		__ipv6_sockopt[%{/* pure */IPV6_FLOWINFO_SEND%}]
			= "IPV6_FLOWINFO_SEND"
		__ipv6_sockopt[%{/* pure */IPV6_IPSEC_POLICY%}]
			= "IPV6_IPSEC_POLICY"
		__ipv6_sockopt[%{/* pure */IPV6_XFRM_POLICY%}]
			= "IPV6_XFRM_POLICY"
		__ipv6_sockopt[%{/* pure */MCAST_JOIN_GROUP%}]
			= "MCAST_JOIN_GROUP"
		__ipv6_sockopt[%{/* pure */MCAST_BLOCK_SOURCE%}]
			= "MCAST_BLOCK_SOURCE"
		__ipv6_sockopt[%{/* pure */MCAST_UNBLOCK_SOURCE%}]
			= "MCAST_UNBLOCK_SOURCE"
		__ipv6_sockopt[%{/* pure */MCAST_LEAVE_GROUP%}]
			= "MCAST_LEAVE_GROUP"
		__ipv6_sockopt[%{/* pure */MCAST_JOIN_SOURCE_GROUP%}]
			= "MCAST_JOIN_SOURCE_GROUP"
		__ipv6_sockopt[%{/* pure */MCAST_LEAVE_SOURCE_GROUP%}]
			= "MCAST_LEAVE_SOURCE_GROUP"
		__ipv6_sockopt[%{/* pure */MCAST_MSFILTER%}] = "MCAST_MSFILTER"
		if (%{/* pure */IPV6_RECVPKTINFO%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_RECVPKTINFO%}]
				= "IPV6_RECVPKTINFO"
		__ipv6_sockopt[%{/* pure */IPV6_PKTINFO%}] = "IPV6_PKTINFO"
		if (%{/* pure */IPV6_RECVHOPLIMIT%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_RECVHOPLIMIT%}]
				= "IPV6_RECVHOPLIMIT"
		__ipv6_sockopt[%{/* pure */IPV6_HOPLIMIT%}] = "IPV6_HOPLIMIT"
		if (%{/* pure */IPV6_RECVHOPOPTS%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_RECVHOPOPTS%}]
				= "IPV6_RECVHOPOPTS"
		__ipv6_sockopt[%{/* pure */IPV6_HOPOPTS%}] = "IPV6_HOPOPTS"
		if (%{/* pure */IPV6_RTHDRDSTOPTS%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_RTHDRDSTOPTS%}]
				= "IPV6_RTHDRDSTOPTS"
		if (%{/* pure */IPV6_RECVRTHDR%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_RECVRTHDR%}]
				= "IPV6_RECVRTHDR"
		__ipv6_sockopt[%{/* pure */IPV6_RTHDR%}] = "IPV6_RTHDR"
		if (%{/* pure */IPV6_RECVDSTOPTS%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_RECVDSTOPTS%}]
				= "IPV6_RECVDSTOPTS"
		__ipv6_sockopt[%{/* pure */IPV6_DSTOPTS%}] = "IPV6_DSTOPTS"
		if (%{/* pure */IPV6_RECVPATHMTU%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_RECVPATHMTU%}]
				= "IPV6_RECVPATHMTU"
		if (%{/* pure */IPV6_PATHMTU%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_PATHMTU%}]
				= "IPV6_PATHMTU"
		if (%{/* pure */IPV6_DONTFRAG%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_DONTFRAG%}]
				= "IPV6_DONTFRAG"
		__ipv6_sockopt[%{/* pure */IPV6_RECVTCLASS%}]
			= "IPV6_RECVTCLASS"
		__ipv6_sockopt[%{/* pure */IPV6_TCLASS%}] = "IPV6_TCLASS"
		if (%{/* pure */IPV6_ADDR_PREFERENCES%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_ADDR_PREFERENCES%}]
				= "IPV6_ADDR_PREFERENCES"
		if (%{/* pure */IPV6_MINHOPCOUNT%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_MINHOPCOUNT%}]
				= "IPV6_MINHOPCOUNT"
		if (%{/* pure */IPV6_RECVORIGDSTADDR%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_RECVORIGDSTADDR%}]
				= "IPV6_RECVORIGDSTADDR"
		if (%{/* pure */IPV6_TRANSPARENT%} > 0)
			__ipv6_sockopt[%{/* pure */IPV6_TRANSPARENT%}]
				= "IPV6_TRANSPARENT"
	}
	return (optname in __ipv6_sockopt ? __ipv6_sockopt[optname]
		: sprintf("UNDEF_SOCKOPT(%d)", optname))
}

/**
  * probe tcp.sendmsg - Sending a tcp message
  * @name: Name of this probe
  * @sock: Network socket 
  * @family: IP address family
  * @size: Number of bytes to send  
  *
  * Context:
  *  The process which sends a tcp message 
  */
probe tcp.sendmsg = kernel.function("tcp_sendmsg") {
	name = "tcp.sendmsg"
	sock = (@defined($sock) ? $sock->sk : $sk)
	family  = __ip_sock_family(@defined($sock) ? $sock->sk : $sk)
	size = $size
}

/**
 * probe tcp.sendmsg.return -  Sending TCP message is done
 * @name: Name of this probe
 * @size: Number of bytes sent or error code if an error occurred. 
 *
 * Context:
 *  The process which sends a tcp message
 */
probe tcp.sendmsg.return = kernel.function("tcp_sendmsg").return {
	name = "tcp.sendmsg"
	size = $return 
}

/**
 * probe tcp.recvmsg - Receiving TCP message
 * @name: Name of this probe
 * @sock: Network socket
 * @size: Number of bytes to be received  
 * @family: IP address family
 * @saddr: A string representing the source IP address
 * @daddr: A string representing the destination IP address
 * @sport: TCP source port 
 * @dport: TCP destination port
 * Context:
 *  The process which receives a tcp message
 */
probe tcp.recvmsg = kernel.function("tcp_recvmsg") {
	name = "tcp.recvmsg"
	sock    = $sk
	size    = $len
	family  = __ip_sock_family($sk)
	saddr   = format_ipaddr(__ip_sock_saddr($sk), __ip_sock_family($sk))
	daddr   = format_ipaddr(__ip_sock_daddr($sk), __ip_sock_family($sk))
	sport   = __tcp_sock_sport($sk)
	dport   = __tcp_sock_dport($sk)
}

/**
 * probe tcp.recvmsg.return - Receiving TCP message complete
 * @name: Name of this probe
 * @size: Number of bytes received or error code if an error occurred.
 * @family: IP address family
 * @saddr: A string representing the source IP address
 * @daddr: A string representing the destination IP address
 * @sport: TCP source port 
 * @dport: TCP destination port
 *
 * Context:
 *  The process which receives a tcp message
 */
probe tcp.recvmsg.return = kernel.function("tcp_recvmsg").return {
	name = "tcp.recvmsg"
	size = $return
	family  = __ip_sock_family($sk)
	saddr   = format_ipaddr(__ip_sock_saddr($sk), __ip_sock_family($sk))
	daddr   = format_ipaddr(__ip_sock_daddr($sk), __ip_sock_family($sk))
	sport = __tcp_sock_sport($sk)
	dport = __tcp_sock_dport($sk)
}

/**
 * probe tcp.disconnect - TCP socket disconnection
 * @name: Name of this probe
 * @sock: Network socket 
 * @family: IP address family
 * @flags: TCP flags (e.g. FIN, etc)  
 * @saddr: A string representing the source IP address
 * @daddr: A string representing the destination IP address
 * @sport: TCP source port 
 * @dport: TCP destination port
 *
 * Context:
 *  The process which disconnects tcp 
 */
probe tcp.disconnect = kernel.function("tcp_disconnect") {
	name = "tcp.disconnect"
	sock  = $sk
	family = __ip_sock_family($sk)
	flags = $flags
	saddr   = format_ipaddr(__ip_sock_saddr($sk), __ip_sock_family($sk))
	daddr   = format_ipaddr(__ip_sock_daddr($sk), __ip_sock_family($sk))
	sport = __tcp_sock_sport($sk)
	dport = __tcp_sock_dport($sk)
}

/**
 * probe tcp.disconnect.return - TCP socket disconnection complete
 * @name: Name of this probe
 * @ret: Error code (0: no error) 
 *
 * Context:
 *  The process which disconnects tcp
 */
probe tcp.disconnect.return = kernel.function("tcp_disconnect").return {
	name = "tcp.disconnect"
	ret = $return 
}

/**
 * probe tcp.setsockopt - Call to setsockopt()
 * @name: Name of this probe
 * @sock: Network socket
 * @family: IP address family
 * @level: The level at which the socket options will be manipulated
 * @optname: TCP socket options (e.g. TCP_NODELAY, TCP_MAXSEG, etc)
 * @optstr: Resolves optname to a human-readable format
 * @optlen: Used to access values for setsockopt()
 *
 * Context:
 *  The process which calls setsockopt
 */
probe tcp.setsockopt = tcp.ipv4.setsockopt, tcp.ipv6.setsockopt
{
}
probe tcp.ipv4.setsockopt = kernel.function("tcp_setsockopt")
{
	name = "tcp.ipv4.setsockopt"
	sock = $sk
	family  = __ip_sock_family($sk)
	level = $level
	optname = $optname
	optstr = tcp_sockopt_str($optname)
	optlen = $optlen
}
probe tcp.ipv6.setsockopt = kernel.function("ipv6_setsockopt")!,
	module("ipv6").function("ipv6_setsockopt")
{
	name = "tcp.ipv6.setsockopt"
	sock = $sk
	family  = __ip_sock_family($sk)
	level = $level
	optname = $optname
	optstr = tcp_ipv6_sockopt_str($optname)
	optlen = $optlen
}

/**
 * probe tcp.setsockopt.return -  Return from setsockopt()
 * @name: Name of this probe
 * @ret: Error code (0: no error)
 *
 * Context:
 *  The process which calls setsockopt
 */
probe tcp.setsockopt.return = tcp.ipv4.setsockopt.return,
	tcp.ipv6.setsockopt.return
{
}
probe tcp.ipv4.setsockopt.return = kernel.function("tcp_setsockopt").return
{
	name = "tcp.ipv4.setsockopt"
	ret = $return
}
probe tcp.ipv6.setsockopt.return = kernel.function("ipv6_setsockopt").return!,
	module("ipv6").function("ipv6_setsockopt").return
{
	name = "tcp.ipv6.setsockopt"
	ret = $return
}

/**
 * probe tcp.receive - Called when a TCP packet is received
 * @name: Name of the probe point
 * @iphdr: IP header address
 * @protocol: Packet protocol from driver
 * @family: IP address family
 * @saddr: A string representing the source IP address
 * @daddr: A string representing the destination IP address
 * @sport: TCP source port
 * @dport: TCP destination port
 * @urg: TCP URG flag
 * @ack: TCP ACK flag
 * @psh: TCP PSH flag
 * @rst: TCP RST flag
 * @syn: TCP SYN flag
 * @fin: TCP FIN flag
 */
probe tcp.receive = tcp.ipv4.receive, tcp.ipv6.receive
{
}

probe tcp.ipv4.receive = kernel.function("tcp_v4_rcv")
{
	name = "tcp.ipv4.receive"
	iphdr = __get_skb_iphdr($skb)
	# If we're here, by definition we're doing AF_INET, not AF_INET6.
	family = %{ /* pure */ AF_INET %}
	saddr = format_ipaddr(__ip_skb_saddr(iphdr), %{ /* pure */ AF_INET %})
	daddr = format_ipaddr(__ip_skb_daddr(iphdr), %{ /* pure */ AF_INET %})
	protocol = __ip_skb_proto(iphdr)

	tcphdr = __get_skb_tcphdr($skb)
	dport = __tcp_skb_dport(tcphdr)
	sport = __tcp_skb_sport(tcphdr)
	urg = __tcp_skb_urg(tcphdr)
	ack = __tcp_skb_ack(tcphdr)
	psh = __tcp_skb_psh(tcphdr)
	rst = __tcp_skb_rst(tcphdr)
	syn = __tcp_skb_syn(tcphdr)
	fin = __tcp_skb_fin(tcphdr)
}

probe tcp.ipv6.receive = kernel.function("tcp_v6_rcv")!,
	module("ipv6").function("tcp_v6_rcv")
{
	name = "tcp.ipv6.receive"
	iphdr = __get_skb_iphdr(@choose_defined($skb, kernel_pointer($pskb)))
	# If we're here, by definition we're doing AF_INET6, not AF_INET.
	family = %{ /* pure */ AF_INET6 %}
	saddr = format_ipaddr(&@cast(iphdr, "ipv6hdr")->saddr,
			      %{ /* pure */ AF_INET6 %})
	daddr = format_ipaddr(&@cast(iphdr, "ipv6hdr")->daddr,
			      %{ /* pure */ AF_INET6 %})
	# If we're here, by definition we're doing IPPROTO_TCP.  There
	# isn't a protocol field in 'struct ipv6hdr'.  There is one in
	# 'struct sk_buff', but that protocol field is an Ethernet
	# Procol ID (ETH_P_*), not an IP protocol ID (IPPROTO_*).
	protocol = %{ /* pure */ IPPROTO_TCP %}

	tcphdr = __get_skb_tcphdr(@choose_defined($skb, kernel_pointer($pskb)))
	dport = __tcp_skb_dport(tcphdr)
	sport = __tcp_skb_sport(tcphdr)
	urg = __tcp_skb_urg(tcphdr)
	ack = __tcp_skb_ack(tcphdr)
	psh = __tcp_skb_psh(tcphdr)
	rst = __tcp_skb_rst(tcphdr)
	syn = __tcp_skb_syn(tcphdr)
	fin = __tcp_skb_fin(tcphdr)
}
