www.pudn.com > ejip.zip > Ppp.java
/*
* Copyright (c) Martin Schoeberl, martin@jopdesign.com
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Martin Schoeberl
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
package ejip;
/**
* Ppp.java
*
* communicate with jopbb via serial line.
*/
import util.*;
/**
* Ppp driver.
*/
public class Ppp extends LinkLayer {
private static final int MAX_BUF = 1500+4; // 1500 is PPP information field
/**
* period for thread in ms.
*/
private static final int PERIOD = 10;
private static final int IP = 0x0021; // Internet Protocol packet
private static final int IPCP = 0x8021; // Internet Protocol Configuration Protocol packet
private static final int CCP = 0x80fd; // Compression Configuration Protocol packet
private static final int LCP = 0xc021; // Link Configuration Protocol packet
private static final int PAP = 0xc023; // Password Authentication Protocol packet
private static final int REQ = 1; // Request options list
private static final int ACK = 2; // Acknowledge options list
private static final int NAK = 3; // Not acknowledge options list
private static final int REJ = 4; // Reject options list
private static final int TERM = 5; // Termination
private static final int NEG_SEND= 3000/PERIOD; // Period of send negotiation
private static final int IP_SEND= 10000/PERIOD; // Send timout for ip for reconnect
/**
* receive buffer
*/
private static int[] rbuf;
/**
* send buffer
*/
private static int[] sbuf;
/**
* bytes received.
*/
private static int cnt;
/**
* mark escape sequence.
*/
private static boolean esc;
/**
* a ppp packet is in the receive buffer.
*/
private static boolean ready;
/**
* bytes to be sent. 0 means txFree
*/
private static int scnt;
/**
* allready sent bytes.
*/
private static int sent;
/**
* flag (0x7e, ~) received
*/
private static boolean flag;
/**
* number for lcp id
*/
private static int lcpId;
/**
* state machine
*/
private static int state;
/**
* reject counter
*/
private static int rejCnt;
private static final int MAX_REJ = 5;
/**
* remote ip address.
*/
public static int ipRemote;
/**
* ip address.
*/
public static int ip;
/**
* The one and only reference to this object.
*/
private static Ppp single;
/**
* private constructor. The singleton object is created in init().
*/
private Ppp() {
super(PERIOD); // thats the period.
}
/**
* allocate buffer, start serial buffer and slip Thread.
*/
public static void init() {
if (single != null) return; // allready called init()
rbuf = new int[MAX_BUF];
sbuf = new int[MAX_BUF];
cnt = 0;
esc = false;
ready = false;
flag = false;
scnt = 0;
sent = 0;
lcpId = 0x11;
ip = 0;
ipRemote = 0;
initStr();
Serial.init(); // start serial buffer thread
single = new Ppp();
single.start(); // kick off the thread
}
/**
* main loop.
*/
public void run() {
connect();
}
/**
* windoz PPP.
*/
private static int[] client;
private static int[] ver;
private static int[] ok;
private static int[] connect;
private static int[] ath;
private static int[] pin;
private static int[] con;
private static int[] dial;
private static int[] flow;
private static void initStr() {
int[] s1 = { 'C', 'L', 'I', 'E', 'N', 'T' };
client = s1;
int[] s2 = { 'V', 'E', 'R' };
ver = s2;
int [] s3 = { 'O', 'K' };
int [] s4 = { 'E', 'C', 'T' };
int [] s5 = { '|', '+', '+', '+', '|', 'A', 'T', 'H', '\r' };
// int [] s6 = { 'A', 'T', '+', 'C', 'P', 'I', 'N', '=', '9', '1', '7', '4','\r' };
int [] s6 = { 'A', 'T', '+', 'C', 'P', 'I', 'N', '=', '5', '6', '4', '4','\r' };
ok = s3;
connect = s4;
ath = s5;
pin = s6;
initStr2();
}
private static void initStr2() {
// int [] s7 = { 'A', 'T', '+', 'C', 'G', 'D', 'C', 'O', 'N', 'T', '=', '1', ',', '"', 'I', 'P', '"', ',', '"', 'w', 'e', 'b', '.', 'o', 'n', 'e', '.', 'a', 't', '"', '\r' };
int [] s7 = { 'A', 'T', '+', 'C', 'G', 'D', 'C', 'O', 'N', 'T', '=', '1', ',', '"', 'I', 'P', '"', ',', '"', 'A', '1', '.', 'n', 'e', 't', '"', '\r' };
int [] s8 = { 'A', 'T', 'D', '*', '9', '9', '*', '*', '*', '1', '#', '\r' };
int [] s9 = { 'A', 'T', '\\', 'Q', '3', '\r' };
con = s7;
dial = s8;
flow = s9;
}
/**
* wait seconds
*/
void waitSec(int t) {
// t *= 1000/PERIOD;
for (int i=0; ii) return false;
Dbg.wr('\'');
for (i=0; i0; --timer) {
waitForNextPeriod();
dropIp();
for (int i = Serial.rxCnt(); i>0; --i) {
int val = Serial.rd();
Dbg.wr(val);
if (val == rcv[ptr]) {
++ptr;
if (ptr==len) {
Dbg.wr('\n');
waitSec(1);
return true; // we're done
}
} else {
ptr = 0; // reset match pointer
}
}
}
Dbg.wr('?');
Dbg.wr('\n');
return false; // timeout expired
}
/**
* do the modem stuff till CONNECT
*/
void modemInit() {
for (;;) {
if (sendWait(ath, ok, 3)) {
if (sendWait(flow, ok, 3)) {
if (!sendWait(con, ok, 2)) { // when ERROR PIN is not set
sendWait(pin, ok, 30);
if (!sendWait(con, ok, 20)) {
continue; // something really strange happend!
}
}
if (sendWait(dial, connect, 10)) {
break;
}
}
}
waitSec(1);
}
state = MODEM_OK;
timer = 0;
lcpAck = false;
ipcpAck = false;
}
/**
* cancel connection.
*/
void modemHangUp() {
ip = 0; // stop sending ip data
state = INIT;
rejCnt = 0;
// flush buffer
for (int i = Serial.rxCnt(); i>0; --i) {
Serial.rd();
}
for (;;) {
if (sendWait(ath, ok, 3)) {
break;
}
waitSec(3);
}
}
private static final int INIT = 0;
private static final int MODEM_OK = 1;
private static final int LCP_SENT = 2;
private static final int LCP_OK = 3;
private static final int PAP_SENT = 4;
private static final int PAP_OK = 5;
private static final int IPCP_SENT = 6;
private static final int IPCP_SENT2 = 7;
private static final int IPCP_OK = 8;
private static final int CONNECTED = 9;
private static int timer; // negotion send and ip-restart timer
private static boolean lcpAck;
private static boolean ipcpAck;
/**
* establish a connetcion.
*/
void connect() {
timer = 0;
state = INIT;
rejCnt = 0;
lcpAck = false;
boolean ipcpAck = false;
//
// start the modem
//
modemInit();
//
// now LCP negotiation
//
for (;;) {
waitForNextPeriod();
loop();
if (state==MODEM_OK) {
}
if (rejCnt > MAX_REJ) {
modemHangUp(); // start over
modemInit();
}
if (ready && scnt==0) { // one packet is read and send buffer is free
yield(); // time for a thread switch
dbgCon();
int prot = (rbuf[2]<<8)+rbuf[3];
int code = rbuf[4];
if (prot == LCP) {
if (code == REQ) {
if (checkOptions(LCP)) {
lcpAck = true;;
} else {
++rejCnt;
}
} else if (code==ACK && rbuf[5]==lcpId) {
state = LCP_OK;
} else if (code==TERM) {
modemHangUp(); // start over
modemInit();
}
} else if (prot == PAP) {
if (rbuf[4]==ACK && rbuf[5]==lcpId) {
state = PAP_OK;
}
} else if (prot == IPCP) {
if (code == REQ) {
if (checkOptions(IPCP)) {
ipcpAck = true;;
}
} else if (code == NAK) { // with this NAK we will get our IP address
ip= (rbuf[10]<<24) + (rbuf[11]<<16) +
(rbuf[12]<<8) + rbuf[13];
dbgIp(ip);
makeIPCP();
state = IPCP_SENT2;
} else if (code == ACK) {
state = IPCP_OK;
// nothing more to do ?
state = CONNECTED;
Dbg.wr('C');
Dbg.wr('\n');
}
//
// des is net guat: kommt nur hierher, wenn der Sendbuffer frei ist!!!
//
} else if (prot == IP) { // we finally got an ip packet :-)
readIp();
}
cnt = 0;
ready = false;
}
doSend();
}
}
void doSend() {
if (state==CONNECTED) { // send waiting ip packets
if (scnt==0) { // transmit buffer is free
timer = 0;
//
// get a ready to send packet with source from this driver.
//
Packet p = Packet.getPacket(single, Packet.SND, Packet.ALLOC);
if (p!=null) {
sendIp(p); // send one packet
}
} else { // increment sendTimer;
timer++;
if (timer>IP_SEND) {
modemHangUp(); // start over
modemInit();
}
}
} else { // do the negotiation stuff
dropIp();
++timer;
if (timer>NEG_SEND) {
/*
Dbg.intVal(state);
if (lcpAck) Dbg.wr('t'); else Dbg.wr('f');
*/
if (scnt==0) { // once every two seconds send a REQ
if (state == MODEM_OK) {
makeLCP();
state = LCP_SENT;
} else if (state == LCP_OK && lcpAck) {
makePAP();
state = PAP_SENT;
// } else if (state == PAP_OK && ipcpAck) { // wait for remote ipcp and ACK first on Linux
} else if (state>=PAP_OK && state');
for (int i=0; i>>24);
Dbg.intVal((ip>>>16)&0xff);
Dbg.intVal((ip>>>8)&0xff);
Dbg.intVal(ip&0xff);
Dbg.wr('\n');
}
/**
* generate a PPP (negotiation) request.
*/
void makeLCP() {
lcpId = 0x22;
Dbg.wr('L');
Dbg.intVal(lcpId);
Dbg.wr('\n');
sbuf[0] = 0xff;
sbuf[1] = 0x03;
// REQ LCP options 2, 7, 8
sbuf[2] = LCP>>8;
sbuf[3] = LCP&0xff;
sbuf[4] = REQ;
sbuf[5] = lcpId;
sbuf[6] = 0;
sbuf[7] = 18-4; // length including code, id and length field
sbuf[8] = 0x02; // async-map
sbuf[9] = 0x06;
sbuf[10] = 0x00;
sbuf[11] = 0x0a;
// sbuf[11] = 0x00; // one does not like this
sbuf[12] = 0x00;
sbuf[13] = 0x00;
sbuf[14] = 0x07; // protocol field compression
sbuf[15] = 0x02;
sbuf[16] = 0x08; // addr., contr. field compression
sbuf[17] = 0x02;
checksum(18);
}
void makePAP() {
lcpId = 0x33;
Dbg.wr('P');
Dbg.intVal(lcpId);
Dbg.wr('\n');
/* compression
sbuf[0] = 0xff;
sbuf[1] = 0x03;
*/
sbuf[0] = PAP>>8;
sbuf[1] = PAP&0xff;
sbuf[2] = REQ;
sbuf[3] = lcpId;
sbuf[4] = 0;
/* A1.net
*/
sbuf[5] = 24-2; // length including code, id and length field
sbuf[6] = 13; // length of user id
sbuf[7] = 'p';
sbuf[8] = 'p';
sbuf[9] = 'p';
sbuf[10] = '@';
sbuf[11] = 'A';
sbuf[12] = '1';
sbuf[13] = 'p';
sbuf[14] = 'l';
sbuf[15] = 'u';
sbuf[16] = 's';
sbuf[17] = '.';
sbuf[18] = 'a';
sbuf[19] = 't';
sbuf[20] = 3; // length of password
sbuf[21] = 'p';
sbuf[22] = 'p';
sbuf[23] = 'p';
checksum(24);
// checksum(23);
/* ONE
sbuf[7] = 30-4; // length including code, id and length field
sbuf[8] = 14; // length of user id
sbuf[9] = '+';
sbuf[10] = '4';
sbuf[11] = '3';
sbuf[12] = '6';
sbuf[13] = '9';
sbuf[14] = '9';
sbuf[15] = '1';
sbuf[16] = '9';
sbuf[17] = '5';
sbuf[18] = '2';
sbuf[19] = '0';
sbuf[20] = '2';
sbuf[21] = '2';
sbuf[22] = '0';
sbuf[23] = 6; // length of password
sbuf[24] = 'N';
sbuf[25] = '6';
sbuf[26] = 'J';
sbuf[27] = '8';
sbuf[28] = 'N';
sbuf[29] = '4';
checksum(30);
*/
}
void makeIPCP() {
lcpId = 0x44;
Dbg.wr('I');
Dbg.intVal(lcpId);
Dbg.wr('\n');
/* compression
sbuf[0] = 0xff;
sbuf[1] = 0x03;
*/
sbuf[0] = IPCP>>8;
sbuf[1] = IPCP&0xff;
sbuf[2] = REQ;
sbuf[3] = lcpId;
sbuf[4] = 0;
sbuf[5] = 14-4; // length including code, id and length field
sbuf[6] = 0x03; // ip-address 0.0.0.0
sbuf[7] = 0x06;
sbuf[8] = ip>>>24;
sbuf[9] = (ip>>16)&0xff;
sbuf[10] = (ip>>8)&0xff;
sbuf[11] = ip&0xff;
// checksum(14);
checksum(12);
}
/**
* process a LCP, IPCP request
*/
boolean checkOptions(int type) {
int i;
int len = (rbuf[6]<<8) + rbuf[7] - 4; // including code, id and lentgh
int ptr = 8;
Dbg.wr('R');
Dbg.wr(' ');
int resp = ACK;
for (i=0; i 0) {
int opt = rbuf[ptr];
Dbg.intVal(opt);
if (type==LCP && opt==3) { // auth. protocol
if ((rbuf[ptr+2]<<8) + rbuf[ptr+3] != PAP) {
resp = REJ;
Dbg.wr('!');
Dbg.wr('P');
Dbg.wr(' ');
}
} else if (type==IPCP) {
if (opt==2) { // IP-Compression
resp = REJ;
} else if (opt==3) { // IP-address
ipRemote = (rbuf[ptr+2]<<24) + (rbuf[ptr+3]<<16) +
(rbuf[ptr+4]<<8) + rbuf[ptr+5];
Dbg.hexVal(ipRemote);
dbgIp(ipRemote);
}
}
// } else if (opt==xx}
if (resp==REJ) {
int optlen = rbuf[ptr+1];
slen = 4 + optlen;
for (i=0; i>>8;
sbuf[7] = slen&0xff;
Dbg.wr('\n');
checksum(slen+4);
return resp == ACK;
}
/**
* get a Packet buffer and copy from receive buffer.
*/
void readIp() {
int i, j, k;
Packet p = Packet.getPacket(Packet.FREE, Packet.ALLOC, single);
if (p==null) {
Dbg.wr('!');
return; // try again later
} // buf blocks receive buffer :-<
int[] pb = p.buf;
cnt -= 6; // minus ppp header and checksum
rbuf[cnt+4] = 0;
rbuf[cnt+4+1] = 0;
rbuf[cnt+4+2] = 0;
// copy buffer
k = 0;
for (i=0; i>>2] = k;
}
p.len = cnt;
// Dbg.wr('s');
// Dbg.intVal(cnt);
/*
dbgIp(pb[3]);
dbgIp(pb[4]);
for (i=0; i<(cnt+4)>>2; ++i) Dbg.hexVal(pb[i]);
Dbg.wr('\n');
*/
cnt = 0;
ready = false;
p.setStatus(Packet.RCV); // inform upper layer
}
/**
* copy packet to send buffer.
*/
void sendIp(Packet p) {
int i, k;
int[] pb = p.buf;
// Dbg.wr('S');
// Dbg.intVal(p.len);
sbuf[0] = 0xff;
sbuf[1] = 0x03;
sbuf[2] = IP>>8;
sbuf[3] = IP&0xff;
int slen = p.len;
sent = 0;
for (i=0; i>>2];
sbuf[i+4] = k>>>24;
sbuf[i+4+1] = (k>>>16)&0xff;
sbuf[i+4+2] = (k>>>8)&0xff;
sbuf[i+4+3] = k&0xff;
}
p.setStatus(Packet.FREE); // mark packet free
checksum(slen+4);
}
/* warum geht das nicht !!!!!
private void loop() {
*/
/**
* read from serial buffer and build a ppp packet.
* send a packet if one is in our send buffer.
*/
boolean loop() {
int i;
boolean ret = false;
i = Serial.rxCnt();
if (i!=0 && !ready) {
ret = true;
rcv(i);
}
if (scnt!=0) {
i = Serial.txFreeCnt();
if (i>2) {
snd(i);
}
}
return ret;
}
/**
* copy from send buffer to serial buffer with flags and escapes.
*/
void snd(int free) {
int i;
if (sent==0) {
Serial.wr('~');
--free;
}
for (i=sent; free>1 && i= LCP_OK) { // hard code async map
if (c=='~' || c=='}' || c==17 || c==19) { // 0x000a0000 async map
Serial.wr('}');
Serial.wr(c ^ ' ');
free -= 2;
} else {
Serial.wr(c);
--free;
}
} else {
*/
if (c=='~' || c=='}' || c<0x20) { // c<0x20 could be omitted after LCP async map
Serial.wr('}');
Serial.wr(c ^ ' ');
free -= 2;
} else {
Serial.wr(c);
--free;
}
/*
}
*/
}
sent = i;
if (sent==scnt && free!=0) {
Serial.wr('~');
scnt = 0;
sent = 0;
}
}
private static boolean escape;
private static int fcs;
/**
* copy from serial buffer to receive buffer.
* calc CRC on the fly.
*/
void rcv(int len) {
int i;
if (cnt==0) fcs = 0xffff;
// get all bytes from serial buffer
for (i=0; i>8);
}
/*
Dbg.wr('r');
Dbg.intVal(cnt);
Dbg.wr('\n');
*/
}
/**
* calculate CRC of byte c for checksum
*/
int check(int c) {
c &= 0xff;
for (int i=0; i<8; ++i) {
if ((c&1) != 0) {
c >>= 1;
c ^= 0x8408;
} else {
c >>= 1;
}
}
return c;
}
/**
* calculate CRC for send packet and mark it ready to send.
*/
void checksum(int len) {
int k, j, i;
int fcs = 0xffff;
for (i=0; i>= 1;
j ^= 0x8408;
} else {
j >>= 1;
}
}
fcs = j ^ (fcs>>8);
}
fcs = fcs ^ 0xffff;
sbuf[len] = fcs & 0xff; // LSB first !
sbuf[len+1] = fcs >> 8;
scnt = len+2;
if (state!=CONNECTED) {
Dbg.wr('<');
for (i=0; i