\documentclass{article}% S Khan/H.Voss 2006
\usepackage{geometry,pstricks}
\usepackage{pst-node,graphicx}
\usepackage{pst-tree}
\definecolor{ContextColorEmac}{rgb}{1.,0.9,0.9}
\definecolor{ContextColorTcpip}{rgb}{0.9,1,0.9}
\definecolor{ContextColorTcpipStrong}{rgb}{0.6,1,0.6}
\definecolor{ContextColorTcpipStrongStrong}{rgb}{0.3,1,0.3}
\definecolor{ContextColorUser}{rgb}{0.9,0.9,1}
\definecolor{ContextColorUserStrong}{rgb}{0.6,0.6,1}
\definecolor{ContextColorUserStrongStrong}{rgb}{0.3,0.3,1}
\pagestyle{empty}
\setlength\parindent{0pt}

\def\Fcn#1{\texttt{#1}}
\def\LabelBox#1{\rput*[tl]{0}(0,0){#1}}
\pslongbox{ContextBox}{\psframebox[fillcolor=\ContextColor,fillstyle=solid]} 
\newenvironment{context}[1]{\hbox{#1}\ContextBox}{\endContextBox} 
\newenvironment{container}{\psmatrix[rowsep=1,colsep=1,mnode=r,mcol=c]}{\endpsmatrix}

%%%% NOTE: Make sure you compile this two or three times initially! 
%%%%       The pst-tree stuff takes a bit to figure out spacing.
%%%%       If things start coliding, run it again.

% These commands work by:
%    \TreeEntity[,param=val,name=something,other=somethingelse]{in}{out}{root}{leaves}
% where
%    in is the reference point on the object, usually "l","r",etc. (notice lowercase)
%    out is the direction the tree continues, usually "L","R","U","D",etc. (notice caps)
%    root is the text shown in the root (not all entities have this)
%    leaves is the text for the leaves of the tree
\newcommand\TreeDot[4][name=dummy]{\pstree[treemode=#3,levelsep=*1cm,linewidth=0.1,arrows=->]{\Tdot[dotsize=0.2cm,#1]}{#4}}
\newcommand\TreeNode[5][name=dummy]{\pstree[treemode=#3,levelsep=*1cm,linewidth=0.1,arrows=->]{\Tr[ref=#2,#1]{\psshadowbox[linewidth=0.05]{#4}}}{#5}}
\newcommand\TreeNodeTabular[5][name=dummy]{\TreeNode[#1]{#2}{#3}{\shortstack{#4}}{#5}}
\newcommand\TreeCircle[5][name=dummy]{\pstree[treemode=#3,levelsep=*1cm,linewidth=0.1,arrows=->]{\Tcircle[ref=#2,fillcolor=\ContextColorStrong,fillstyle=solid,linewidth=0.05,#1]{#4}}{#5}}
\newcommand\TreeOval[5][name=dummy]{\pstree[treemode=#3,levelsep=*1cm,linewidth=0.1,arrows=->]{\Toval[ref=#2,fillcolor=\ContextColorStrong,fillstyle=solid,linewidth=0.05,#1]{#4}}{#5}}
\newcommand\TreeDiamond[5][name=dummy]{\pstree[treemode=#3,levelsep=*1cm,linewidth=0.1,arrows=->]{\Tdia[ref=#2,fillcolor=\ContextColorStrong,fillstyle=solid,linewidth=0.05,#1]{#4}}{#5}}

\newcommand\TreeNodeExternal[5][name=dummy]{\pstree[treemode=#3,levelsep=*1cm,linewidth=0.1,arrows=->]{\Tr[ref=#2,#1]{\psshadowbox[linewidth=0.05,linestyle=dashed]{#4}}}{#5}}

\newcommand\LineLabel[1]{\ncput*[fillcolor=\ContextColor]{\tiny #1}}
\begin{document}
\psset{linearc=0} % it makes a round corner of connection link

%%%%%%%%%%% EMAC CONTEXT %%%%%%%%%%%
%\psset{showbbox=true}

\def\ContextColor{ContextColorEmac}
\begin{context}{EMAC}
	\hspace{1cm}
	\uput[90](0,0){link}
	\TreeDot{l}{R}{
	  \TreeNode{l}{R}{\Fcn{link\_input}}{
	    \TreeNodeTabular{l}{R}{\Fcn{tcpip\_ethinput}\\Create mbox message}{
			\TreeNodeTabular[name=tcpipEthinput]{c}{R}{\Fcn{TCPIP\_MSG\_ETHINPUT}:\\received \texttt{pbuf}}{}
		}
    } } 
\end{context}

\def\ContextColor{ContextColorTcpip}
\def\ContextColorStrong{ContextColorTcpipStrong}
\begin{context}{TCP/IP}
 \begin{container}
	\TreeCircle[name=tcpipMbox]{c}{L}{\shortstack{tcpip\\mbox}}{
	  \TreeNode{c}{L}{\Fcn{tcpip\_thread}}{
	    \TreeNode{c}{D}{\Fcn{ethernet\_input}}{
		   \TreeNode{c}{D}{\Fcn{etharp\_arp\_input}}{\tlput{ARP}
		    \TreeNode{c}{D}{\Fcn{update\_arp\_entry}}{
		      	\TreeDot{c}{R}{}
				\uput[270](0,0){done}
		     }
		   }
	       \TreeNode{c}{D}{\Fcn{etharp\_ip\_input}}{\trput{IP}
		     \TreeNode[name=fromIP]{c}{D}{\Fcn{update\_arp\_entry}}{}
		   }
	}}}
	\\

	\psset{xbbh=-5}\TreeNodeTabular[name=toIP]{c}{D}{\Fcn{ip\_input} \\ \scriptsize choose the netif}{
	  \TreeNode[name=tcpipReass]{c}{D}{\Fcn{ip\_reass}}{\LineLabel{fragmented?}}
%	  \skiplevels{1}
	     \psset{xbbh=-.3}\TreeNode[name=tcpipRaw]{c}{D}{\Fcn{raw\_input}}{
		   \psset{xbbl=-3}\TreeDot{c}{R}{\LineLabel{eaten?}}\uput[180](0,0){done}
		   \psset{xbbl=3}\TreeDot{c}{D}{
		   \skiplevels{1}
		 	  \TreeCircle{t}{D}{\Fcn{upd\_input}}{\LineLabel{UDP}}
			  \TreeCircle{t}{D}{\Fcn{tcp\_input}}{\LineLabel{TCP}}
			  \TreeCircle{t}{D}{\Fcn{icmp\_input}}{\LineLabel{ICMP}}
			  \TreeCircle{t}{D}{\Fcn{igmp\_input}}{\LineLabel{IGMP}}
		   \endskiplevels
		   \psset{xbbl=-2}\TreeCircle[fillcolor=gray]{t}{D}{drop}{\LineLabel{else}}
			}
	     }
%	  \endskiplevels
	 \TreeNode{c}{R}{\Fcn{ip\_forward}}{\LineLabel{forward?}
	  	\TreeDot{c}{R}{}\uput[0](0,0){done}
	  }
    }
 \end{container}
\ncangle[angleA=0,angleB=0,linewidth=0.1,linestyle=dashed,armB=1]{->}{tcpipEthinput}{tcpipMbox}
\nccurve[angleA=0,angleB=180,linewidth=0.1,linearc=.2,armB=.5]{->}{tcpipReass}{tcpipRaw}
\ncline[angleA=270,angleB=90,linewidth=0.1]{->}{fromIP}{toIP}
\end{context}

\begin{context}{}
\begin{container}
	 
		\psset{xbbl=3cm}\TreeCircle{c}{R}{\Fcn{udp\_input}}{\TreeCircle{c}{R}{...}{}}
	         &
	     \TreeCircle{c}{R}{\Fcn{igmp\_input}}{\TreeCircle{c}{R}{...}{}}

\\
\TreeCircle{c}{R}{\Fcn{icmp\_input}}{
	\TreeNodeTabular{c}{R}{copy to \\ new \texttt{pbuf}}{\naput{\shortstack{\tiny ECHO/\\\tiny PING}}
		\TreeNode{c}{R}{\Fcn{ip\_output\_if}}{
			\TreeCircle{c}{R}{TX}{}
		}
	}
	\TreeCircle[fillcolor=gray]{c}{R}{drop}{\nbput{\tiny else}}
	}\psspan{2}
\\
\TreeCircle{c}{R}{\Fcn{tcp\_input}}{
	\TreeNodeTabular{c}{D}{For a conn in \\ \texttt{tcp\_active\_pcbs}?}{
	    \TreeNode{c}{D}{\Fcn{tcp\_process}}{\tlput{Yes}
	    	\skiplevels{3}
			   \TreeCircle[fillstyle=hlines,hatchwidth=0.1pt,hatchsep=2pt]{c}{D}{TCP FSM}{} 
			   \uput[0](1,0){(internals shown later)} 
			
			\endskiplevels
	    }
		\TreeNodeTabular{t}{D}{For \texttt{tcp\_tw\_pcbs}?}{\trput{No}
		   \TreeNode{t}{D}{\Fcn{tcp\_timewait\_input}}{\tlput{Yes}
			  \TreeNode{c}{D}{\Fcn{tcp\_ack\_now}}{}
		   }
		  \TreeNodeTabular{t}{D}{For \texttt{tcp\_listen\_pcbs}?}{\trput{No}
			\TreeNodeTabular{t}{D}{\Fcn{tcp\_listen\_input}}{\tlput{Yes}
				\psset{xbbh=1cm}\TreeNode{t}{D}{\Fcn{tcp\_rst}}{\tlput{ recv ACK}}
				\psset{xbbh=1cm}\TreeNodeTabular{t}{D}{\Fcn{tcp\_output}\\\tiny (send SYN/ACK)}{\trput{ recv SYN}}			
			}
			\TreeCircle[fillcolor=gray]{c}{D}{drop}{\trput{No}}
		   }
	    }
	}
}\psspan{2}
\end{container}
\end{context}

\begin{context}{}
\begin{container}
	\TreeCircle[fillstyle=hlines,hatchwidth=0.1pt,hatchsep=2pt]{c}{R}{TCP FSM}{
		\TreeNodeTabular{c}{R}{\texttt{if (ACK sent)} \\ \texttt{EVENT\_SENT}}{
			\TreeNodeTabular{c}{R}{\texttt{if (data avail)} \\ \texttt{EVENT\_RECV(data)}}{
				\TreeNodeTabular{c}{R}{\texttt{if (FIN)} \\ \texttt{EVENT\_RECV(NULL)}}{
					\TreeDot{c}{R}{}
					\uput[90](0,0){done} 
				}
			}
		}
	}
\\
	\begin{tabular}{|l|l|l|l|}
		\hline
		event fcn              &   \texttt{LWIP\_EVENT\_API} &  LWIP API          &  user-defined       \\
		\hline
		\texttt{EVENT\_SENT()} & \texttt{lwip\_tcp\_event()} & \texttt{sent\_tcp()} & \texttt{pcb->sent()}\\
		\texttt{EVENT\_RECV()} & \texttt{lwip\_tcp\_event()} & \texttt{recv\_tcp()} & \texttt{pcb->recv()}\\
		\texttt{EVENT\_ACCEPT()} & \texttt{lwip\_tcp\_event()} & \texttt{accept\_function()} & \texttt{pcb->accept()}\\
		\texttt{EVENT\_CONNECT()} & \texttt{lwip\_tcp\_event()} & \texttt{do\_connected()} & \texttt{pcb->connected()}\\
		\hline
	\end{tabular}
\\
	\uput[180](0,0){\texttt{EVENT\_RECV}}
	\TreeDot{c}{R}{
		\TreeNode{c}{R}{\Fcn{recv\_tcp}}{
			\TreeNodeTabular{l}{R}{call netconn callback \\ \texttt{conn-\textgreater{}callback(RECV+)}}{
				\TreeNodeTabular[name=recvPost]{l}{R}{Msg:\\ received \texttt{pbuf}}{}
			}
		}
	}
\end{container}
\end{context}

%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% USER
\def\ContextColor{ContextColorUser}
\def\ContextColorStrong{ContextColorUserStrong}
\begin{context}{User}
\begin{container}
	\TreeCircle[name=recvMbox]{t}{L}{\shortstack{netconn\\recvmbox}}{
		\TreeNodeTabular[name=recvFcn]{c}{L}{\Fcn{netconn\_recv} \\ convert \texttt{pbuf} to \texttt{netbuf}}{
			\TreeNodeTabular{c}{L}{call netconn callback \\ \texttt{conn-\textgreater{}callback(RECV-)}}{
				\TreeNodeTabular[name=recvExit]{c}{L}{\Fcn{TCPIP\_MSG\_API}:\\ \Fcn{do\_recv}}{}
			}
		}
	}
\\
	\TreeNodeExternal[name=userEstablished]{c}{L}{\shortstack{User Application \\ (ESTABLISHED)}}{}
	\ncangle[angleA=0,angleB=90,linewidth=0.1,linestyle=dashed]{->}{recvPost}{recvMbox}
	\ncangle[angleA=270,angleB=90,linewidth=0.1,armB=.75,offsetB=-.2cm]{->}{recvExit}{userEstablished}
	\ncangle[angleA=90,angleB=270,linewidth=0.1,armB=.75,offsetA=-.2cm]{->}{userEstablished}{recvFcn}
\end{container}
\end{context}

\def\ContextColor{ContextColorTcpip}
\def\ContextColorStrong{ContextColorTcpipStrong}
\begin{context}{}
\begin{container}
	\TreeCircle[name=tcpipMbox]{c}{R}{\shortstack{tcpip\\mbox}}{
		\TreeNode{c}{R}{\Fcn{do\_recv}}{
			\TreeNode{c}{R}{\shortstack{\Fcn{tcp\_recved} \\ adjust recv window \\ send ACK}}{
				\TreeDot{c}{R}{}
				\uput[90](0,0){done}
			}
		}
	}
\ncangle[angleA=270,angleB=90,linewidth=0.1,linestyle=dashed,offsetA=-.2cm,armB=1.25]{->}{recvExit}{tcpipMbox}	
\end{container}
\end{context}

%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% back to TCP/IP
\def\ContextColor{ContextColorTcpip}
\def\ContextColorStrong{ContextColorTcpipStrong}
\begin{context}{}
		\psframebox[fillcolor=\ContextColor,fillstyle=hlines,hatchwidth=0.1pt,hatchsep=2pt]{
			\begin{container}
				\TreeOval{c}{D}{SYN\_SENT}{
					\psset{xbbh=1cm}\TreeNode{t}{D}{\Fcn{tcp\_rst}}{\tlput{ recv ACK}}
					\psset{xbbh=1cm}\TreeNode{t}{D}{\Fcn{tcp\_ack}}{\trput{ recv SYN}
						\TreeNode{t}{D}{\Fcn{EVENT\_CONN}}{
							\TreeOval{t}{D}{next=ESTABLISHED}{
								\Tr{}
							}
						}
					}								
				} 
			  & \TreeOval{c}{D}{SYN\_RCVD}{
					\psset{xbbh=1cm}\TreeNode{t}{D}{\Fcn{tcp\_rst}}{\tlput{ recv ``bad'' ACK}}
					\psset{xbbh=1cm}\TreeNode{t}{D}{\Fcn{tcp\_ack}}{\trput{ recv ``good'' ACK}
						\TreeNode{t}{D}{\Fcn{EVENT\_ACCEPT}}{
							\TreeNodeExternal{t}{C}{\Fcn{tcp\_receive}}{
								\TreeOval{t}{D}{next=ESTABLISHED}{
									\Tr{}
								}
							}
						}
					}								
			    }
			 \\ \TreeOval{c}{D}{CLOSE\_WAIT}{
					\psset{xbbl=1cm}\TreeNodeExternal[name=CwEstJoiner]{c}{D}{\Fcn{tcp\_receive}}{
						\TreeOval{t}{D}{next=CLOSE\_WAIT}{\tlput{recv FIN}
							\TreeNode{t}{D}{\Fcn{tcp\_ack\_now}}{
								\Tr{}
							}
						}
						\def\psedge{\ncdiag[armA=0,angleA=270,angleB=90,armB=3.4]}
						\skiplevels{2}
							\Tr{}
						\endskiplevels						
					}							
			    }
				\TreeOval[name=Est]{c}{D}{ESTABLISHED}{}
				\ncdiag[angleA=270,angleB=0,linewidth=.1,armB=1]{->}{Est}{CwEstJoiner}
			  & \TreeOval{c}{D}{LAST\_ACK}{
					\TreeNodeExternal[name=CwEstJoiner]{t}{C}{\Fcn{tcp\_receive}}{
						\skiplevels{1}\def\psedge{\ncdiag[armA=0,angleA=270,angleB=90,armB=1.5]}
							\Tr{}
						\endskiplevels
						\TreeOval{t}{D}{next=CLOSED}{\trput{recv ``good'' ACK}
							\Tr{}
						}
					}
			    }
			\end{container}
		}
\end{context}

\begin{context}{}
	\begin{container}
		\psframebox[fillcolor=\ContextColor,fillstyle=hlines,hatchwidth=0.1pt,hatchsep=2pt]{
			\begin{container}
		  		\TreeOval{c}{D}{FIN\_WAIT\_1}{
					\TreeNodeExternal{t}{C}{\Fcn{tcp\_receive}}{
						\TreeOval{t}{D}{next=CLOSING}{\tlput{recv FIN}
							\TreeNode{t}{D}{\Fcn{tcp\_ack\_now}}{
								\Tr{}
							}
						}
						\TreeOval{t}{D}{next=FIN\_WAIT\_2}{\tlput{recv ACK}
							\TreeNode{t}{D}{\Fcn{tcp\_ack\_now}}{
								\Tr{}
							}
						}
						\TreeOval{t}{D}{next=TIME\_WAIT}{\trput{recv ACK/FIN}
							\skiplevels{1}
								\Tr{}
							\endskiplevels
						}
					}
			    }
			 \\ \TreeOval{c}{D}{FIN\_WAIT\_2}{
					\TreeNodeExternal{t}{C}{\Fcn{tcp\_receive}}{
						\TreeOval{t}{D}{next=TIME\_WAIT}{\tlput{recv FIN}
							\TreeNode{t}{D}{\Fcn{tcp\_ack\_now}}{
								\Tr{}
							}
						}
						\skiplevels{2}\def\psedge{\ncdiag[armA=0,angleA=270,angleB=90,armB=3.2]}
							\Tr{}
						\endskiplevels						
					}
			    }
			\end{container}
		}
		\\

			\TreeNodeExternal{c}{D}{\Fcn{tcp\_receive}}{
				\TreeNodeTabular{c}{R}{\small Handle ACK\\ \small in pkt hdr}{
					\TreeNodeTabular{c}{R}{Gather out-of-seq\\now in-seq}{
						\TreeNode{c}{R}{\Fcn{tcp\_ack}}{
							\TreeNode{c}{R}{return data}{
								\TreeDot[name=tcpReceiveExit]{c}{U}{
									\Tr{}
								}
							}
						}
					}
					\TreeNode{c}{R}{\Fcn{tcp\_ack}}{\tbput{\small out of seq}
						\TreeNodeTabular[name=OOSEQ]{c}{R}{add to OOSEQ queue \\ remove gaps}{}
						\ncdiag[angleA=0,angleB=225,linewidth=0.1]{->}{OOSEQ}{tcpReceiveExit}
					}
				}
			}

	\end{container}
\end{context}

\end{document}
