/*

   ppp finite state machine for LCP and IPCP

   Copyright Kate Marika Alhola 1992

   Adapted to Linux by Kate Alhola, and Matti Aarnio

 */

#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <termio.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include <fcntl.h>


#define   PROTO_LCP    0x100
#define   PROTO_IPCP   0x200

#define   PPP_Initial  0
#define   PPP_Starting 1
#define   PPP_Closed   2
#define   PPP_Stoped   3
#define   PPP_Closing  4
#define   PPP_Stoping  5
#define   PPP_ReqSent  6
#define   PPP_AckRcvd  7
#define   PPP_AckSent  8
#define   PPP_Opened   9



#define   EVENT_Null   0
#define   EVENT_Up     1
#define   EVENT_Down   2
#define   EVENT_Open   3
#define   EVENT_Close  4
#define   EVENT_TOP    5
#define   EVENT_TON    6
#define   EVENT_RCR    7
#define   EVENT_RCA    8
#define   EVENT_RCN    9
#define   EVENT_RTR    10
#define   EVENT_RTA    11
#define   EVENT_RUC    12
#define   EVENT_RCOR   13
#define   EVENT_RPR    14
#define   EVENT_RXR    15
#define   EVENT_ECR    16
#define   EVENT_DIR    17
#define   EVENT_Last   18

#define   LCP_CREQ     1
#define   LCP_CACK     2
#define   LCP_CNAK     3
#define   LCP_CREJ     4
#define   LCP_TREQ     5
#define   LCP_TACK     6
#define   LCP_COREJ    7
#define   LCP_PREJ     8
#define   LCP_EREQ     9
#define   LCP_EREP     10
#define   LCP_DREQ     11

#define ALARM_PERIOD   2
#define TIMEOUT        2

struct ppp_hdr {
    unsigned char addr, ctl;	/* 0xff 0x03  */
    unsigned short proto;	/* Protocol */
};

char *lcp_state_name[] =
{"STATE_Initial",
 "STATE_Starting",
 "STATE_Closed",
 "STATE_Stoped",
 "State_Colsing",
 "STATE_Stoping",
 "STATE_ReqSent",
 "STATE_AckRvbd",
 "STATE_AckSent",
 "STATE_Opened"};

char *lcp_event_name[] =
{"EVENT_Null",
 "EVENT_Up",
 "EVENT_Down",
 "EVENT_Open",
 "EVENT_Close",
 "EVENT_TOP",
 "EVENT_TON",
 "EVENT_RCR",
 "EVENT_RCA",
 "EVENT_RCN",
 "EVENT_RTR",
 "EVENT_RTA",
 "EVENT_RUC",
 "EVENT_RCOR",
 "EVENT_RPR",
 "EVENT_RXR",
 "EVENT_ECR",
 "EVENT_DIR"};


char *lcp_frame[] =
{"_Unknown",
 "_Configure_Req",
 "_Configure_Ack",
 "_Configure_Nak",
 "_Configure_Rej",
 "_Terminate_Req",
 "_Terminate_Ack",
 "_Code_Rej",
 "_Protocol_Rej",
 "_Echo_Req",
 "_Echo_Rep",
 "_Discard_Req"};


void signterm(), signusr1(), signusr2(), sigalarm();
int pppdev, ipcp, sp, debug, siggot;
int creq_id = 0;


int lcp_timer = -1;
int lcp_counter = 0;
int ipcp_timer = -1;
int ipcp_counter = 0;
int event, lcp_state, ipcp_state, rlen;
unsigned char rdata[2048];

main(argc, argv)
int argc;
char **argv;
{
    int my_lsap;
    int major;

    debug = 1;

    signal(SIGTERM, signterm);
    signal(SIGUSR1, signusr1);
    signal(SIGUSR2, signusr2);
    signal(SIGALRM, sigalarm);

    pppdev = open("/dev/xnet0",O_RDWR);
    if (pppdev < 0) {
	perror("Can't open /dev/xnet0");
	exit(1);
    }
    alarm(ALARM_PERIOD);

    lcp_state = PPP_Initial;
    ipcp_state = PPP_Initial;

    event = EVENT_Up;

    ppp_fsm(&lcp_state, event, PROTO_LCP, rdata, 0);

    event = EVENT_Open;

    ppp_fsm(&lcp_state, event, PROTO_LCP, rdata, 0);

    event = EVENT_Up;

    ppp_fsm(&ipcp_state, event, PROTO_IPCP, rdata, 0);

    event = EVENT_Open;

    ppp_fsm(&ipcp_state, event, PROTO_IPCP, rdata, 0);

    while (1) {
	event = recframe(9999999, rdata, &rlen);

	if (event >= PROTO_IPCP)
	    ppp_fsm(&ipcp_state, event & 255, PROTO_IPCP, rdata, rlen);
	else
	    ppp_fsm(&lcp_state, event & 255, PROTO_LCP, rdata, rlen);
    }
}

/*=====================================================

  perform actual ppp lcp or ipcp state machine

=======================================================*/


ppp_fsm(state, event, proto, event_data, event_data_len)
int *state;
int event, event_data_len, proto;
unsigned char *event_data;
{
    int tmpevent;

    tmpevent = (event > 0 && event < EVENT_Last) ? event : EVENT_Null;

    printf("ppp_fsm:in_event %d=%s %s %d\n",
	   event, proto == PROTO_LCP ? "LCP" : "IPCP",
	   lcp_event_name[tmpevent], event_data_len);

    if (tmpevent == EVENT_ECR)
	proc_ecr(proto, event_data, event_data_len);

    switch (*state) {
    case PPP_Initial:
	switch (tmpevent) {
	case EVENT_Up:
	    *state = PPP_Closed;
	    break;
	case EVENT_Open:
	    tls(event_data);	/* This layer start */
	    *state = PPP_Starting;
	    break;
	case EVENT_Close:
	    *state = PPP_Initial;
	    break;
	default:
	    break;
	}
	break;
    case PPP_Starting:
	switch (event) {
	case EVENT_Up:
	    irc();		/* Initialize restart counter */
	    scr(proto);		/* Send configuration request */
	    *state = PPP_ReqSent;
	    break;
	case EVENT_Open:
	    *state = PPP_Starting;
	    break;
	case EVENT_Close:
	    *state = PPP_Initial;
	    break;
	default:
	    break;
	}
	break;
    case PPP_Closed:
	switch (event) {
	case EVENT_Open:
	    irc(proto);		/* Initialize restart counter */
	    scr(proto);		/* Send configuration request */
	    *state = PPP_ReqSent;
	    break;
	case EVENT_Down:
	    *state = PPP_Initial;
	    break;
	case EVENT_Close:
	case EVENT_RTA:
	case EVENT_RPR:
	case EVENT_RCOR:
	case EVENT_RXR:
	    *state = PPP_Closed;
	    break;
	case EVENT_RCR:
	case EVENT_RCA:
	case EVENT_RCN:
	case EVENT_RTR:
	    sta(proto);		/* Send Terminate ack */
	    *state = PPP_Closed;
	    break;
	case EVENT_RUC:
	    scj(proto);		/* Send Code reject */
	    *state = PPP_Closed;
	    break;
	    /*      case EVENT_RXJN: tlf(proto);*state=PPP_Closed; break; */
	default:
	    break;
	}
	break;
    case PPP_Stoped:
	switch (event) {
	case EVENT_RCA:
	case EVENT_RCN:
	case EVENT_RTR:
	    sta(proto);		/* Send Terminate ack */
	    *state = PPP_Stoped;
	    break;
	case EVENT_RTA:
	case EVENT_RXR:
	    *state = PPP_Stoped;
	    break;
	case EVENT_RUC:
	    scj(proto);		/* Send Code reject */
	    *state = PPP_Closed;
	    break;
	case EVENT_RCOR:
	    tlf(proto);
	    *state = PPP_Stoped;
	    break;
	default:
	    break;
	}
	break;
    case PPP_Closing:
	switch (event) {
	case EVENT_Down:
	    *state = PPP_Initial;
	    break;
	case EVENT_Open:
	    *state = PPP_Stoping;
	    break;
	case EVENT_Close:
	    *state = PPP_Closing;
	    break;
	case EVENT_TOP:
	    str(proto);		/* Send Terminate Request */
	    *state = PPP_Closing;
	    break;
	case EVENT_TON:
	    tlf(proto);		/* This Layer Finished */
	    *state = PPP_Closed;
	    break;
	case EVENT_RCR:
	case EVENT_RCA:
	case EVENT_RCN:
	    *state = PPP_Closing;
	    break;
	case EVENT_RTR:
	    sta(proto);		/* Send Terminate ack */
	    *state = PPP_Closed;
	    break;
	case EVENT_RTA:
	    tlf(proto);		/* This Layer Finished */
	    *state = PPP_Closed;
	    break;
	case EVENT_RUC:
	    scj(proto);		/* Send Code reject */
	    *state = PPP_Closed;
	    break;
	case EVENT_RCOR:
	    tlf(proto);
	    *state = PPP_Closed;
	    break;
	default:
	    break;
	}
	break;
    case PPP_Stoping:
	switch (event) {
	case EVENT_Down:
	    *state = PPP_Starting;
	    break;
	case EVENT_Open:
	    *state = PPP_Stoping;
	    break;
	case EVENT_Close:
	    *state = PPP_Closing;
	    break;
	case EVENT_TOP:
	    str(proto);		/* Send Terminate Request */
	    *state = PPP_Stoping;
	    break;
	case EVENT_TON:
	    tlf(proto);		/* This Layer Finished */
	    *state = PPP_Stoping;
	    break;
	case EVENT_RCR:
	case EVENT_RCA:
	case EVENT_RCN:
	    *state = PPP_Stoping;
	    break;
	case EVENT_RTR:
	    sta(proto);		/* Send Terminate ack */
	    *state = PPP_Stoping;
	    break;
	case EVENT_RTA:
	    tlf(proto);		/* This Layer Finished */
	    *state = PPP_Stoped;
	    break;
	case EVENT_RUC:
	    scj(proto);		/* Send Code reject */
	    *state = PPP_Stoping;
	    break;
	case EVENT_RCOR:
	    tlf(proto);
	    *state = PPP_Stoped;
	    break;
	default:
	    break;
	}
	break;
    case PPP_ReqSent:
	switch (event) {
	case EVENT_Down:
	    *state = PPP_Starting;
	    break;
	case EVENT_Open:
	    break;
	case EVENT_Close:
	    irc(proto);		/* Initialize restart counter */
	    str(proto);		/* Send Terminate request */
	    *state = PPP_Closing;
	    break;
	case EVENT_TOP:
	    scr(proto);		/* Send configuration request */
	    *state = PPP_ReqSent;
	    break;
	case EVENT_RCR:
	    if (proc_rcr(proto, event_data, event_data_len))
		*state = PPP_AckSent;
	    break;
	case EVENT_RCA:
	    irc(proto);		/* Initialize restart counter */
	    *state = PPP_AckRcvd;
	    break;
	case EVENT_RTR:
	    sta(proto);
	    *state = PPP_ReqSent;
	    break;
	case EVENT_RTA:
	    *state = PPP_ReqSent;
	    break;
	default:
	    break;
	}
	break;
    case PPP_AckRcvd:
	switch (event) {
	case EVENT_Down:
	    *state = PPP_Starting;
	    break;
	case EVENT_Open:
	    break;
	case EVENT_Close:
	    irc(proto);		/* Initialize restart counter */
	    str(proto);		/* Send Terminate request */
	    *state = PPP_Closing;
	    break;
	case EVENT_TOP:
	    scr(proto);		/* Send configuration request */
	    *state = PPP_ReqSent;
	    break;
	case EVENT_TON:
	    tlf(proto);		/* This Layer Finished */
	    *state = PPP_Stoped;
	    break;
	case EVENT_RCR:
	    if (proc_rcr(proto, event_data, event_data_len)) {
		tlu(proto);	/* This layer up */
		src(proto);	/* Stop restart counter */
		*state = PPP_Opened;
		break;
	    }
	    break;
	case EVENT_RCA:
	    scr(proto);		/* Send configuration request */
	    *state = PPP_ReqSent;
	    break;
	case EVENT_RTR:
	    sta(proto);
	    *state = PPP_ReqSent;
	    break;
	case EVENT_RTA:
	    *state = PPP_ReqSent;
	    break;
	default:
	    break;
	}
	break;
    case PPP_AckSent:
	switch (event) {
	case EVENT_Down:
	    *state = PPP_Starting;
	    break;
	case EVENT_Open:
	    break;
	case EVENT_Close:
	    irc(proto);		/* Initialize restart counter */
	    str(proto);		/* Send Terminate request */
	    *state = PPP_Closing;
	    break;
	case EVENT_TOP:
	    scr(proto);		/* Send configuration request */
	    *state = PPP_AckSent;
	    break;
	case EVENT_RCR:
	    if (proc_rcr(proto, event_data, event_data_len))
		*state = PPP_AckSent;
	    else
		*state = PPP_ReqSent;
	    break;
	case EVENT_RCA:
	    irc(proto);		/* Initialize restart counter */
	    tlu(proto);		/* This layer up */
	    src(proto);		/* Stop restart counter */
	    *state = PPP_Opened;
	    break;
	case EVENT_RTR:
	    sta(proto);
	    *state = PPP_ReqSent;
	    break;
	case EVENT_RTA:
	    *state = PPP_ReqSent;
	    break;
	default:
	    break;
	}
	break;
    case PPP_Opened:
	switch (event) {
	case EVENT_Down:
	    tld(proto);		/* This Layer Down */
	    *state = PPP_Starting;
	    break;
	case EVENT_Open:
	    break;
	case EVENT_Close:
	    tld(proto);		/* This layer down */
	    irc(proto);		/* Initialize restart counter */
	    str(proto);		/* Send Terminate request */
	    *state = PPP_Closing;
	    break;
	case EVENT_RCR:
	    scr(proto);		/* Send configure request */
	    irc(proto);		/* Initialize restart counter */
	    if (proc_rcr(proto, event_data, event_data_len))
		*state = PPP_AckSent;
	    else
		*state = PPP_ReqSent;
	    break;
	case EVENT_RCA:
	    /* scr(proto); *//* Initialize restart counter */
	    /* tld(proto); *//* This layer up */
	    *state = PPP_Opened;
	    break;
	case EVENT_RTR:
	    tld(proto);
	    sta(proto);
	    irc(proto);		/* Initialize restart counter */
	    *state = PPP_Stoping;
	    break;
	case EVENT_RTA:
	    tld(proto);
	    scr(proto);
	    irc(proto);		/* Initialize restart counter */
	    *state = PPP_ReqSent;
	    break;
	default:
	    break;
	}
    default:
	break;
    }
    printf("ppp_fsm: out_state %d=%s %s\n", *state,
	   proto == PROTO_LCP ? "LCP" : "IPCP",
	   lcp_state_name[*state]);
}
/*=================================================================
!
!  Sigalarm handler, will decrement timeout counters
!  but actual timeout handling is done in recframe
!  function. 
!
!  In normal situation recframe sits in poll, and will get out
!  from poll when signal is received. In any case, when poll
!  is exited or when recframe is entered with zero timeout
!  counter values the timeout event is generated.
!
\*====================================================================*/

void sigalarm()
{
/*  printf("sigalarm %d %d\n",lcp_timer,ipcp_timer); */
    signal(SIGALRM, sigalarm);
    siggot = SIGALRM;
    if (lcp_timer > 0)
	lcp_timer -= 1;
    if (ipcp_timer > 0)
	ipcp_timer -= 1;
    alarm(ALARM_PERIOD);
}
/*============================================================
!
! SIGTERM handler, actual processing is done in recframe
!  function 
\*===========================================================*/

void signterm()
{
    printf("signterm\n");
    signal(SIGTERM, signterm);
    siggot = SIGTERM;
}

void signusr1()
{
    printf("signusr1\n");
    signal(SIGUSR1, signusr1);
    siggot = SIGUSR1;
}

void signusr2()
{

    signal(SIGUSR2, signusr2);
    siggot = SIGUSR2;
}

/*========================================================================
!
!
!
\*=======================================================================*/

recframe(timeout, rdataptr, rlen)
int timeout;
char *rdataptr;
int *rlen;
{
    struct timeval tp;
    int len;
    struct ppp_hdr *hdr;
    char *p;
    int retval, i, flags, event, frame_type, proto;

    proto = 0;

    do {

	if (ipcp_timer == 0) {
	    ipcp_timer = -1;
	    proto = PROTO_IPCP;
	    if (ipcp_counter > 0) {
		event = EVENT_TOP;
		ipcp_timer = TIMEOUT;
		ipcp_counter -= 1;
	    } else
		event = EVENT_TON;
	    return (event + proto);
	}
	if (lcp_timer == 0) {
	    lcp_timer = -1;
	    proto = PROTO_LCP;
	    if (lcp_counter > 0) {
		event = EVENT_TOP;
		lcp_counter -= 1;
		ipcp_timer = TIMEOUT;
	    } else
		event = EVENT_TON;
	    return (event + proto);
	}
	*rlen = 0;

	p = rdataptr;
	for (i = 0; i < 100; i++)
	    *p++ = 0;

	len = read(pppdev, rdataptr, 100);
	if (len > 2)
	    len = len - 2;
	hdr = (struct ppp_hdr *) rdataptr;
	gettimeofday(&tp, NULL);
	if (debug && (len)) {
	    printf("read len=%d proto=%04x %d\n",
		   len, hdr->proto, tp.tv_sec, tp.tv_usec);
	    hexdump(len, rdataptr);

	}
	if (hdr->proto == 0x21c0)
	    proto = PROTO_LCP;
	if (hdr->proto == 0x2180)
	    proto = PROTO_IPCP;

	*rlen = len;

	frame_type = rdataptr[4];

	event = EVENT_Null;

	switch (frame_type) {
	case LCP_CREQ:
	    event = EVENT_RCR;	/* Configure request received */
	    break;
	case LCP_CACK:
	    event = EVENT_RCA;	/* Configure Ack received */
	    break;
	case LCP_CNAK:
	    event = EVENT_RCN;	/* Configure Nak received */
	    break;
	case LCP_CREJ:
	    event = EVENT_RCN;	/* Configure reject/Nak received */
	    break;
	case LCP_TREQ:
	    event = EVENT_RTR;	/* Trerminate request received */
	    break;
	case LCP_TACK:
	    event = EVENT_RTA;	/* Terminate ack received */
	    break;
	case LCP_COREJ:
	    event = EVENT_RCOR;	/* Code reject */
	    break;
	case LCP_PREJ:
	    event = EVENT_RPR;	/* Protocol Reject */
	    break;
	case LCP_EREQ:
	    event = EVENT_ECR;	/* Echo Request */
	    break;
	case LCP_DREQ:
	    event = EVENT_DIR;	/* Discard Request */
	}

    }
    while (proto == 0);

    printf("recframe:frame %d=%s %s event %d=%s\n",
	   frame_type, lcp_frame[frame_type],
	   proto == PROTO_LCP ? "LCP" : "IPCP",
	   event, lcp_event_name[event]);

    return (proto + event);
}

/*====================================================================
!
!                 This Leyer start
!
\*====================================================================*/
tls(proto)
int proto;
{
    printf("This Layer start\n");
}

/* Initialize restart counter */
irc(proto)
int proto;
{
    printf("Initialize restart counter\n");
    if (proto == PROTO_LCP) {
	lcp_timer = TIMEOUT;
	lcp_counter = 5;
    }
    if (proto == PROTO_IPCP) {
	ipcp_timer = TIMEOUT;
	ipcp_counter = 5;
    }
}

/*====================================================================
!
! Stop restart counter
!
! When transition occurs to state, where timeouts are not usef
! timeout timers are stopped
!
\*=================================================================*/
src(proto)
int proto;
{
    printf("Stop restart counter\n");
    if (proto == PROTO_LCP) {
	lcp_timer = -1;
	lcp_counter = -1;
    }
    if (proto == PROTO_IPCP) {
	ipcp_timer = -1;
	ipcp_counter = -1;
    }
}


/* Send terminate acknowledge */
sta(proto)
int proto;
{
    char data[10];
    char *p;

    p = data;

    if (proto == PROTO_LCP) {
	*p++ = 0xff;
	*p++ = 0x03;
	*p++ = 0xc0;
	*p++ = 0x21;

	*p++ = LCP_TACK;
	*p++ = creq_id++;
	*p++ = 0;
	*p++ = 4;		/* Length */
	write(pppdev, data, 8);
	hexdump(8, data);
    }
    if (proto == PROTO_IPCP) {
	*p++ = 0xff;
	*p++ = 0x03;
	*p++ = 0x80;
	*p++ = 0x21;

	*p++ = LCP_TACK;
	*p++ = creq_id++;
	*p++ = 0;
	*p++ = 4;		/* Length */
	write(pppdev, data, 8);
	hexdump(8, data);
    }
    printf("Send terminate acknowledge\n");
}

/* Send Configure request */
scr(proto)
int proto;
{
    char data[10];
    char *p;

    p = data;

    printf("Send Configure request\n");

    if (proto == PROTO_LCP) {
	*p++ = 0xff;
	*p++ = 0x03;
	*p++ = 0xc0;
	*p++ = 0x21;

	*p++ = LCP_CREQ;
	*p++ = creq_id++;
	*p++ = 0;
	*p++ = 4;		/* Length */
	write(pppdev, data, 8);
	hexdump(8, data);
    }
    if (proto == PROTO_IPCP) {
	*p++ = 0xff;
	*p++ = 0x03;
	*p++ = 0x80;
	*p++ = 0x21;

	*p++ = LCP_CREQ;
	*p++ = creq_id++;
	*p++ = 0;
	*p++ = 4;		/* Length */
	write(pppdev, data, 8);
	hexdump(8, data);
    }
}

/* Send code reject */
scj(proto)
int proto;
{
    char data[10];
    char *p;

    p = data;

    printf("Send code reject\n");
    if (proto == PROTO_LCP) {
	*p++ = 0xff;
	*p++ = 0x03;
	*p++ = 0xc0;
	*p++ = 0x21;

	*p++ = LCP_CREJ;
	*p++ = creq_id++;
	*p++ = 0;
	*p++ = 4;		/* Length */
	write(pppdev, data, 8);
	hexdump(8, data);
    }
    if (proto == PROTO_IPCP) {
	*p++ = 0xff;
	*p++ = 0x03;
	*p++ = 0x80;
	*p++ = 0x21;

	*p++ = LCP_CREJ;
	*p++ = creq_id++;
	*p++ = 0;
	*p++ = 4;		/* Length */
	write(pppdev, data, 8);
	hexdump(8, data);

    }
}

/* Thlis layer finished */
tlf(proto)
int proto;
{
    printf("This layer finished\n");
}

/* Send terminate request */
str(proto)
int proto;
{
    char data[10];
    char *p;

    p = data;

    printf("Send terminate request\n");
    if (proto == PROTO_LCP) {
	*p++ = 0xff;
	*p++ = 0x03;
	*p++ = 0xc0;
	*p++ = 0x21;

	*p++ = LCP_TREQ;
	*p++ = creq_id++;
	*p++ = 0;
	*p++ = 4;		/* Length */
	write(pppdev, data, 8);
	hexdump(8, data);
    }
    if (proto == PROTO_IPCP) {
	*p++ = 0xff;
	*p++ = 0x03;
	*p++ = 0x80;
	*p++ = 0x21;

	*p++ = LCP_TREQ;
	*p++ = creq_id++;
	*p++ = 0;
	*p++ = 4;		/* Length */
	write(pppdev, data, 8);
	hexdump(8, data);
    }
}


/* Process configure request */
proc_rcr(proto, event_data, event_data_len)
int proto;
char *event_data;
int event_data_len;
{

    int reply;

    reply = LCP_CACK;

    printf("Process configure request %d\n", event_data_len);
    printf("pcr:send_configure_ack\n");

    event_data[0] = 0xff;
    event_data[1] = 0x03;

    if (proto == PROTO_LCP) {
	switch (event_data[8]) {
	case 1:
	    printf("conf req=Max receive unit l=%d\n", event_data[5]);
	    break;
	case 2:
	    printf("conf req=Async controll character map l=%d\n", event_data[5]);
	    break;
	case 3:
	    printf("conf req=Authentication Protocol l=%d\n", event_data[5]);
	    break;
	case 4:
	    printf("conf req=Quality Protocol l=%d\n", event_data[5]);
	    break;
	case 5:
	    printf("conf req=Magic Number l=%d\n", event_data[9]);
	    /* event_data[10]='K';
	       event_data[11]='a';
	       event_data[12]='t';
	       event_data[13]='e'; */
	    reply = LCP_CREJ;	/* reject  this option */
	    break;
	case 6:
	    printf("conf req=RESERVER l=%d\n", event_data[5]);
	    break;
	case 7:
	    printf("conf req=Protocol Field Compression l=%d\n", event_data[5]);
	    break;
	case 8:
	    printf("conf req=Address-and-controll field compression l=%d\n", event_data[5]);
	    break;
	}

	event_data[4] = reply;
	write(pppdev, event_data, event_data_len);
	hexdump(event_data_len, event_data);
    }
    if (proto == PROTO_IPCP) {
	event_data[4] = LCP_CACK;	/* Send same package as acknowledge */
	write(pppdev, event_data, event_data_len);
	hexdump(event_data_len, event_data);
    }
    return (reply);
}

/* Process echo request */
proc_ecr(proto, event_data, event_data_len)
int proto;
char *event_data;
int event_data_len;
{


    printf("Process echo request %d\n", event_data_len);
    printf("ecr:send_echo reply\n");

    if (proto == PROTO_LCP) {
	event_data[4] = LCP_EREP;	/* Send same package as acknowledge */
	write(pppdev, event_data, event_data_len);
    }
    if (proto == PROTO_IPCP) {
	event_data[4] = LCP_EREP;	/* Send same package as acknowledge */
	write(pppdev, event_data, event_data_len);
    }
    return (1);
}

/* This layer up */
tlu(int proto)
{
    printf("This layer up\n");
}

/* This layer down */
tld(int proto)
{
    printf("This layer down\n");
}

hexdump(int n, unsigned char *p)
{
    register int i, y;
    unsigned char *q;

    q = p;


    while (n) {
	q = p;
	i = (n >= 16) ? 16 : n;
	while (i--)
	    printf("%02x ", *p++);
	i = (n >= 16) ? 16 : n;
	n -= i;
	while (i--) {
	    y = *q++ & 127;
	    putchar((y < 32) || (y > 126) ? '.' : y);
	}
	printf("\n");
    }
}
