/* A really little IP stack using slip
   Use: nanotcp <>/dev/ttype
   azz@gnu.org
*/

#include <stdio.h>

#define MYIPA 192
#define MYIPB 168
#define MYIPC 1
#define MYIPD 42

unsigned char readrawbyte() {
  return (unsigned char)getchar();
}

/* Cope with SLIP escaping */
unsigned char unslip(unsigned char c) {
  if (c==219) {
    c=readrawbyte();
    if (c==220) return 192;
    if (c==221) return 219;
  }
  return c;
}

unsigned char readbyte() {
  return unslip(readrawbyte());
}

void putrawbyte(unsigned char c) {
  putchar((char)c);
}

void putbyte(unsigned char c) {
  if (c==192) {
    putrawbyte(219); putrawbyte(220);
  } else if (c==219) {
    putrawbyte(219); putrawbyte(221);
  } else putrawbyte(c);
}

int main() {
  unsigned char c, ihl, ipa, ipb, ipc, ipd, protocol, csa, csb;
  unsigned short int datalen, id, seqnum, x, y;

  while(1) {
    /* read packet */
    do {
      c=readrawbyte();
    } while (c==192); /* skip ENDs */
    c=unslip(c);
    ihl=c&15;
    fprintf(stderr, "Datagram VERSION=%d IHL=%d\n", c>>4, ihl);
    c=readbyte();
    fprintf(stderr, "Type of service=%d\n", c);
    c=readbyte();
    datalen=(c<<8)+readbyte();
    fprintf(stderr, "Total length=%d\n", datalen);
    c=5;while(c--)readbyte();
    protocol=readbyte();
    fprintf(stderr, "Protocol=%d\n", protocol);
    readbyte();readbyte();
    ipa=readbyte();ipb=readbyte();ipc=readbyte();ipd=readbyte();
    fprintf(stderr, "Source addr=%d.%d.%d.%d\n",ipa,ipb,ipc,ipd);
    c=4;while(c--)readbyte();
    ihl -= 5; datalen -= 20;
    while(ihl--) {
      c=4;while(c--)readbyte();
      datalen -= 4;
    }
    switch(protocol) {
    case 1: /* ICMP */
      fprintf(stderr, "That's an ICMP packet\n");
      c=readbyte();
      if (c==8) { /* Echo, aka PING */
	readbyte();csa=readbyte();csb=readbyte();
	c=readbyte();id=(c<<8)+readbyte();
	c=readbyte();seqnum=(c<<8)+readbyte();
	fprintf(stderr, "Echo cs=%02x%02x id=%d seq=%d\n", csa, csb, id, seqnum);
	/* now to send off a packet */
	putrawbyte(192); /* SLIP END */
	putbyte(4); putbyte(5);
	datalen += 20;
	putbyte(datalen >> 8); putbyte(datalen & 255);
	putbyte(0); putbyte(0); putbyte(0); putbyte(0);
	putbyte(255); putbyte(1);
	/* CHECKSUM */ putbyte(0);putbyte(0);
	putbyte(MYIPA); putbyte(MYIPB); putbyte(MYIPC); putbyte(MYIPD);
	putbyte(ipa);putbyte(ipb);putbyte(ipc);putbyte(ipd);
	/* dump back the data we were sent */
	while((c=readrawbyte())!=192) {
	  putbyte(unslip(c));
	}
      } else {
	/* now read 'til SLIP END */
	while((c=readrawbyte())!=192) {
	  c=unslip(c);
	  fprintf(stderr, "%02x ", c);
	}
	fprintf(stderr, "\n");
      }
      break;
    default: /* otherwise dump it */
      fprintf(stderr, "Remaining data (%d bytes):\n", datalen);
      while(datalen--) {
	fprintf(stderr, "%02x ", readbyte());
      }
      fprintf(stderr, "\n");
      break;
    }
  }
}
