Simplex ppp (for IrDA use)

Pavel Machek (pavel@bug.ucw.cz)
Tue, 29 Sep 1998 23:12:29 +0200


Hi!

I've hacked simplex support into Linux's ppp. It is not well tested as
I have only one IrDA capable machine; I would like anyone out there to
test it and let me know.

This is _NOT_ meant for official kernel inclusion.

You need patched kernel, and when setting up link you have to use mru
2345 on both sides (which will magically activate simplex
support). (I'm planning more clean support, but that will need hacked
pppd, and pppd-2.3.4 does not work for me :-( ).

This patch should enable you to run ppp over 115200 irda links in
notebooks. It violates about all standarts it can violate. Please
test,

Pavel

--- clean//include/linux/if_ppp.h Sun Jul 19 23:30:19 1998
+++ linux/include/linux/if_ppp.h Tue Sep 29 21:13:12 1998
@@ -21,7 +21,7 @@
*/

/*
- * ==FILEVERSION 980704==
+ * ==FILEVERSION XXXXXX==
*
* NOTE TO MAINTAINERS:
* If you modify this file at all, please set the above date.
@@ -73,6 +73,7 @@
#define SC_LOG_OUTPKT 0x00040000 /* log contents of pkts sent */
#define SC_LOG_RAWIN 0x00080000 /* log all chars received */
#define SC_LOG_FLUSH 0x00100000 /* log all chars flushed */
+#define SC_SIMPLEX 0x01000000 /* assume simplex link */
#define SC_MASK 0x0f0000ff /* bits that user can change */

/* state bits */
--- clean//include/linux/if_pppvar.h Sun Jul 19 23:30:19 1998
+++ linux/include/linux/if_pppvar.h Tue Sep 29 19:35:23 1998
@@ -42,7 +42,7 @@
*/

/*
- * ==FILEVERSION 980704==
+ * ==FILEVERSION XXXXXX==
*
* NOTE TO MAINTAINERS:
* If you modify this file at all, please set the above date.
@@ -114,6 +114,16 @@

/* Statistic information */
struct pppstat stats; /* statistic information */
+
+ /* Simplex support */
+ __u8 token_state; /* Start in UNK_TOKEN */ /* our state wrt token */
+#define NO_TOKEN 0
+#define GOT_TOKEN 1
+#define UNK_TOKEN 2
+ unsigned long got_token_from;
+ struct timer_list token_timer; /* INIT! */
+
+ unsigned long xmit_lock;

/* PPP compression protocol information */
struct compressor *sc_xcomp; /* transmit compressor */
--- clean//drivers/net/ppp.c Wed Aug 26 13:09:37 1998
+++ linux/drivers/net/ppp.c Tue Sep 29 21:16:43 1998
@@ -4,7 +4,7 @@
* Al Longyear <longyear@netcom.com>
* Extensively rewritten by Paul Mackerras <paulus@cs.anu.edu.au>
*
- * ==FILEVERSION 980704==
+ * ==FILEVERSION XXXXXX==
*
* NOTE TO MAINTAINERS:
* If you modify this file at all, please set the number above to the
@@ -40,6 +40,9 @@
processing for each received character.
*/

+#define TOKEN_TIME1 ((HZ * 2)/100) /* ~20msec */
+#define TOKEN_TIME2 ((HZ * 5)/100) /* ~50msec */
+#define TOKEN_HOLD_TIME (HZ /5) /* 200msec */
#define OPTIMIZE_FLAG_TIME ((HZ * 3)/2)
#define CHECK_CHARACTERS 1

@@ -115,6 +118,7 @@
static void ppp_output_wakeup(struct ppp *ppp);
static void ppp_send_ctrl(struct ppp *ppp, struct sk_buff *skb);
static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb);
+static inline void ppp_send_frames(struct ppp *ppp);
static struct sk_buff *ppp_vj_compress(struct ppp *ppp, struct sk_buff *skb);

static struct ppp *ppp_find (int pid_value);
@@ -124,6 +128,10 @@
static void ppp_print_buffer (const char *, const __u8 *, int);
static struct compressor *find_compressor (int type);

+static void token_packet_rx(struct ppp *ppp);
+static void token_packet_tx(struct ppp *ppp);
+static void send_token_somehow(struct ppp *ppp);
+
#ifndef OPTIMIZE_FLAG_TIME
#define OPTIMIZE_FLAG_TIME 0
#endif
@@ -1220,6 +1228,7 @@
static int rcv_proto_vjc_comp (struct ppp *, struct sk_buff *);
static int rcv_proto_vjc_uncomp (struct ppp *, struct sk_buff *);
static int rcv_proto_ccp (struct ppp *, struct sk_buff *);
+static int rcv_simplex_token (struct ppp *, struct sk_buff *);
static int rcv_proto_unknown (struct ppp *, struct sk_buff *);

static
@@ -1230,6 +1239,7 @@
{ PPP_VJC_COMP, rcv_proto_vjc_comp },
{ PPP_VJC_UNCOMP, rcv_proto_vjc_uncomp },
{ PPP_CCP, rcv_proto_ccp },
+ { 0xfeff, rcv_simplex_token },
{ 0, rcv_proto_unknown } /* !!! MUST BE LAST !!! */
};

@@ -1386,6 +1396,13 @@
break;
if (temp_i < PPP_MRU)
temp_i = PPP_MRU;
+
+/* HACK HACK HACK */
+ if (temp_i == 2345) {
+ printk( "WARNING: forcing simplex on\n" );
+ ppp->flags |= SC_SIMPLEX | SC_DEBUG;
+ }
+ ppp->mru = temp_i;
if (ppp->flags & SC_DEBUG)
printk(KERN_INFO
"ppp_ioctl: set mru to %x\n", temp_i);
@@ -1422,6 +1439,8 @@
temp_i = (temp_i & SC_MASK) | (oldflags & ~SC_MASK);
ppp->flags = temp_i;
restore_flags(flags);
+ if (temp_i & SC_SIMPLEX)
+ printk(KERN_INFO "ppp_ioctl: experimental simplex enabled\n");

if ((oldflags | temp_i) & SC_DEBUG)
printk(KERN_INFO
@@ -1971,6 +1990,8 @@
static int
ppp_rcv_rx(struct ppp *ppp, __u16 proto, struct sk_buff *skb)
{
+ if (ppp->flags & SC_SIMPLEX)
+ token_packet_rx(ppp);

/*
* Fill in a few fields of the skb and give it to netif_rx().
@@ -2097,6 +2118,172 @@
return 1;
}

+/* ===================================================================
+ * SIMPLEX handling routines
+ * ===================================================================
+ */
+
+static void
+wake_me_up(struct ppp *ppp)
+{
+ ppp_send_frames(ppp);
+}
+
+static void
+token_timeout(struct ppp *ppp)
+{
+ printk( "TOKEN: tick tock: " );
+ switch (ppp->token_state) {
+ case UNK_TOKEN:
+ printk( "UNK_TOKEN ??? You can not have ticker in UNKNOWN state!" );
+ break;
+ case NO_TOKEN:
+ printk( "NO_TOKEN -> UNK_TOKEN (+wakeup)" );
+ ppp->token_state = UNK_TOKEN;
+ wake_me_up(ppp);
+ break;
+ case GOT_TOKEN:
+ printk( "GOT_TOKEN -> UNK_TOKEN" );
+ ppp->token_state = UNK_TOKEN;
+ break;
+ default:
+ printk( "This can not happen (famous last words)" );
+ }
+
+ printk( "\n" );
+}
+
+static void
+set_timer(struct ppp *ppp, int time)
+{
+ if (ppp->token_state != UNK_TOKEN)
+ del_timer(&ppp->token_timer);
+ ppp->token_timer.expires = jiffies + time;
+ ppp->token_timer.prev = ppp->token_timer.next = NULL;
+ add_timer(&ppp->token_timer);
+}
+
+/*
+ Simplex support:
+ GOT_TOKEN
+ packet_rx -> other side does not follow protocol
+ packet_tx -> GOT_TOKEN
+ 10msec -> UNKNOWN
+ has been in GOT_TOKEN for > 200msec -> give_token() -> NO_TOKEN (set tbusy to 1)
+ NO_TOKEN
+ packet_tx -> PANIC!
+ packet_rx -> NO_TOKEN
+ 10msec -> UNKNOWN (set tbusy to 0)
+ token cames -> GOT_TOKEN (set got_token_from, set tbusy to 0)
+ UNKNOWN
+ packet_rx -> NO_TOKEN
+ packet_tx -> GOT_TOKEN (set got_token_from)
+ */
+
+static void
+token_packet_rx(struct ppp *ppp)
+{
+ printk( "TOKEN: packet_rx: " );
+ switch (ppp->token_state) {
+ case GOT_TOKEN:
+ printk("ppp/simplex: Other side does not follow protocol\n");
+ break;
+ case NO_TOKEN:
+ printk("NO_TOKEN");
+ set_timer(ppp, TOKEN_TIME2);
+ break;
+ case UNK_TOKEN:
+ set_timer(ppp, TOKEN_TIME2);
+ printk("UNK_TOKEN -> NO_TOKEN");
+ ppp->token_state = NO_TOKEN;
+ break;
+ default: printk("ppp/simplex: this can not happen\n");
+ }
+ printk( "\n" );
+}
+
+static void
+token_packet_tx(struct ppp *ppp)
+{
+ printk( "TOKEN: packet_tx: " );
+ switch (ppp->token_state) {
+ case NO_TOKEN:
+ printk("ppp/simplex: I do not follow protocol - this can not happen\n");
+ break;
+ case GOT_TOKEN:
+ printk( "GOT_TOKEN" );
+ set_timer(ppp, TOKEN_TIME1);
+ if (jiffies - ppp->got_token_from > TOKEN_HOLD_TIME) {
+ del_timer(&ppp->token_timer);
+ ppp->flags &=~SC_SIMPLEX;
+ send_token_somehow(ppp);
+ ppp->flags |= SC_SIMPLEX;
+ set_timer(ppp, TOKEN_TIME2);
+ ppp->token_state = NO_TOKEN;
+ printk( " passing token!" );
+ }
+ break;
+ case UNK_TOKEN:
+ set_timer(ppp, TOKEN_TIME1);
+ printk( "UNK_TOKEN->GOT_TOKEN");
+ ppp->got_token_from = jiffies;
+ ppp->token_state = GOT_TOKEN;
+ break;
+ default: printk("ppp/simplex: this can not happen\n");
+ }
+ printk( "\n" );
+}
+
+/*
+ * We received token
+ */
+static int
+rcv_simplex_token(struct ppp *ppp, struct sk_buff *skb)
+{
+ CHECK_PPP(0);
+
+ if (!(ppp->flags & SC_SIMPLEX))
+ printk("Received token when not in simplex mode?\n");
+
+ if (ppp->token_state != NO_TOKEN) {
+ printk("Unexpected token came\n");
+ return 0;
+ }
+ set_timer(ppp, TOKEN_TIME1);
+ ppp->got_token_from = jiffies;
+ ppp->token_state = GOT_TOKEN;
+ wake_me_up(ppp);
+ printk("Received token: GOT_TOKEN\n");
+ return 0;
+}
+
+static void
+send_token_somehow(struct ppp *ppp)
+{
+ int count = 4;
+ char *new_data;
+ struct sk_buff *skb;
+
+ /*
+ * Allocate a buffer for the data and fetch it from the user space.
+ */
+ skb = alloc_skb(count, GFP_ATOMIC);
+ if (skb == NULL) {
+ printk(KERN_ERR "send_token_somehow: no memory\n");
+ return;
+ }
+ new_data = skb_put(skb, count);
+ *new_data++ = PPP_ALLSTATIONS;
+ *new_data++ = PPP_UI;
+ *new_data++ = 0xfe;
+ *new_data++ = 0xff;
+
+ /*
+ * Send the frame
+ */
+ ppp_send_frame(ppp, skb);
+}
+
/*************************************************************
* TRANSMIT-SIDE ROUTINES
*************************************************************/
@@ -2112,8 +2299,8 @@

/*
* Compress and send an frame to the peer.
- * Should be called with dev->tbusy == 1, having been set by the caller.
- * That is, we use dev->tbusy as a lock to prevent reentry of this
+ * Should be called with xmit_lock == 1, having been set by the caller.
+ * That is, we use xmit_lock as a lock to prevent reentry of this
* procedure.
*/
static void
@@ -2185,7 +2372,7 @@
if (new_skb == NULL) {
printk(KERN_ERR "ppp_send_frame: no memory\n");
kfree_skb(skb);
- ppp->dev.tbusy = 0;
+ ppp->xmit_lock = 0;
return;
}

@@ -2214,11 +2401,15 @@
ret = ppp_async_send(ppp, skb);
if (ret > 0) {
/* we can release the lock */
- ppp->dev.tbusy = 0;
+ ppp->xmit_lock = 0;
+
+ if (ppp->flags & SC_SIMPLEX)
+ token_packet_tx(ppp);
+
} else if (ret < 0) {
- /* this can't happen, since the caller got the tbusy lock */
+ /* this can't happen, since the caller got the xmit_lock */
printk(KERN_ERR "ppp: ppp_async_send didn't accept pkt\n");
- }
+ } else printk( "Unexpected alternative\n" );
}

/*
@@ -2275,10 +2466,14 @@
{
struct sk_buff *skb;

- while (!test_and_set_bit(0, &ppp->dev.tbusy)) {
+ if ((ppp->flags & SC_SIMPLEX) && (ppp->token_state == NO_TOKEN)) {
+ printk( "ppp: No token -> not now\n" );
+ return;
+ }
+ while (!test_and_set_bit(0, &ppp->xmit_lock)) {
skb = skb_dequeue(&ppp->xmt_q);
if (skb == NULL) {
- ppp->dev.tbusy = 0;
+ ppp->xmit_lock = 0;
mark_bh(NET_BH);
break;
}
@@ -2295,11 +2490,11 @@
{
CHECK_PPP_VOID();

- if (!ppp->dev.tbusy) {
- printk(KERN_ERR "ppp_output_wakeup called but tbusy==0\n");
+ if (!ppp->xmit_lock) {
+ printk(KERN_ERR "ppp_output_wakeup called but xmit_lock==0\n");
return;
}
- ppp->dev.tbusy = 0;
+ ppp->xmit_lock = 0;
ppp_send_frames(ppp);
}

@@ -2421,14 +2616,6 @@
}

/*
- * The dev->tbusy field acts as a lock to allow only
- * one packet to be processed at a time. If we can't
- * get the lock, try again later.
- */
- if (test_and_set_bit(0, &dev->tbusy))
- return 1;
-
- /*
* Put the 4-byte PPP header on the packet.
* If there isn't room for it, we have to copy the packet.
*/
@@ -2440,7 +2627,6 @@
printk(KERN_ERR "%s: skb hdr alloc failed\n",
ppp->name);
dev_kfree_skb(skb);
- dev->tbusy = 0;
return 0;
}
skb_reserve(new_skb, PPP_HDRLEN);
@@ -2455,7 +2641,14 @@
hdr[2] = proto >> 8;
hdr[3] = proto;

- ppp_send_frame(ppp, skb);
+ /*
+ * The xmit_lock field acts as a lock to allow only
+ * one packet to be processed at a time. If we can't
+ * get the lock, try again later.
+ */
+
+ skb_queue_tail(&ppp->xmt_q, skb);
+ ppp_send_frames(ppp);
return 0;
}

@@ -2597,8 +2790,13 @@
skb_queue_head_init(&ppp->xmt_q);
skb_queue_head_init(&ppp->rcv_q);

- ppp->last_xmit = jiffies;
- ppp->last_recv = jiffies;
+ ppp->last_xmit = ppp->last_recv = ppp->got_token_from = jiffies;
+
+ ppp->xmit_lock = 0;
+ ppp->token_state = UNK_TOKEN;
+ init_timer(&ppp->token_timer);
+ ppp->token_timer.data = (unsigned long) ((void *) ppp);
+ ppp->token_timer.function = (void *) token_timeout;

/* clear statistics */
memset(&ppp->stats, 0, sizeof (struct pppstat));

-- 
I'm really pavel@atrey.karlin.mff.cuni.cz. 	   Pavel
Look at http://atrey.karlin.mff.cuni.cz/~pavel/ ;-).

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/