19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <ip.h>
49a747e4fSDavid du Colombier #include "dat.h"
59a747e4fSDavid du Colombier #include "protos.h"
69a747e4fSDavid du Colombier
79a747e4fSDavid du Colombier typedef struct Hdr Hdr;
89a747e4fSDavid du Colombier struct Hdr
99a747e4fSDavid du Colombier {
109a747e4fSDavid du Colombier uchar sport[2];
119a747e4fSDavid du Colombier uchar dport[2];
129a747e4fSDavid du Colombier uchar seq[4];
139a747e4fSDavid du Colombier uchar ack[4];
149a747e4fSDavid du Colombier uchar flag[2];
159a747e4fSDavid du Colombier uchar win[2];
169a747e4fSDavid du Colombier uchar cksum[2];
179a747e4fSDavid du Colombier uchar urg[2];
186b6b9ac8SDavid du Colombier uchar opt[1];
199a747e4fSDavid du Colombier };
209a747e4fSDavid du Colombier
219a747e4fSDavid du Colombier typedef struct PseudoHdr{
229a747e4fSDavid du Colombier uchar src[4];
239a747e4fSDavid du Colombier uchar dst[4];
249a747e4fSDavid du Colombier uchar zero;
259a747e4fSDavid du Colombier uchar proto;
269a747e4fSDavid du Colombier uchar length[2];
279a747e4fSDavid du Colombier uchar hdrdata[1580];
289a747e4fSDavid du Colombier } PseudoHdr;
299a747e4fSDavid du Colombier
309a747e4fSDavid du Colombier enum
319a747e4fSDavid du Colombier {
329a747e4fSDavid du Colombier TCPLEN= 20,
339a747e4fSDavid du Colombier };
349a747e4fSDavid du Colombier
359a747e4fSDavid du Colombier enum
369a747e4fSDavid du Colombier {
379a747e4fSDavid du Colombier Os,
389a747e4fSDavid du Colombier Od,
399a747e4fSDavid du Colombier Osd,
409a747e4fSDavid du Colombier };
419a747e4fSDavid du Colombier
429a747e4fSDavid du Colombier static Field p_fields[] =
439a747e4fSDavid du Colombier {
449a747e4fSDavid du Colombier {"s", Fnum, Os, "source port", } ,
459a747e4fSDavid du Colombier {"d", Fnum, Od, "dest port", } ,
46dc5a79c1SDavid du Colombier {"a", Fnum, Osd, "source/dest port", } ,
479a747e4fSDavid du Colombier {"sd", Fnum, Osd, "source/dest port", } ,
489a747e4fSDavid du Colombier {0}
499a747e4fSDavid du Colombier };
509a747e4fSDavid du Colombier
519a747e4fSDavid du Colombier static Mux p_mux[] =
529a747e4fSDavid du Colombier {
53b4b9fc2fSDavid du Colombier {"dns", 53, },
549a747e4fSDavid du Colombier {"ninep", 17007, }, /* exportfs */
559a747e4fSDavid du Colombier {"ninep", 564, }, /* 9fs */
569a747e4fSDavid du Colombier {"ninep", 17005, }, /* ocpu */
579a747e4fSDavid du Colombier {"ninep", 17010, }, /* ncpu */
589a747e4fSDavid du Colombier {"ninep", 17013, }, /* cpu */
599a747e4fSDavid du Colombier {0},
609a747e4fSDavid du Colombier };
619a747e4fSDavid du Colombier
626b6b9ac8SDavid du Colombier enum
636b6b9ac8SDavid du Colombier {
646b6b9ac8SDavid du Colombier EOLOPT = 0,
656b6b9ac8SDavid du Colombier NOOPOPT = 1,
666b6b9ac8SDavid du Colombier MSSOPT = 2,
676b6b9ac8SDavid du Colombier MSS_LENGTH = 4, /* Mean segment size */
686b6b9ac8SDavid du Colombier WSOPT = 3,
696b6b9ac8SDavid du Colombier WS_LENGTH = 3, /* Bits to scale window size by */
706b6b9ac8SDavid du Colombier };
716b6b9ac8SDavid du Colombier
729a747e4fSDavid du Colombier static void
p_compile(Filter * f)739a747e4fSDavid du Colombier p_compile(Filter *f)
749a747e4fSDavid du Colombier {
759a747e4fSDavid du Colombier Mux *m;
769a747e4fSDavid du Colombier
779a747e4fSDavid du Colombier if(f->op == '='){
780b9a5132SDavid du Colombier compile_cmp(tcp.name, f, p_fields);
799a747e4fSDavid du Colombier return;
809a747e4fSDavid du Colombier }
819a747e4fSDavid du Colombier for(m = p_mux; m->name != nil; m++)
829a747e4fSDavid du Colombier if(strcmp(f->s, m->name) == 0){
839a747e4fSDavid du Colombier f->pr = m->pr;
849a747e4fSDavid du Colombier f->ulv = m->val;
853ff48bf5SDavid du Colombier f->subop = Osd;
869a747e4fSDavid du Colombier return;
879a747e4fSDavid du Colombier }
889a747e4fSDavid du Colombier sysfatal("unknown tcp field or protocol: %s", f->s);
899a747e4fSDavid du Colombier }
909a747e4fSDavid du Colombier
919a747e4fSDavid du Colombier static int
p_filter(Filter * f,Msg * m)929a747e4fSDavid du Colombier p_filter(Filter *f, Msg *m)
939a747e4fSDavid du Colombier {
949a747e4fSDavid du Colombier Hdr *h;
959a747e4fSDavid du Colombier
969a747e4fSDavid du Colombier if(m->pe - m->ps < TCPLEN)
979a747e4fSDavid du Colombier return 0;
989a747e4fSDavid du Colombier
999a747e4fSDavid du Colombier h = (Hdr*)m->ps;
100*e6dcbf51SDavid du Colombier m->ps += (NetS(h->flag)>>10) & 0x3f;
1019a747e4fSDavid du Colombier
1029a747e4fSDavid du Colombier switch(f->subop){
1039a747e4fSDavid du Colombier case Os:
1049a747e4fSDavid du Colombier return NetS(h->sport) == f->ulv;
1059a747e4fSDavid du Colombier case Od:
1069a747e4fSDavid du Colombier return NetS(h->dport) == f->ulv;
1079a747e4fSDavid du Colombier case Osd:
1089a747e4fSDavid du Colombier return NetS(h->sport) == f->ulv || NetS(h->dport) == f->ulv;
1099a747e4fSDavid du Colombier }
1109a747e4fSDavid du Colombier return 0;
1119a747e4fSDavid du Colombier }
1129a747e4fSDavid du Colombier
1139a747e4fSDavid du Colombier enum
1149a747e4fSDavid du Colombier {
1159a747e4fSDavid du Colombier URG = 0x20, /* Data marked urgent */
1169a747e4fSDavid du Colombier ACK = 0x10, /* Aknowledge is valid */
1179a747e4fSDavid du Colombier PSH = 0x08, /* Whole data pipe is pushed */
1189a747e4fSDavid du Colombier RST = 0x04, /* Reset connection */
1199a747e4fSDavid du Colombier SYN = 0x02, /* Pkt. is synchronise */
1209a747e4fSDavid du Colombier FIN = 0x01, /* Start close down */
1219a747e4fSDavid du Colombier };
1229a747e4fSDavid du Colombier
1239a747e4fSDavid du Colombier static char*
flags(int f)1249a747e4fSDavid du Colombier flags(int f)
1259a747e4fSDavid du Colombier {
1269a747e4fSDavid du Colombier static char fl[20];
1279a747e4fSDavid du Colombier char *p;
1289a747e4fSDavid du Colombier
1299a747e4fSDavid du Colombier p = fl;
1309a747e4fSDavid du Colombier if(f & URG)
1319a747e4fSDavid du Colombier *p++ = 'U';
1329a747e4fSDavid du Colombier if(f & ACK)
1339a747e4fSDavid du Colombier *p++ = 'A';
1349a747e4fSDavid du Colombier if(f & PSH)
1359a747e4fSDavid du Colombier *p++ = 'P';
1369a747e4fSDavid du Colombier if(f & RST)
1379a747e4fSDavid du Colombier *p++ = 'R';
1389a747e4fSDavid du Colombier if(f & SYN)
1399a747e4fSDavid du Colombier *p++ = 'S';
1409a747e4fSDavid du Colombier if(f & FIN)
1419a747e4fSDavid du Colombier *p++ = 'F';
1429a747e4fSDavid du Colombier *p = 0;
1439a747e4fSDavid du Colombier return fl;
1449a747e4fSDavid du Colombier }
1459a747e4fSDavid du Colombier
1469a747e4fSDavid du Colombier
1479a747e4fSDavid du Colombier static int
p_seprint(Msg * m)1489a747e4fSDavid du Colombier p_seprint(Msg *m)
1499a747e4fSDavid du Colombier {
150*e6dcbf51SDavid du Colombier int dport, sport, len, flag, optlen;
1516b6b9ac8SDavid du Colombier uchar *optr;
152*e6dcbf51SDavid du Colombier Hdr *h;
1539a747e4fSDavid du Colombier
1549a747e4fSDavid du Colombier if(m->pe - m->ps < TCPLEN)
1559a747e4fSDavid du Colombier return -1;
1569a747e4fSDavid du Colombier h = (Hdr*)m->ps;
1579a747e4fSDavid du Colombier
1589a747e4fSDavid du Colombier /* get tcp header length */
1599a747e4fSDavid du Colombier flag = NetS(h->flag);
1606b6b9ac8SDavid du Colombier len = (flag>>10) & ~3;
1619a747e4fSDavid du Colombier flag &= 0x3ff;
1629a747e4fSDavid du Colombier m->ps += len;
1639a747e4fSDavid du Colombier
1649a747e4fSDavid du Colombier /* next protocol */
1659a747e4fSDavid du Colombier dport = NetS(h->dport);
1669a747e4fSDavid du Colombier sport = NetS(h->sport);
1679a747e4fSDavid du Colombier demux(p_mux, sport, dport, m, &dump);
1689a747e4fSDavid du Colombier
1699a747e4fSDavid du Colombier m->p = seprint(m->p, m->e, "s=%d d=%d seq=%lud ack=%lud fl=%s win=%d ck=%4.4ux",
1709a747e4fSDavid du Colombier NetS(h->sport), dport,
1719a747e4fSDavid du Colombier (ulong)NetL(h->seq), (ulong)NetL(h->ack),
1729a747e4fSDavid du Colombier flags(flag), NetS(h->win),
1739a747e4fSDavid du Colombier NetS(h->cksum));
1749a747e4fSDavid du Colombier
1756b6b9ac8SDavid du Colombier /* tcp options */
1766b6b9ac8SDavid du Colombier len -= TCPLEN;
1776b6b9ac8SDavid du Colombier optr = h->opt;
1786b6b9ac8SDavid du Colombier while(len > 0) {
1796b6b9ac8SDavid du Colombier if(*optr == EOLOPT){
1806b6b9ac8SDavid du Colombier m->p = seprint(m->p, m->e, " opt=EOL");
1816b6b9ac8SDavid du Colombier break;
1826b6b9ac8SDavid du Colombier }
1836b6b9ac8SDavid du Colombier if(*optr == NOOPOPT) {
1846b6b9ac8SDavid du Colombier m->p = seprint(m->p, m->e, " opt=NOOP");
1856b6b9ac8SDavid du Colombier len--;
1866b6b9ac8SDavid du Colombier optr++;
1876b6b9ac8SDavid du Colombier continue;
1886b6b9ac8SDavid du Colombier }
1896b6b9ac8SDavid du Colombier optlen = optr[1];
1906b6b9ac8SDavid du Colombier if(optlen < 2 || optlen > len)
1916b6b9ac8SDavid du Colombier break;
1926b6b9ac8SDavid du Colombier switch(*optr) {
1936b6b9ac8SDavid du Colombier case MSSOPT:
194*e6dcbf51SDavid du Colombier m->p = seprint(m->p, m->e, " opt%d=(mss %ud)",
195*e6dcbf51SDavid du Colombier optlen, nhgets(optr+2));
1966b6b9ac8SDavid du Colombier break;
1976b6b9ac8SDavid du Colombier case WSOPT:
198*e6dcbf51SDavid du Colombier m->p = seprint(m->p, m->e, " opt%d=(wscale %ud)",
199*e6dcbf51SDavid du Colombier optlen, *(optr+2));
2006b6b9ac8SDavid du Colombier break;
2016b6b9ac8SDavid du Colombier default:
202*e6dcbf51SDavid du Colombier m->p = seprint(m->p, m->e, " opt%d=(%ud %.*H)",
203*e6dcbf51SDavid du Colombier optlen, *optr, optlen-2, optr+2);
2046b6b9ac8SDavid du Colombier }
2056b6b9ac8SDavid du Colombier len -= optlen;
2066b6b9ac8SDavid du Colombier optr += optlen;
2076b6b9ac8SDavid du Colombier }
2089a747e4fSDavid du Colombier return 0;
2099a747e4fSDavid du Colombier }
2109a747e4fSDavid du Colombier
2119a747e4fSDavid du Colombier Proto tcp =
2129a747e4fSDavid du Colombier {
2139a747e4fSDavid du Colombier "tcp",
2149a747e4fSDavid du Colombier p_compile,
2159a747e4fSDavid du Colombier p_filter,
2169a747e4fSDavid du Colombier p_seprint,
2179a747e4fSDavid du Colombier p_mux,
218ed397113SDavid du Colombier "%lud",
2199a747e4fSDavid du Colombier p_fields,
2203ff48bf5SDavid du Colombier defaultframer,
2219a747e4fSDavid du Colombier };
222