1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include "dat.h"
5 #include "protos.h"
6 
7 typedef struct Hdr	Hdr;
8 struct Hdr
9 {
10 	uchar	sport[2];
11 	uchar	dport[2];
12 	uchar	seq[4];
13 	uchar	ack[4];
14 	uchar	flag[2];
15 	uchar	win[2];
16 	uchar	cksum[2];
17 	uchar	urg[2];
18 	uchar	opt[1];
19 };
20 
21 typedef struct PseudoHdr{
22 	uchar	src[4];
23 	uchar	dst[4];
24 	uchar	zero;
25 	uchar	proto;
26 	uchar	length[2];
27 	uchar	hdrdata[1580];
28 } PseudoHdr;
29 
30 enum
31 {
32 	TCPLEN= 20
33 };
34 
35 enum
36 {
37 	Os,
38 	Od,
39 	Osd
40 };
41 
42 static Field p_fields[] =
43 {
44 	{"s",		Fnum,	Os,	"source port",	} ,
45 	{"d",		Fnum,	Od,	"dest port",	} ,
46 	{"a",		Fnum,	Osd,	"source/dest port",	} ,
47 	{"sd",		Fnum,	Osd,	"source/dest port",	} ,
48 	{0}
49 };
50 
51 static Mux p_mux[] =
52 {
53 	{"ninep",	17007, },	/* exportfs */
54 	{"ninep",	564, },		/* 9fs */
55 	{"ninep",	17005, },	/* ocpu */
56 	{"ninep",	17010, },	/* ncpu */
57 	{"ninep",	17013, },	/* cpu */
58 	{0}
59 };
60 
61 enum
62 {
63 	EOLOPT		= 0,
64 	NOOPOPT		= 1,
65 	MSSOPT		= 2,
66 	MSS_LENGTH	= 4,		/* Mean segment size */
67 	WSOPT		= 3,
68 	WS_LENGTH	= 3,		/* Bits to scale window size by */
69 };
70 
71 static void
p_compile(Filter * f)72 p_compile(Filter *f)
73 {
74 	Mux *m;
75 
76 	if(f->op == '='){
77 		compile_cmp(udp.name, f, p_fields);
78 		return;
79 	}
80 	for(m = p_mux; m->name != nil; m++)
81 		if(strcmp(f->s, m->name) == 0){
82 			f->pr = m->pr;
83 			f->ulv = m->val;
84 			f->subop = Osd;
85 			return;
86 		}
87 	sysfatal("unknown tcp field or protocol: %s", f->s);
88 }
89 
90 static int
p_filter(Filter * f,Msg * m)91 p_filter(Filter *f, Msg *m)
92 {
93 	Hdr *h;
94 
95 	if(m->pe - m->ps < TCPLEN)
96 		return 0;
97 
98 	h = (Hdr*)m->ps;
99 	m->ps += ((NetS(h->flag)>>10)&0x3f);
100 
101 	switch(f->subop){
102 	case Os:
103 		return NetS(h->sport) == f->ulv;
104 	case Od:
105 		return NetS(h->dport) == f->ulv;
106 	case Osd:
107 		return NetS(h->sport) == f->ulv || NetS(h->dport) == f->ulv;
108 	}
109 	return 0;
110 }
111 
112 enum
113 {
114 	URG		= 0x20,		/* Data marked urgent */
115 	ACK		= 0x10,		/* Aknowledge is valid */
116 	PSH		= 0x08,		/* Whole data pipe is pushed */
117 	RST		= 0x04,		/* Reset connection */
118 	SYN		= 0x02,		/* Pkt. is synchronise */
119 	FIN		= 0x01,		/* Start close down */
120 };
121 
122 static char*
flags(int f)123 flags(int f)
124 {
125 	static char fl[20];
126 	char *p;
127 
128 	p = fl;
129 	if(f & URG)
130 		*p++ = 'U';
131 	if(f & ACK)
132 		*p++ = 'A';
133 	if(f & PSH)
134 		*p++ = 'P';
135 	if(f & RST)
136 		*p++ = 'R';
137 	if(f & SYN)
138 		*p++ = 'S';
139 	if(f & FIN)
140 		*p++ = 'F';
141 	*p = 0;
142 	return fl;
143 }
144 
145 
146 static int
p_seprint(Msg * m)147 p_seprint(Msg *m)
148 {
149 	Hdr *h;
150 	int dport, sport;
151 	int len, flag, optlen;
152 	uchar *optr;
153 
154 	if(m->pe - m->ps < TCPLEN)
155 		return -1;
156 	h = (Hdr*)m->ps;
157 
158 	/* get tcp header length */
159 	flag = NetS(h->flag);
160 	len = (flag>>10)&~3;
161 	flag &= 0x3ff;
162 	m->ps += len;
163 
164 	/* next protocol */
165 	dport = NetS(h->dport);
166 	sport = NetS(h->sport);
167 	demux(p_mux, sport, dport, m, &dump);
168 
169 	m->p = seprint(m->p, m->e, "s=%d d=%d seq=%lud ack=%lud fl=%s win=%d ck=%4.4ux",
170 			NetS(h->sport), dport,
171 			(ulong)NetL(h->seq), (ulong)NetL(h->ack),
172 			flags(flag), NetS(h->win),
173 			NetS(h->cksum));
174 
175 	/* tcp options */
176 	len -= TCPLEN;
177 	optr = h->opt;
178 	while(len > 0) {
179 		if(*optr == EOLOPT){
180 			m->p = seprint(m->p, m->e, " opt=EOL");
181 			break;
182 		}
183 		if(*optr == NOOPOPT) {
184 			m->p = seprint(m->p, m->e, " opt=NOOP");
185 			len--;
186 			optr++;
187 			continue;
188 		}
189 		optlen = optr[1];
190 		if(optlen < 2 || optlen > len)
191 			break;
192 		switch(*optr) {
193 		case MSSOPT:
194 			m->p = seprint(m->p, m->e, " opt%d=(mss %ud)", optlen, nhgets(optr+2));
195 			break;
196 		case WSOPT:
197 			m->p = seprint(m->p, m->e, " opt%d=(wscale %ud)", optlen, *(optr+2));
198 			break;
199 		default:
200 			m->p = seprint(m->p, m->e, " opt%d=(%ud %.*H)", optlen, *optr, optlen-2,optr+2);
201 		}
202 		len -= optlen;
203 		optr += optlen;
204 	}
205 
206 	if(Cflag){
207 		/* editing in progress by ehg */
208 	}
209 	return 0;
210 }
211 
212 Proto tcp =
213 {
214 	"tcp",
215 	p_compile,
216 	p_filter,
217 	p_seprint,
218 	p_mux,
219 	"%lud",
220 	p_fields,
221 	defaultframer
222 };
223