%include "INet:Formats.Inc" %externalpredicatespec FS lookup(%string(31) what, %integername value) %systemroutinespec phex(%integer x) %systemstring(127)%fnspec itos(%integer n, p) %constinteger max TCP trace = 127; ! Suitable for masking %ownstring(31) TCP trace name = "INET__TCP_TRACE_BUFFER" %constinteger TCP trace data = 96 %constinteger TCP trace in = 1 %constinteger TCP trace out = 2 %constinteger TCP trace reTX = 3 %constinteger TCP trace check = 4 %constinteger TCP trace ACK = 5 %recordformat TCP trace fm(%integer inout, data bytes, %record(TCB fm) TCB, %record(TCP header fm) TCP header, %bytearray data(1 : TCP trace data)) %constinteger TCP trace size = 4 + 4 + TCB size + %c TCP header size + 4 {options} + TCP trace data %recordformat TCP trace buffer fm(%integer next, %record(TCP trace fm)%array t(0 : max TCP trace)) %include "INet:Dump.Inc" %routine print INet address(%integer addr) write(addr >> 24 & 255, 0); print symbol('.') write(addr >> 16 & 255, 0); print symbol('.') write(addr >> 8 & 255, 0); print symbol('.') write(addr & 255, 0) %end %routine print TCB address(%record(TCB fm)%name t) print inet address(t_remote address) print symbol('.'); write(t_remote port, 0) print symbol('/'); write(t_local port, 0) %end %routine show TCP header(%record(TCP header fm)%name h, %integer n, %string(15) s) printstring("TCP "); printstring(s) printstring(" -- source: "); write(h_source, 0) printstring(", dest: "); write(h_destination, 0) printstring(", seq: "); phex(h_seq) printstring(", ack: "); phex(h_ack) printstring(" FIN") %if h_flags & FIN bit # 0 printstring(" SYN") %if h_flags & SYN bit # 0 printstring(" RST") %if h_flags & RST bit # 0 printstring(" PSH") %if h_flags & PSH bit # 0 printstring(" ACK") %if h_flags & ACK bit # 0 printstring(" URG") %if h_flags & URG bit # 0 %if n # 0 %start printstring(" + "); write(n, 0) %finish newline printstring("Window: "); write(h_window, 0) printstring(", urgent: ") %and write(h_urgent, 0) %if h_flags & URG bit # 0 newline %if (h_data offset >> 4) & 15 > 5 %start ! Options printstring("Options: "); phex(h_options); newline %finish %end %routine show TCB(%record(TCB fm)%name TCB) %integer now, offset %if TCB_local port = 0 %start printstring("*free*"); newline %return %finish print inet address(TCB_remote address); print symbol('.') write(TCB_remote port, 0); printstring(" <--> ") write(TCB_local port, 0); newline printstring("State "); printstring(TCP state name(TCB_state)) printstring(", from "); printstring(TCP state name(TCB_previous state)) ! now = msecs timestamp ! offset = now - TCB_state change stamp ! printstring(", changed ") ! %if offset >= 0 %start ! write(offset, 0); printstring(" msec") ! print symbol('s') %if offset # 1 ! %else ! printstring("ages") ! %finish ! printstring(" ago") newline printstring("Snd nxt: "); phex(TCB_snd nxt) printstring(", ISS: "); phex(TCB_iss) printstring(", sent: "); write(TCB_snd nxt - TCB_iss, 0) printstring(", una: "); phex(TCB_snd una) printstring(", window: "); write(TCB_snd wnd, 0); newline printstring("RTT: rto "); write(TCB_rto, 0) printstring(", avg "); write(TCB_avg, 0) printstring(", mdev "); write(TCB_mdev, 0); newline printstring("Rcv nxt: "); phex(TCB_rcv nxt) printstring(", IRS: "); phex(TCB_irs) printstring(", received: "); write(TCB_rcv nxt - TCB_irs, 0) printstring(", window: "); write(TCB_rcv wnd, 0); newline %end %routine show one(%record(TCP trace fm)%name t) %integer dumping, diff %return %if t_TCB_local port = 0; ! Unused !! printstring("One at "); phex(addr(t)); newline !! print TCB address(t_TCB); newline %if t_inout = TCP trace in %start show TCP header(t_TCP header, t_data bytes, "in") %else %if t_inout = TCP trace out show TCP header(t_TCP header, t_data bytes, "out") %else %if t_inout = TCP trace reTX show TCP header(t_TCP header, t_data bytes, "reTX") %else show TCP header(t_TCP header, t_data bytes, itos(t_inout, 0) . " ??") %finish dumping = t_data bytes dumping = TCP trace data %if dumping > TCP trace data dump(t_data(1), dumping) %if dumping > 0 show TCB(t_TCB) %if t_inout = TCP trace in %start diff = t_TCP header_seq - t_TCB_rcv nxt %if diff # 0 %start printstring("Receive: ") print symbol('+') %if diff > 0 write(diff, 0); newline %finish diff = t_TCP header_ack - t_TCB_snd nxt %if diff # 0 %start printstring("ACK: ") print symbol('+') %if diff > 0 write(diff, 0); newline %finish %else %if t_inout = TCP trace out %or t_inout = TCP trace reTX diff = t_TCP header_seq - t_TCB_snd nxt %if diff # 0 %start printstring("Transmit: ") print symbol('+') %if diff > 0 write(diff, 0); newline %finish %finish newline %end %begin %record(TCP trace buffer fm)%name TCP trace buffer %string(255) out file %integer status, i %if FS lookup(TCP trace name, i) %start TCP trace buffer == record(i) %else printstring("No TCP trace buffer"); newline %stop %finish !! printstring("TCP trace buffer mapped at ") !! phex(addr(TCP trace buffer)); newline out file = CLI param out file = ":T" %if out file = "" open output(3, out file); select output(3) show one(TCP trace buffer_t(i & max TCP trace)) %c %for i = TCP trace buffer_next, 1, TCP trace buffer_next + max TCP trace + 1 close output select output(0) %end %of %program