xref: /plan9/sys/src/cmd/ip/snoopy/hdlc.c (revision ed397113cdcf7aafea372b730bbcd17b05ee3f60)
13ff48bf5SDavid du Colombier #include <u.h>
23ff48bf5SDavid du Colombier #include <libc.h>
33ff48bf5SDavid du Colombier #include <ip.h>
43ff48bf5SDavid du Colombier #include "dat.h"
53ff48bf5SDavid du Colombier #include "protos.h"
63ff48bf5SDavid du Colombier 
73ff48bf5SDavid du Colombier enum {
83ff48bf5SDavid du Colombier 	HDLC_frame=	0x7e,
93ff48bf5SDavid du Colombier 	HDLC_esc=	0x7d,
103ff48bf5SDavid du Colombier 
113ff48bf5SDavid du Colombier 	/* PPP frame fields */
123ff48bf5SDavid du Colombier 	PPP_addr=	0xff,
133ff48bf5SDavid du Colombier 	PPP_ctl=	0x3,
143ff48bf5SDavid du Colombier 	PPP_initfcs=	0xffff,
153ff48bf5SDavid du Colombier 	PPP_goodfcs=	0xf0b8,
163ff48bf5SDavid du Colombier };
173ff48bf5SDavid du Colombier 
183ff48bf5SDavid du Colombier /*
193ff48bf5SDavid du Colombier  * Calculate FCS - rfc 1331
203ff48bf5SDavid du Colombier  */
213ff48bf5SDavid du Colombier ushort fcstab[256] =
223ff48bf5SDavid du Colombier {
233ff48bf5SDavid du Colombier       0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
243ff48bf5SDavid du Colombier       0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
253ff48bf5SDavid du Colombier       0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
263ff48bf5SDavid du Colombier       0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
273ff48bf5SDavid du Colombier       0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
283ff48bf5SDavid du Colombier       0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
293ff48bf5SDavid du Colombier       0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
303ff48bf5SDavid du Colombier       0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
313ff48bf5SDavid du Colombier       0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
323ff48bf5SDavid du Colombier       0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
333ff48bf5SDavid du Colombier       0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
343ff48bf5SDavid du Colombier       0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
353ff48bf5SDavid du Colombier       0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
363ff48bf5SDavid du Colombier       0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
373ff48bf5SDavid du Colombier       0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
383ff48bf5SDavid du Colombier       0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
393ff48bf5SDavid du Colombier       0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
403ff48bf5SDavid du Colombier       0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
413ff48bf5SDavid du Colombier       0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
423ff48bf5SDavid du Colombier       0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
433ff48bf5SDavid du Colombier       0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
443ff48bf5SDavid du Colombier       0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
453ff48bf5SDavid du Colombier       0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
463ff48bf5SDavid du Colombier       0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
473ff48bf5SDavid du Colombier       0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
483ff48bf5SDavid du Colombier       0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
493ff48bf5SDavid du Colombier       0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
503ff48bf5SDavid du Colombier       0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
513ff48bf5SDavid du Colombier       0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
523ff48bf5SDavid du Colombier       0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
533ff48bf5SDavid du Colombier       0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
543ff48bf5SDavid du Colombier       0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
553ff48bf5SDavid du Colombier };
563ff48bf5SDavid du Colombier 
573ff48bf5SDavid du Colombier static uchar inbuf[16*1024];
583ff48bf5SDavid du Colombier static int inlen;
593ff48bf5SDavid du Colombier 
603ff48bf5SDavid du Colombier static Mux p_mux[] =
613ff48bf5SDavid du Colombier {
623ff48bf5SDavid du Colombier 	{"ppp",		(PPP_addr<<8)|PPP_ctl,	} ,
633ff48bf5SDavid du Colombier 	{0}
643ff48bf5SDavid du Colombier };
653ff48bf5SDavid du Colombier 
663ff48bf5SDavid du Colombier enum
673ff48bf5SDavid du Colombier {
683ff48bf5SDavid du Colombier 	Ot = 1
693ff48bf5SDavid du Colombier };
703ff48bf5SDavid du Colombier 
713ff48bf5SDavid du Colombier static void
p_compile(Filter * f)723ff48bf5SDavid du Colombier p_compile(Filter *f)
733ff48bf5SDavid du Colombier {
743ff48bf5SDavid du Colombier 	Mux *m;
753ff48bf5SDavid du Colombier 
763ff48bf5SDavid du Colombier 	for(m = p_mux; m->name != nil; m++)
773ff48bf5SDavid du Colombier 		if(strcmp(f->s, m->name) == 0){
783ff48bf5SDavid du Colombier 			f->pr = m->pr;
793ff48bf5SDavid du Colombier 			f->ulv = m->val;
803ff48bf5SDavid du Colombier 			f->subop = Ot;
813ff48bf5SDavid du Colombier 			return;
823ff48bf5SDavid du Colombier 		}
833ff48bf5SDavid du Colombier 	sysfatal("unknown ethernet field or protocol: %s", f->s);
843ff48bf5SDavid du Colombier }
853ff48bf5SDavid du Colombier 
863ff48bf5SDavid du Colombier static int
p_filter(Filter * f,Msg * m)873ff48bf5SDavid du Colombier p_filter(Filter *f, Msg *m)
883ff48bf5SDavid du Colombier {
893ff48bf5SDavid du Colombier 	ulong t;
903ff48bf5SDavid du Colombier 
913ff48bf5SDavid du Colombier 	if(m->pe-m->ps < 2)
923ff48bf5SDavid du Colombier 		return 0;
933ff48bf5SDavid du Colombier 
943ff48bf5SDavid du Colombier 	switch(f->subop){
953ff48bf5SDavid du Colombier 	case Ot:
963ff48bf5SDavid du Colombier 		t = (m->ps[0]<<8)|m->ps[1];
973ff48bf5SDavid du Colombier 		if(t != f->ulv)
983ff48bf5SDavid du Colombier 			return 0;
993ff48bf5SDavid du Colombier 		break;
1003ff48bf5SDavid du Colombier 	}
1013ff48bf5SDavid du Colombier 	return 1;
1023ff48bf5SDavid du Colombier }
1033ff48bf5SDavid du Colombier 
1043ff48bf5SDavid du Colombier static int
p_seprint(Msg * m)1053ff48bf5SDavid du Colombier p_seprint(Msg *m)
1063ff48bf5SDavid du Colombier {
1073ff48bf5SDavid du Colombier 	ulong t;
1083ff48bf5SDavid du Colombier 
1093ff48bf5SDavid du Colombier 	if(m->pe-m->ps < 2)
1103ff48bf5SDavid du Colombier 		return -1;
1113ff48bf5SDavid du Colombier 
1123ff48bf5SDavid du Colombier 	t = (m->ps[0]<<8)|m->ps[1];
1133ff48bf5SDavid du Colombier 	m->ps += 2;
1143ff48bf5SDavid du Colombier 	demux(p_mux, t, t, m, &dump);
1153ff48bf5SDavid du Colombier 
1163ff48bf5SDavid du Colombier 	return 0;
1173ff48bf5SDavid du Colombier }
1183ff48bf5SDavid du Colombier 
1193ff48bf5SDavid du Colombier static int
p_framer(int fd,uchar * pkt,int pktlen)1203ff48bf5SDavid du Colombier p_framer(int fd, uchar *pkt, int pktlen)
1213ff48bf5SDavid du Colombier {
1223ff48bf5SDavid du Colombier 	ushort fcs;
1233ff48bf5SDavid du Colombier 	uchar *from, *efrom, *to, *eto;
1243ff48bf5SDavid du Colombier 	int n;
1253ff48bf5SDavid du Colombier 	ulong c;
1263ff48bf5SDavid du Colombier 
1273ff48bf5SDavid du Colombier 	eto = pkt+pktlen;
1283ff48bf5SDavid du Colombier 	for(;;){
1293ff48bf5SDavid du Colombier 		efrom = memchr(inbuf, HDLC_frame, inlen);
1303ff48bf5SDavid du Colombier 		if(efrom == nil){
1313ff48bf5SDavid du Colombier 			if(inlen >= sizeof(inbuf))
1323ff48bf5SDavid du Colombier 				inlen = 0;
1333ff48bf5SDavid du Colombier 			n = read(fd, inbuf+inlen, sizeof(inbuf)-inlen);
1343ff48bf5SDavid du Colombier 			if(n <= 0)
1353ff48bf5SDavid du Colombier 				break;
1363ff48bf5SDavid du Colombier 			inlen += n;
1373ff48bf5SDavid du Colombier 			continue;
1383ff48bf5SDavid du Colombier 		}
1393ff48bf5SDavid du Colombier 
1403ff48bf5SDavid du Colombier 		/* checksum and unescape the frame */
1413ff48bf5SDavid du Colombier 		fcs = PPP_initfcs;
1423ff48bf5SDavid du Colombier 		to = pkt;
1433ff48bf5SDavid du Colombier 		for(from = inbuf; from < efrom;){
1443ff48bf5SDavid du Colombier 			c = *from++;
1453ff48bf5SDavid du Colombier 			if(c == HDLC_esc)
1463ff48bf5SDavid du Colombier 				c = (*from++) ^ 0x20;
1473ff48bf5SDavid du Colombier 			if(to < eto)
1483ff48bf5SDavid du Colombier 				*to++ = c;
1493ff48bf5SDavid du Colombier 			fcs = (fcs >> 8) ^ fcstab[(fcs ^ c) & 0xff];
1503ff48bf5SDavid du Colombier 		}
1513ff48bf5SDavid du Colombier 
1523ff48bf5SDavid du Colombier 		/* move down anything that's left */
1533ff48bf5SDavid du Colombier 		inlen -= efrom+1-inbuf;
1543ff48bf5SDavid du Colombier 		memmove(inbuf, efrom+1, inlen);
1553ff48bf5SDavid du Colombier 
1563ff48bf5SDavid du Colombier 		/* accept if this is a good packet */
1573ff48bf5SDavid du Colombier 		if(fcs != PPP_goodfcs)
1586b6b9ac8SDavid du Colombier 			print("bad frame %ld %2.2ux %2.2ux!\n", to-pkt, pkt[0], pkt[1]);
1593ff48bf5SDavid du Colombier 		else
1603ff48bf5SDavid du Colombier 			return to-pkt;
1613ff48bf5SDavid du Colombier 	}
1623ff48bf5SDavid du Colombier 	return -1;
1633ff48bf5SDavid du Colombier }
1643ff48bf5SDavid du Colombier 
1653ff48bf5SDavid du Colombier Proto hdlc =
1663ff48bf5SDavid du Colombier {
1673ff48bf5SDavid du Colombier 	"hdlc",
1683ff48bf5SDavid du Colombier 	p_compile,
1693ff48bf5SDavid du Colombier 	p_filter,
1703ff48bf5SDavid du Colombier 	p_seprint,
1713ff48bf5SDavid du Colombier 	p_mux,
172*ed397113SDavid du Colombier 	"%#.4lux",
1733ff48bf5SDavid du Colombier 	nil,
1743ff48bf5SDavid du Colombier 	p_framer,
1753ff48bf5SDavid du Colombier };
176