URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k/trunk/linux/linux-2.4/net/lapb
- from Rev 1275 to Rev 1765
- ↔ Reverse comparison
Rev 1275 → Rev 1765
/lapb_timer.c
0,0 → 1,189
/* |
* LAPB release 002 |
* |
* This code REQUIRES 2.1.15 or higher/ NET3.038 |
* |
* This module: |
* This module is free software; you can redistribute it and/or |
* modify it under the terms of the GNU General Public License |
* as published by the Free Software Foundation; either version |
* 2 of the License, or (at your option) any later version. |
* |
* History |
* LAPB 001 Jonathan Naylor Started Coding |
* LAPB 002 Jonathan Naylor New timer architecture. |
*/ |
|
#include <linux/errno.h> |
#include <linux/types.h> |
#include <linux/socket.h> |
#include <linux/in.h> |
#include <linux/kernel.h> |
#include <linux/sched.h> |
#include <linux/timer.h> |
#include <linux/string.h> |
#include <linux/sockios.h> |
#include <linux/net.h> |
#include <linux/inet.h> |
#include <linux/skbuff.h> |
#include <net/sock.h> |
#include <asm/uaccess.h> |
#include <asm/system.h> |
#include <linux/fcntl.h> |
#include <linux/mm.h> |
#include <linux/interrupt.h> |
#include <net/lapb.h> |
|
static void lapb_t1timer_expiry(unsigned long); |
static void lapb_t2timer_expiry(unsigned long); |
|
void lapb_start_t1timer(lapb_cb *lapb) |
{ |
del_timer(&lapb->t1timer); |
|
lapb->t1timer.data = (unsigned long)lapb; |
lapb->t1timer.function = &lapb_t1timer_expiry; |
lapb->t1timer.expires = jiffies + lapb->t1; |
|
add_timer(&lapb->t1timer); |
} |
|
void lapb_start_t2timer(lapb_cb *lapb) |
{ |
del_timer(&lapb->t2timer); |
|
lapb->t2timer.data = (unsigned long)lapb; |
lapb->t2timer.function = &lapb_t2timer_expiry; |
lapb->t2timer.expires = jiffies + lapb->t2; |
|
add_timer(&lapb->t2timer); |
} |
|
void lapb_stop_t1timer(lapb_cb *lapb) |
{ |
del_timer(&lapb->t1timer); |
} |
|
void lapb_stop_t2timer(lapb_cb *lapb) |
{ |
del_timer(&lapb->t2timer); |
} |
|
int lapb_t1timer_running(lapb_cb *lapb) |
{ |
return timer_pending(&lapb->t1timer); |
} |
|
static void lapb_t2timer_expiry(unsigned long param) |
{ |
lapb_cb *lapb = (lapb_cb *)param; |
|
if (lapb->condition & LAPB_ACK_PENDING_CONDITION) { |
lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; |
lapb_timeout_response(lapb); |
} |
} |
|
static void lapb_t1timer_expiry(unsigned long param) |
{ |
lapb_cb *lapb = (lapb_cb *)param; |
|
switch (lapb->state) { |
|
/* |
* If we are a DCE, keep going DM .. DM .. DM |
*/ |
case LAPB_STATE_0: |
if (lapb->mode & LAPB_DCE) |
lapb_send_control(lapb, LAPB_DM, LAPB_POLLOFF, LAPB_RESPONSE); |
break; |
|
/* |
* Awaiting connection state, send SABM(E), up to N2 times. |
*/ |
case LAPB_STATE_1: |
if (lapb->n2count == lapb->n2) { |
lapb_clear_queues(lapb); |
lapb->state = LAPB_STATE_0; |
lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token); |
#endif |
return; |
} else { |
lapb->n2count++; |
if (lapb->mode & LAPB_EXTENDED) { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 TX SABME(1)\n", lapb->token); |
#endif |
lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); |
} else { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 TX SABM(1)\n", lapb->token); |
#endif |
lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); |
} |
} |
break; |
|
/* |
* Awaiting disconnection state, send DISC, up to N2 times. |
*/ |
case LAPB_STATE_2: |
if (lapb->n2count == lapb->n2) { |
lapb_clear_queues(lapb); |
lapb->state = LAPB_STATE_0; |
lapb_disconnect_confirmation(lapb, LAPB_TIMEDOUT); |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); |
#endif |
return; |
} else { |
lapb->n2count++; |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S2 TX DISC(1)\n", lapb->token); |
#endif |
lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); |
} |
break; |
|
/* |
* Data transfer state, restransmit I frames, up to N2 times. |
*/ |
case LAPB_STATE_3: |
if (lapb->n2count == lapb->n2) { |
lapb_clear_queues(lapb); |
lapb->state = LAPB_STATE_0; |
lapb_stop_t2timer(lapb); |
lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token); |
#endif |
return; |
} else { |
lapb->n2count++; |
lapb_requeue_frames(lapb); |
} |
break; |
|
/* |
* Frame reject state, restransmit FRMR frames, up to N2 times. |
*/ |
case LAPB_STATE_4: |
if (lapb->n2count == lapb->n2) { |
lapb_clear_queues(lapb); |
lapb->state = LAPB_STATE_0; |
lapb_disconnect_indication(lapb, LAPB_TIMEDOUT); |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S4 -> S0\n", lapb->token); |
#endif |
return; |
} else { |
lapb->n2count++; |
lapb_transmit_frmr(lapb); |
} |
break; |
} |
|
lapb_start_t1timer(lapb); |
} |
/lapb_in.c
0,0 → 1,641
/* |
* LAPB release 002 |
* |
* This code REQUIRES 2.1.15 or higher/ NET3.038 |
* |
* This module: |
* This module is free software; you can redistribute it and/or |
* modify it under the terms of the GNU General Public License |
* as published by the Free Software Foundation; either version |
* 2 of the License, or (at your option) any later version. |
* |
* History |
* LAPB 001 Jonathan Naulor Started Coding |
* LAPB 002 Jonathan Naylor New timer architecture. |
* 2000-10-29 Henner Eisen lapb_data_indication() return status. |
*/ |
|
#include <linux/errno.h> |
#include <linux/types.h> |
#include <linux/socket.h> |
#include <linux/in.h> |
#include <linux/kernel.h> |
#include <linux/sched.h> |
#include <linux/timer.h> |
#include <linux/string.h> |
#include <linux/sockios.h> |
#include <linux/net.h> |
#include <linux/inet.h> |
#include <linux/netdevice.h> |
#include <linux/skbuff.h> |
#include <net/sock.h> |
#include <asm/uaccess.h> |
#include <asm/system.h> |
#include <linux/fcntl.h> |
#include <linux/mm.h> |
#include <linux/interrupt.h> |
#include <net/lapb.h> |
|
/* |
* State machine for state 0, Disconnected State. |
* The handling of the timer(s) is in file lapb_timer.c. |
*/ |
static void lapb_state0_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) |
{ |
switch (frame->type) { |
case LAPB_SABM: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S0 RX SABM(%d)\n", lapb->token, frame->pf); |
#endif |
if (lapb->mode & LAPB_EXTENDED) { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); |
} else { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf); |
#endif |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token); |
#endif |
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); |
lapb_stop_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_3; |
lapb->condition = 0x00; |
lapb->n2count = 0; |
lapb->vs = 0; |
lapb->vr = 0; |
lapb->va = 0; |
lapb_connect_indication(lapb, LAPB_OK); |
} |
break; |
|
case LAPB_SABME: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S0 RX SABME(%d)\n", lapb->token, frame->pf); |
#endif |
if (lapb->mode & LAPB_EXTENDED) { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf); |
#endif |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S0 -> S3\n", lapb->token); |
#endif |
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); |
lapb_stop_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_3; |
lapb->condition = 0x00; |
lapb->n2count = 0; |
lapb->vs = 0; |
lapb->vr = 0; |
lapb->va = 0; |
lapb_connect_indication(lapb, LAPB_OK); |
} else { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S0 TX DM(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); |
} |
break; |
|
case LAPB_DISC: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S0 RX DISC(%d)\n", lapb->token, frame->pf); |
printk(KERN_DEBUG "lapb: (%p) S0 TX UA(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); |
break; |
|
default: |
break; |
} |
|
kfree_skb(skb); |
} |
|
/* |
* State machine for state 1, Awaiting Connection State. |
* The handling of the timer(s) is in file lapb_timer.c. |
*/ |
static void lapb_state1_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) |
{ |
switch (frame->type) { |
case LAPB_SABM: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 RX SABM(%d)\n", lapb->token, frame->pf); |
#endif |
if (lapb->mode & LAPB_EXTENDED) { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); |
} else { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); |
} |
break; |
|
case LAPB_SABME: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 RX SABME(%d)\n", lapb->token, frame->pf); |
#endif |
if (lapb->mode & LAPB_EXTENDED) { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 TX UA(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); |
} else { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); |
} |
break; |
|
case LAPB_DISC: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 RX DISC(%d)\n", lapb->token, frame->pf); |
printk(KERN_DEBUG "lapb: (%p) S1 TX DM(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); |
break; |
|
case LAPB_UA: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 RX UA(%d)\n", lapb->token, frame->pf); |
#endif |
if (frame->pf) { |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S1 -> S3\n", lapb->token); |
#endif |
lapb_stop_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_3; |
lapb->condition = 0x00; |
lapb->n2count = 0; |
lapb->vs = 0; |
lapb->vr = 0; |
lapb->va = 0; |
lapb_connect_confirmation(lapb, LAPB_OK); |
} |
break; |
|
case LAPB_DM: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 RX DM(%d)\n", lapb->token, frame->pf); |
#endif |
if (frame->pf) { |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token); |
#endif |
lapb_clear_queues(lapb); |
lapb->state = LAPB_STATE_0; |
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb_disconnect_indication(lapb, LAPB_REFUSED); |
} |
break; |
|
default: |
break; |
} |
|
kfree_skb(skb); |
} |
|
/* |
* State machine for state 2, Awaiting Release State. |
* The handling of the timer(s) is in file lapb_timer.c |
*/ |
static void lapb_state2_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) |
{ |
switch (frame->type) { |
case LAPB_SABM: |
case LAPB_SABME: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S2 RX {SABM,SABME}(%d)\n", lapb->token, frame->pf); |
printk(KERN_DEBUG "lapb: (%p) S2 TX DM(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); |
break; |
|
case LAPB_DISC: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S2 RX DISC(%d)\n", lapb->token, frame->pf); |
printk(KERN_DEBUG "lapb: (%p) S2 TX UA(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); |
break; |
|
case LAPB_UA: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S2 RX UA(%d)\n", lapb->token, frame->pf); |
#endif |
if (frame->pf) { |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); |
#endif |
lapb->state = LAPB_STATE_0; |
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb_disconnect_confirmation(lapb, LAPB_OK); |
} |
break; |
|
case LAPB_DM: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, frame->pf); |
#endif |
if (frame->pf) { |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S2 -> S0\n", lapb->token); |
#endif |
lapb->state = LAPB_STATE_0; |
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb_disconnect_confirmation(lapb, LAPB_NOTCONNECTED); |
} |
break; |
|
case LAPB_I: |
case LAPB_REJ: |
case LAPB_RNR: |
case LAPB_RR: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S2 RX {I,REJ,RNR,RR}(%d)\n", lapb->token, frame->pf); |
printk(KERN_DEBUG "lapb: (%p) S2 RX DM(%d)\n", lapb->token, frame->pf); |
#endif |
if (frame->pf) lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); |
break; |
|
default: |
break; |
} |
|
kfree_skb(skb); |
} |
|
/* |
* State machine for state 3, Connected State. |
* The handling of the timer(s) is in file lapb_timer.c |
*/ |
static void lapb_state3_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) |
{ |
int queued = 0; |
int modulus; |
|
modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; |
|
switch (frame->type) { |
case LAPB_SABM: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 RX SABM(%d)\n", lapb->token, frame->pf); |
#endif |
if (lapb->mode & LAPB_EXTENDED) { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); |
} else { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); |
lapb_stop_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->condition = 0x00; |
lapb->n2count = 0; |
lapb->vs = 0; |
lapb->vr = 0; |
lapb->va = 0; |
lapb_requeue_frames(lapb); |
} |
break; |
|
case LAPB_SABME: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 RX SABME(%d)\n", lapb->token, frame->pf); |
#endif |
if (lapb->mode & LAPB_EXTENDED) { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 TX UA(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); |
lapb_stop_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->condition = 0x00; |
lapb->n2count = 0; |
lapb->vs = 0; |
lapb->vr = 0; |
lapb->va = 0; |
lapb_requeue_frames(lapb); |
} else { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 TX DM(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); |
} |
break; |
|
case LAPB_DISC: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 RX DISC(%d)\n", lapb->token, frame->pf); |
#endif |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token); |
#endif |
lapb_clear_queues(lapb); |
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); |
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_0; |
lapb_disconnect_indication(lapb, LAPB_OK); |
break; |
|
case LAPB_DM: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 RX DM(%d)\n", lapb->token, frame->pf); |
#endif |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S3 -> S0\n", lapb->token); |
#endif |
lapb_clear_queues(lapb); |
lapb->state = LAPB_STATE_0; |
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb_disconnect_indication(lapb, LAPB_NOTCONNECTED); |
break; |
|
case LAPB_RNR: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 RX RNR(%d) R%d\n", lapb->token, frame->pf, frame->nr); |
#endif |
lapb->condition |= LAPB_PEER_RX_BUSY_CONDITION; |
lapb_check_need_response(lapb, frame->cr, frame->pf); |
if (lapb_validate_nr(lapb, frame->nr)) { |
lapb_check_iframes_acked(lapb, frame->nr); |
} else { |
lapb->frmr_data = *frame; |
lapb->frmr_type = LAPB_FRMR_Z; |
lapb_transmit_frmr(lapb); |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); |
#endif |
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_4; |
lapb->n2count = 0; |
} |
break; |
|
case LAPB_RR: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 RX RR(%d) R%d\n", lapb->token, frame->pf, frame->nr); |
#endif |
lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; |
lapb_check_need_response(lapb, frame->cr, frame->pf); |
if (lapb_validate_nr(lapb, frame->nr)) { |
lapb_check_iframes_acked(lapb, frame->nr); |
} else { |
lapb->frmr_data = *frame; |
lapb->frmr_type = LAPB_FRMR_Z; |
lapb_transmit_frmr(lapb); |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); |
#endif |
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_4; |
lapb->n2count = 0; |
} |
break; |
|
case LAPB_REJ: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 RX REJ(%d) R%d\n", lapb->token, frame->pf, frame->nr); |
#endif |
lapb->condition &= ~LAPB_PEER_RX_BUSY_CONDITION; |
lapb_check_need_response(lapb, frame->cr, frame->pf); |
if (lapb_validate_nr(lapb, frame->nr)) { |
lapb_frames_acked(lapb, frame->nr); |
lapb_stop_t1timer(lapb); |
lapb->n2count = 0; |
lapb_requeue_frames(lapb); |
} else { |
lapb->frmr_data = *frame; |
lapb->frmr_type = LAPB_FRMR_Z; |
lapb_transmit_frmr(lapb); |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); |
#endif |
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_4; |
lapb->n2count = 0; |
} |
break; |
|
case LAPB_I: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 RX I(%d) S%d R%d\n", lapb->token, frame->pf, frame->ns, frame->nr); |
#endif |
if (!lapb_validate_nr(lapb, frame->nr)) { |
lapb->frmr_data = *frame; |
lapb->frmr_type = LAPB_FRMR_Z; |
lapb_transmit_frmr(lapb); |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); |
#endif |
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_4; |
lapb->n2count = 0; |
break; |
} |
if (lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) { |
lapb_frames_acked(lapb, frame->nr); |
} else { |
lapb_check_iframes_acked(lapb, frame->nr); |
} |
if (frame->ns == lapb->vr) { |
int cn; |
cn = lapb_data_indication(lapb, skb); |
queued = 1; |
/* |
* If upper layer has dropped the frame, we |
* basically ignore any further protocol |
* processing. This will cause the peer |
* to re-transmit the frame later like |
* a frame lost on the wire. |
*/ |
if(cn == NET_RX_DROP){ |
printk(KERN_DEBUG "LAPB: rx congestion\n"); |
break; |
} |
lapb->vr = (lapb->vr + 1) % modulus; |
lapb->condition &= ~LAPB_REJECT_CONDITION; |
if (frame->pf) { |
lapb_enquiry_response(lapb); |
} else { |
if (!(lapb->condition & LAPB_ACK_PENDING_CONDITION)) { |
lapb->condition |= LAPB_ACK_PENDING_CONDITION; |
lapb_start_t2timer(lapb); |
} |
} |
} else { |
if (lapb->condition & LAPB_REJECT_CONDITION) { |
if (frame->pf) |
lapb_enquiry_response(lapb); |
} else { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 TX REJ(%d) R%d\n", lapb->token, frame->pf, lapb->vr); |
#endif |
lapb->condition |= LAPB_REJECT_CONDITION; |
lapb_send_control(lapb, LAPB_REJ, frame->pf, LAPB_RESPONSE); |
lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; |
} |
} |
break; |
|
case LAPB_FRMR: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 RX FRMR(%d) %02X %02X %02X %02X %02X\n", lapb->token, frame->pf, skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4]); |
#endif |
lapb_establish_data_link(lapb); |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S3 -> S1\n", lapb->token); |
#endif |
lapb_requeue_frames(lapb); |
lapb->state = LAPB_STATE_1; |
break; |
|
case LAPB_ILLEGAL: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 RX ILLEGAL(%d)\n", lapb->token, frame->pf); |
#endif |
lapb->frmr_data = *frame; |
lapb->frmr_type = LAPB_FRMR_W; |
lapb_transmit_frmr(lapb); |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S3 -> S4\n", lapb->token); |
#endif |
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_4; |
lapb->n2count = 0; |
break; |
|
default: |
break; |
} |
|
if (!queued) |
kfree_skb(skb); |
} |
|
/* |
* State machine for state 4, Frame Reject State. |
* The handling of the timer(s) is in file lapb_timer.c. |
*/ |
static void lapb_state4_machine(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) |
{ |
switch (frame->type) { |
case LAPB_SABM: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S4 RX SABM(%d)\n", lapb->token, frame->pf); |
#endif |
if (lapb->mode & LAPB_EXTENDED) { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); |
} else { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", lapb->token, frame->pf); |
#endif |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token); |
#endif |
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); |
lapb_stop_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_3; |
lapb->condition = 0x00; |
lapb->n2count = 0; |
lapb->vs = 0; |
lapb->vr = 0; |
lapb->va = 0; |
lapb_connect_indication(lapb, LAPB_OK); |
} |
break; |
|
case LAPB_SABME: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S4 RX SABME(%d)\n", lapb->token, frame->pf); |
#endif |
if (lapb->mode & LAPB_EXTENDED) { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S4 TX UA(%d)\n", lapb->token, frame->pf); |
#endif |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S4 -> S3\n", lapb->token); |
#endif |
lapb_send_control(lapb, LAPB_UA, frame->pf, LAPB_RESPONSE); |
lapb_stop_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_3; |
lapb->condition = 0x00; |
lapb->n2count = 0; |
lapb->vs = 0; |
lapb->vr = 0; |
lapb->va = 0; |
lapb_connect_indication(lapb, LAPB_OK); |
} else { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S4 TX DM(%d)\n", lapb->token, frame->pf); |
#endif |
lapb_send_control(lapb, LAPB_DM, frame->pf, LAPB_RESPONSE); |
} |
break; |
|
default: |
break; |
} |
|
kfree_skb(skb); |
} |
|
/* |
* Process an incoming LAPB frame |
*/ |
void lapb_data_input(lapb_cb *lapb, struct sk_buff *skb) |
{ |
struct lapb_frame frame; |
|
lapb_decode(lapb, skb, &frame); |
|
switch (lapb->state) { |
case LAPB_STATE_0: |
lapb_state0_machine(lapb, skb, &frame); |
break; |
case LAPB_STATE_1: |
lapb_state1_machine(lapb, skb, &frame); |
break; |
case LAPB_STATE_2: |
lapb_state2_machine(lapb, skb, &frame); |
break; |
case LAPB_STATE_3: |
lapb_state3_machine(lapb, skb, &frame); |
break; |
case LAPB_STATE_4: |
lapb_state4_machine(lapb, skb, &frame); |
break; |
} |
|
lapb_kick(lapb); |
} |
/lapb_out.c
0,0 → 1,223
/* |
* LAPB release 002 |
* |
* This code REQUIRES 2.1.15 or higher/ NET3.038 |
* |
* This module: |
* This module is free software; you can redistribute it and/or |
* modify it under the terms of the GNU General Public License |
* as published by the Free Software Foundation; either version |
* 2 of the License, or (at your option) any later version. |
* |
* History |
* LAPB 001 Jonathan Naylor Started Coding |
* LAPB 002 Jonathan Naylor New timer architecture. |
*/ |
|
#include <linux/errno.h> |
#include <linux/types.h> |
#include <linux/socket.h> |
#include <linux/in.h> |
#include <linux/kernel.h> |
#include <linux/sched.h> |
#include <linux/timer.h> |
#include <linux/string.h> |
#include <linux/sockios.h> |
#include <linux/net.h> |
#include <linux/inet.h> |
#include <linux/skbuff.h> |
#include <net/sock.h> |
#include <asm/uaccess.h> |
#include <asm/system.h> |
#include <linux/fcntl.h> |
#include <linux/mm.h> |
#include <linux/interrupt.h> |
#include <net/lapb.h> |
|
/* |
* This procedure is passed a buffer descriptor for an iframe. It builds |
* the rest of the control part of the frame and then writes it out. |
*/ |
static void lapb_send_iframe(lapb_cb *lapb, struct sk_buff *skb, int poll_bit) |
{ |
unsigned char *frame; |
|
if (skb == NULL) |
return; |
|
if (lapb->mode & LAPB_EXTENDED) { |
frame = skb_push(skb, 2); |
|
frame[0] = LAPB_I; |
frame[0] |= (lapb->vs << 1); |
frame[1] = (poll_bit) ? LAPB_EPF : 0; |
frame[1] |= (lapb->vr << 1); |
} else { |
frame = skb_push(skb, 1); |
|
*frame = LAPB_I; |
*frame |= (poll_bit) ? LAPB_SPF : 0; |
*frame |= (lapb->vr << 5); |
*frame |= (lapb->vs << 1); |
} |
|
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S%d TX I(%d) S%d R%d\n", lapb->token, lapb->state, poll_bit, lapb->vs, lapb->vr); |
#endif |
|
lapb_transmit_buffer(lapb, skb, LAPB_COMMAND); |
} |
|
void lapb_kick(lapb_cb *lapb) |
{ |
struct sk_buff *skb, *skbn; |
unsigned short modulus, start, end; |
|
modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; |
|
start = (skb_peek(&lapb->ack_queue) == NULL) ? lapb->va : lapb->vs; |
end = (lapb->va + lapb->window) % modulus; |
|
if (!(lapb->condition & LAPB_PEER_RX_BUSY_CONDITION) && |
start != end && |
skb_peek(&lapb->write_queue) != NULL) { |
|
lapb->vs = start; |
|
/* |
* Dequeue the frame and copy it. |
*/ |
skb = skb_dequeue(&lapb->write_queue); |
|
do { |
if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { |
skb_queue_head(&lapb->write_queue, skb); |
break; |
} |
|
if (skb->sk != NULL) |
skb_set_owner_w(skbn, skb->sk); |
|
/* |
* Transmit the frame copy. |
*/ |
lapb_send_iframe(lapb, skbn, LAPB_POLLOFF); |
|
lapb->vs = (lapb->vs + 1) % modulus; |
|
/* |
* Requeue the original data frame. |
*/ |
skb_queue_tail(&lapb->ack_queue, skb); |
|
} while (lapb->vs != end && (skb = skb_dequeue(&lapb->write_queue)) != NULL); |
|
lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; |
|
if (!lapb_t1timer_running(lapb)) |
lapb_start_t1timer(lapb); |
} |
} |
|
void lapb_transmit_buffer(lapb_cb *lapb, struct sk_buff *skb, int type) |
{ |
unsigned char *ptr; |
|
ptr = skb_push(skb, 1); |
|
if (lapb->mode & LAPB_MLP) { |
if (lapb->mode & LAPB_DCE) { |
if (type == LAPB_COMMAND) |
*ptr = LAPB_ADDR_C; |
if (type == LAPB_RESPONSE) |
*ptr = LAPB_ADDR_D; |
} else { |
if (type == LAPB_COMMAND) |
*ptr = LAPB_ADDR_D; |
if (type == LAPB_RESPONSE) |
*ptr = LAPB_ADDR_C; |
} |
} else { |
if (lapb->mode & LAPB_DCE) { |
if (type == LAPB_COMMAND) |
*ptr = LAPB_ADDR_A; |
if (type == LAPB_RESPONSE) |
*ptr = LAPB_ADDR_B; |
} else { |
if (type == LAPB_COMMAND) |
*ptr = LAPB_ADDR_B; |
if (type == LAPB_RESPONSE) |
*ptr = LAPB_ADDR_A; |
} |
} |
|
#if LAPB_DEBUG > 2 |
printk(KERN_DEBUG "lapb: (%p) S%d TX %02X %02X %02X\n", lapb->token, lapb->state, skb->data[0], skb->data[1], skb->data[2]); |
#endif |
|
if (!lapb_data_transmit(lapb, skb)) |
kfree_skb(skb); |
} |
|
void lapb_establish_data_link(lapb_cb *lapb) |
{ |
lapb->condition = 0x00; |
lapb->n2count = 0; |
|
if (lapb->mode & LAPB_EXTENDED) { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S%d TX SABME(1)\n", lapb->token, lapb->state); |
#endif |
lapb_send_control(lapb, LAPB_SABME, LAPB_POLLON, LAPB_COMMAND); |
} else { |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S%d TX SABM(1)\n", lapb->token, lapb->state); |
#endif |
lapb_send_control(lapb, LAPB_SABM, LAPB_POLLON, LAPB_COMMAND); |
} |
|
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
} |
|
void lapb_enquiry_response(lapb_cb *lapb) |
{ |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S%d TX RR(1) R%d\n", lapb->token, lapb->state, lapb->vr); |
#endif |
|
lapb_send_control(lapb, LAPB_RR, LAPB_POLLON, LAPB_RESPONSE); |
|
lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; |
} |
|
void lapb_timeout_response(lapb_cb *lapb) |
{ |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S%d TX RR(0) R%d\n", lapb->token, lapb->state, lapb->vr); |
#endif |
|
lapb_send_control(lapb, LAPB_RR, LAPB_POLLOFF, LAPB_RESPONSE); |
|
lapb->condition &= ~LAPB_ACK_PENDING_CONDITION; |
} |
|
void lapb_check_iframes_acked(lapb_cb *lapb, unsigned short nr) |
{ |
if (lapb->vs == nr) { |
lapb_frames_acked(lapb, nr); |
lapb_stop_t1timer(lapb); |
lapb->n2count = 0; |
} else { |
if (lapb->va != nr) { |
lapb_frames_acked(lapb, nr); |
lapb_start_t1timer(lapb); |
} |
} |
} |
|
void lapb_check_need_response(lapb_cb *lapb, int type, int pf) |
{ |
if (type == LAPB_COMMAND && pf) |
lapb_enquiry_response(lapb); |
} |
/lapb_iface.c
0,0 → 1,412
/* |
* LAPB release 002 |
* |
* This code REQUIRES 2.1.15 or higher/ NET3.038 |
* |
* This module: |
* This module is free software; you can redistribute it and/or |
* modify it under the terms of the GNU General Public License |
* as published by the Free Software Foundation; either version |
* 2 of the License, or (at your option) any later version. |
* |
* History |
* LAPB 001 Jonathan Naylor Started Coding |
* LAPB 002 Jonathan Naylor New timer architecture. |
* 2000-10-29 Henner Eisen lapb_data_indication() return status. |
*/ |
|
#include <linux/module.h> |
#include <linux/errno.h> |
#include <linux/types.h> |
#include <linux/socket.h> |
#include <linux/in.h> |
#include <linux/kernel.h> |
#include <linux/sched.h> |
#include <linux/timer.h> |
#include <linux/string.h> |
#include <linux/sockios.h> |
#include <linux/net.h> |
#include <linux/inet.h> |
#include <linux/if_arp.h> |
#include <linux/skbuff.h> |
#include <net/sock.h> |
#include <asm/uaccess.h> |
#include <asm/system.h> |
#include <linux/fcntl.h> |
#include <linux/mm.h> |
#include <linux/interrupt.h> |
#include <linux/stat.h> |
#include <linux/init.h> |
#include <net/lapb.h> |
|
static lapb_cb *volatile lapb_list /* = NULL initially */; |
|
/* |
* Free an allocated lapb control block. This is done to centralise |
* the MOD count code. |
*/ |
static void lapb_free_cb(lapb_cb *lapb) |
{ |
kfree(lapb); |
|
MOD_DEC_USE_COUNT; |
} |
|
/* |
* Socket removal during an interrupt is now safe. |
*/ |
static void lapb_remove_cb(lapb_cb *lapb) |
{ |
lapb_cb *s; |
unsigned long flags; |
|
save_flags(flags); cli(); |
|
if ((s = lapb_list) == lapb) { |
lapb_list = s->next; |
restore_flags(flags); |
return; |
} |
|
while (s != NULL && s->next != NULL) { |
if (s->next == lapb) { |
s->next = lapb->next; |
restore_flags(flags); |
return; |
} |
|
s = s->next; |
} |
|
restore_flags(flags); |
} |
|
/* |
* Add a socket to the bound sockets list. |
*/ |
static void lapb_insert_cb(lapb_cb *lapb) |
{ |
unsigned long flags; |
|
save_flags(flags); cli(); |
|
lapb->next = lapb_list; |
lapb_list = lapb; |
|
restore_flags(flags); |
} |
|
/* |
* Convert the integer token used by the device driver into a pointer |
* to a LAPB control structure. |
*/ |
static lapb_cb *lapb_tokentostruct(void *token) |
{ |
lapb_cb *lapb; |
|
for (lapb = lapb_list; lapb != NULL; lapb = lapb->next) |
if (lapb->token == token) |
return lapb; |
|
return NULL; |
} |
|
/* |
* Create an empty LAPB control block. |
*/ |
static lapb_cb *lapb_create_cb(void) |
{ |
lapb_cb *lapb; |
|
if ((lapb = kmalloc(sizeof(*lapb), GFP_ATOMIC)) == NULL) |
return NULL; |
|
MOD_INC_USE_COUNT; |
|
memset(lapb, 0x00, sizeof(*lapb)); |
|
skb_queue_head_init(&lapb->write_queue); |
skb_queue_head_init(&lapb->ack_queue); |
|
init_timer(&lapb->t1timer); |
init_timer(&lapb->t2timer); |
|
lapb->t1 = LAPB_DEFAULT_T1; |
lapb->t2 = LAPB_DEFAULT_T2; |
lapb->n2 = LAPB_DEFAULT_N2; |
lapb->mode = LAPB_DEFAULT_MODE; |
lapb->window = LAPB_DEFAULT_WINDOW; |
lapb->state = LAPB_STATE_0; |
|
return lapb; |
} |
|
int lapb_register(void *token, struct lapb_register_struct *callbacks) |
{ |
lapb_cb *lapb; |
|
if (lapb_tokentostruct(token) != NULL) |
return LAPB_BADTOKEN; |
|
if ((lapb = lapb_create_cb()) == NULL) |
return LAPB_NOMEM; |
|
lapb->token = token; |
lapb->callbacks = *callbacks; |
|
lapb_insert_cb(lapb); |
|
lapb_start_t1timer(lapb); |
|
return LAPB_OK; |
} |
|
int lapb_unregister(void *token) |
{ |
lapb_cb *lapb; |
|
if ((lapb = lapb_tokentostruct(token)) == NULL) |
return LAPB_BADTOKEN; |
|
lapb_stop_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
|
lapb_clear_queues(lapb); |
|
lapb_remove_cb(lapb); |
|
lapb_free_cb(lapb); |
|
return LAPB_OK; |
} |
|
int lapb_getparms(void *token, struct lapb_parms_struct *parms) |
{ |
lapb_cb *lapb; |
|
if ((lapb = lapb_tokentostruct(token)) == NULL) |
return LAPB_BADTOKEN; |
|
parms->t1 = lapb->t1 / HZ; |
parms->t2 = lapb->t2 / HZ; |
parms->n2 = lapb->n2; |
parms->n2count = lapb->n2count; |
parms->state = lapb->state; |
parms->window = lapb->window; |
parms->mode = lapb->mode; |
|
if (!timer_pending(&lapb->t1timer)) |
parms->t1timer = 0; |
else |
parms->t1timer = (lapb->t1timer.expires - jiffies) / HZ; |
|
if (!timer_pending(&lapb->t2timer)) |
parms->t2timer = 0; |
else |
parms->t2timer = (lapb->t2timer.expires - jiffies) / HZ; |
|
return LAPB_OK; |
} |
|
int lapb_setparms(void *token, struct lapb_parms_struct *parms) |
{ |
lapb_cb *lapb; |
|
if ((lapb = lapb_tokentostruct(token)) == NULL) |
return LAPB_BADTOKEN; |
|
if (parms->t1 < 1) |
return LAPB_INVALUE; |
|
if (parms->t2 < 1) |
return LAPB_INVALUE; |
|
if (parms->n2 < 1) |
return LAPB_INVALUE; |
|
if (lapb->state == LAPB_STATE_0) { |
if (parms->mode & LAPB_EXTENDED) { |
if (parms->window < 1 || parms->window > 127) |
return LAPB_INVALUE; |
} else { |
if (parms->window < 1 || parms->window > 7) |
return LAPB_INVALUE; |
} |
|
lapb->mode = parms->mode; |
lapb->window = parms->window; |
} |
|
lapb->t1 = parms->t1 * HZ; |
lapb->t2 = parms->t2 * HZ; |
lapb->n2 = parms->n2; |
|
return LAPB_OK; |
} |
|
int lapb_connect_request(void *token) |
{ |
lapb_cb *lapb; |
|
if ((lapb = lapb_tokentostruct(token)) == NULL) |
return LAPB_BADTOKEN; |
|
switch (lapb->state) { |
case LAPB_STATE_1: |
return LAPB_OK; |
case LAPB_STATE_3: |
case LAPB_STATE_4: |
return LAPB_CONNECTED; |
} |
|
lapb_establish_data_link(lapb); |
|
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S0 -> S1\n", lapb->token); |
#endif |
|
lapb->state = LAPB_STATE_1; |
|
return LAPB_OK; |
} |
|
int lapb_disconnect_request(void *token) |
{ |
lapb_cb *lapb; |
|
if ((lapb = lapb_tokentostruct(token)) == NULL) |
return LAPB_BADTOKEN; |
|
switch (lapb->state) { |
case LAPB_STATE_0: |
return LAPB_NOTCONNECTED; |
|
case LAPB_STATE_1: |
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S1 TX DISC(1)\n", lapb->token); |
#endif |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S1 -> S0\n", lapb->token); |
#endif |
lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); |
lapb->state = LAPB_STATE_0; |
lapb_start_t1timer(lapb); |
return LAPB_NOTCONNECTED; |
|
case LAPB_STATE_2: |
return LAPB_OK; |
} |
|
lapb_clear_queues(lapb); |
lapb->n2count = 0; |
lapb_send_control(lapb, LAPB_DISC, LAPB_POLLON, LAPB_COMMAND); |
lapb_start_t1timer(lapb); |
lapb_stop_t2timer(lapb); |
lapb->state = LAPB_STATE_2; |
|
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S3 DISC(1)\n", lapb->token); |
#endif |
#if LAPB_DEBUG > 0 |
printk(KERN_DEBUG "lapb: (%p) S3 -> S2\n", lapb->token); |
#endif |
|
return LAPB_OK; |
} |
|
int lapb_data_request(void *token, struct sk_buff *skb) |
{ |
lapb_cb *lapb; |
|
if ((lapb = lapb_tokentostruct(token)) == NULL) |
return LAPB_BADTOKEN; |
|
if (lapb->state != LAPB_STATE_3 && lapb->state != LAPB_STATE_4) |
return LAPB_NOTCONNECTED; |
|
skb_queue_tail(&lapb->write_queue, skb); |
|
lapb_kick(lapb); |
|
return LAPB_OK; |
} |
|
int lapb_data_received(void *token, struct sk_buff *skb) |
{ |
lapb_cb *lapb; |
|
if ((lapb = lapb_tokentostruct(token)) == NULL) |
return LAPB_BADTOKEN; |
|
lapb_data_input(lapb, skb); |
|
return LAPB_OK; |
} |
|
void lapb_connect_confirmation(lapb_cb *lapb, int reason) |
{ |
if (lapb->callbacks.connect_confirmation != NULL) |
(lapb->callbacks.connect_confirmation)(lapb->token, reason); |
} |
|
void lapb_connect_indication(lapb_cb *lapb, int reason) |
{ |
if (lapb->callbacks.connect_indication != NULL) |
(lapb->callbacks.connect_indication)(lapb->token, reason); |
} |
|
void lapb_disconnect_confirmation(lapb_cb *lapb, int reason) |
{ |
if (lapb->callbacks.disconnect_confirmation != NULL) |
(lapb->callbacks.disconnect_confirmation)(lapb->token, reason); |
} |
|
void lapb_disconnect_indication(lapb_cb *lapb, int reason) |
{ |
if (lapb->callbacks.disconnect_indication != NULL) |
(lapb->callbacks.disconnect_indication)(lapb->token, reason); |
} |
|
int lapb_data_indication(lapb_cb *lapb, struct sk_buff *skb) |
{ |
if (lapb->callbacks.data_indication != NULL) { |
return (lapb->callbacks.data_indication)(lapb->token, skb); |
} |
kfree_skb(skb); |
return NET_RX_CN_HIGH; /* For now; must be != NET_RX_DROP */ |
} |
|
int lapb_data_transmit(lapb_cb *lapb, struct sk_buff *skb) |
{ |
int used = 0; |
|
if (lapb->callbacks.data_transmit != NULL) { |
(lapb->callbacks.data_transmit)(lapb->token, skb); |
used = 1; |
} |
|
return used; |
} |
|
EXPORT_SYMBOL(lapb_register); |
EXPORT_SYMBOL(lapb_unregister); |
EXPORT_SYMBOL(lapb_getparms); |
EXPORT_SYMBOL(lapb_setparms); |
EXPORT_SYMBOL(lapb_connect_request); |
EXPORT_SYMBOL(lapb_disconnect_request); |
EXPORT_SYMBOL(lapb_data_request); |
EXPORT_SYMBOL(lapb_data_received); |
|
static char banner[] __initdata = KERN_INFO "NET4: LAPB for Linux. Version 0.01 for NET4.0\n"; |
|
static int __init lapb_init(void) |
{ |
printk(banner); |
return 0; |
} |
|
MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>"); |
MODULE_DESCRIPTION("The X.25 Link Access Procedure B link layer protocol"); |
MODULE_LICENSE("GPL"); |
|
module_init(lapb_init); |
/lapb_subr.c
0,0 → 1,276
/* |
* LAPB release 002 |
* |
* This code REQUIRES 2.1.15 or higher/ NET3.038 |
* |
* This module: |
* This module is free software; you can redistribute it and/or |
* modify it under the terms of the GNU General Public License |
* as published by the Free Software Foundation; either version |
* 2 of the License, or (at your option) any later version. |
* |
* History |
* LAPB 001 Jonathan Naylor Started Coding |
*/ |
|
#include <linux/errno.h> |
#include <linux/types.h> |
#include <linux/socket.h> |
#include <linux/in.h> |
#include <linux/kernel.h> |
#include <linux/sched.h> |
#include <linux/timer.h> |
#include <linux/string.h> |
#include <linux/sockios.h> |
#include <linux/net.h> |
#include <linux/inet.h> |
#include <linux/skbuff.h> |
#include <net/sock.h> |
#include <asm/uaccess.h> |
#include <asm/system.h> |
#include <linux/fcntl.h> |
#include <linux/mm.h> |
#include <linux/interrupt.h> |
#include <net/lapb.h> |
|
/* |
* This routine purges all the queues of frames. |
*/ |
void lapb_clear_queues(lapb_cb *lapb) |
{ |
skb_queue_purge(&lapb->write_queue); |
skb_queue_purge(&lapb->ack_queue); |
} |
|
/* |
* This routine purges the input queue of those frames that have been |
* acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the |
* SDL diagram. |
*/ |
void lapb_frames_acked(lapb_cb *lapb, unsigned short nr) |
{ |
struct sk_buff *skb; |
int modulus; |
|
modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; |
|
/* |
* Remove all the ack-ed frames from the ack queue. |
*/ |
if (lapb->va != nr) { |
while (skb_peek(&lapb->ack_queue) != NULL && lapb->va != nr) { |
skb = skb_dequeue(&lapb->ack_queue); |
kfree_skb(skb); |
lapb->va = (lapb->va + 1) % modulus; |
} |
} |
} |
|
void lapb_requeue_frames(lapb_cb *lapb) |
{ |
struct sk_buff *skb, *skb_prev = NULL; |
|
/* |
* Requeue all the un-ack-ed frames on the output queue to be picked |
* up by lapb_kick called from the timer. This arrangement handles the |
* possibility of an empty output queue. |
*/ |
while ((skb = skb_dequeue(&lapb->ack_queue)) != NULL) { |
if (skb_prev == NULL) |
skb_queue_head(&lapb->write_queue, skb); |
else |
skb_append(skb_prev, skb); |
skb_prev = skb; |
} |
} |
|
/* |
* Validate that the value of nr is between va and vs. Return true or |
* false for testing. |
*/ |
int lapb_validate_nr(lapb_cb *lapb, unsigned short nr) |
{ |
unsigned short vc = lapb->va; |
int modulus; |
|
modulus = (lapb->mode & LAPB_EXTENDED) ? LAPB_EMODULUS : LAPB_SMODULUS; |
|
while (vc != lapb->vs) { |
if (nr == vc) return 1; |
vc = (vc + 1) % modulus; |
} |
|
if (nr == lapb->vs) return 1; |
|
return 0; |
} |
|
/* |
* This routine is the centralised routine for parsing the control |
* information for the different frame formats. |
*/ |
void lapb_decode(lapb_cb *lapb, struct sk_buff *skb, struct lapb_frame *frame) |
{ |
frame->type = LAPB_ILLEGAL; |
|
#if LAPB_DEBUG > 2 |
printk(KERN_DEBUG "lapb: (%p) S%d RX %02X %02X %02X\n", lapb->token, lapb->state, skb->data[0], skb->data[1], skb->data[2]); |
#endif |
|
if (lapb->mode & LAPB_MLP) { |
if (lapb->mode & LAPB_DCE) { |
if (skb->data[0] == LAPB_ADDR_D) |
frame->cr = LAPB_COMMAND; |
if (skb->data[0] == LAPB_ADDR_C) |
frame->cr = LAPB_RESPONSE; |
} else { |
if (skb->data[0] == LAPB_ADDR_C) |
frame->cr = LAPB_COMMAND; |
if (skb->data[0] == LAPB_ADDR_D) |
frame->cr = LAPB_RESPONSE; |
} |
} else { |
if (lapb->mode & LAPB_DCE) { |
if (skb->data[0] == LAPB_ADDR_B) |
frame->cr = LAPB_COMMAND; |
if (skb->data[0] == LAPB_ADDR_A) |
frame->cr = LAPB_RESPONSE; |
} else { |
if (skb->data[0] == LAPB_ADDR_A) |
frame->cr = LAPB_COMMAND; |
if (skb->data[0] == LAPB_ADDR_B) |
frame->cr = LAPB_RESPONSE; |
} |
} |
|
skb_pull(skb, 1); |
|
if (lapb->mode & LAPB_EXTENDED) { |
if ((skb->data[0] & LAPB_S) == 0) { |
frame->type = LAPB_I; /* I frame - carries NR/NS/PF */ |
frame->ns = (skb->data[0] >> 1) & 0x7F; |
frame->nr = (skb->data[1] >> 1) & 0x7F; |
frame->pf = skb->data[1] & LAPB_EPF; |
frame->control[0] = skb->data[0]; |
frame->control[1] = skb->data[1]; |
skb_pull(skb, 2); |
} else if ((skb->data[0] & LAPB_U) == 1) { /* S frame - take out PF/NR */ |
frame->type = skb->data[0] & 0x0F; |
frame->nr = (skb->data[1] >> 1) & 0x7F; |
frame->pf = skb->data[1] & LAPB_EPF; |
frame->control[0] = skb->data[0]; |
frame->control[1] = skb->data[1]; |
skb_pull(skb, 2); |
} else if ((skb->data[0] & LAPB_U) == 3) { /* U frame - take out PF */ |
frame->type = skb->data[0] & ~LAPB_SPF; |
frame->pf = skb->data[0] & LAPB_SPF; |
frame->control[0] = skb->data[0]; |
frame->control[1] = 0x00; |
skb_pull(skb, 1); |
} |
} else { |
if ((skb->data[0] & LAPB_S) == 0) { |
frame->type = LAPB_I; /* I frame - carries NR/NS/PF */ |
frame->ns = (skb->data[0] >> 1) & 0x07; |
frame->nr = (skb->data[0] >> 5) & 0x07; |
frame->pf = skb->data[0] & LAPB_SPF; |
} else if ((skb->data[0] & LAPB_U) == 1) { /* S frame - take out PF/NR */ |
frame->type = skb->data[0] & 0x0F; |
frame->nr = (skb->data[0] >> 5) & 0x07; |
frame->pf = skb->data[0] & LAPB_SPF; |
} else if ((skb->data[0] & LAPB_U) == 3) { /* U frame - take out PF */ |
frame->type = skb->data[0] & ~LAPB_SPF; |
frame->pf = skb->data[0] & LAPB_SPF; |
} |
|
frame->control[0] = skb->data[0]; |
|
skb_pull(skb, 1); |
} |
} |
|
/* |
* This routine is called when the HDLC layer internally generates a |
* command or response for the remote machine ( eg. RR, UA etc. ). |
* Only supervisory or unnumbered frames are processed, FRMRs are handled |
* by lapb_transmit_frmr below. |
*/ |
void lapb_send_control(lapb_cb *lapb, int frametype, int poll_bit, int type) |
{ |
struct sk_buff *skb; |
unsigned char *dptr; |
|
if ((skb = alloc_skb(LAPB_HEADER_LEN + 3, GFP_ATOMIC)) == NULL) |
return; |
|
skb_reserve(skb, LAPB_HEADER_LEN + 1); |
|
if (lapb->mode & LAPB_EXTENDED) { |
if ((frametype & LAPB_U) == LAPB_U) { |
dptr = skb_put(skb, 1); |
*dptr = frametype; |
*dptr |= (poll_bit) ? LAPB_SPF : 0; |
} else { |
dptr = skb_put(skb, 2); |
dptr[0] = frametype; |
dptr[1] = (lapb->vr << 1); |
dptr[1] |= (poll_bit) ? LAPB_EPF : 0; |
} |
} else { |
dptr = skb_put(skb, 1); |
*dptr = frametype; |
*dptr |= (poll_bit) ? LAPB_SPF : 0; |
if ((frametype & LAPB_U) == LAPB_S) /* S frames carry NR */ |
*dptr |= (lapb->vr << 5); |
} |
|
lapb_transmit_buffer(lapb, skb, type); |
} |
|
/* |
* This routine generates FRMRs based on information previously stored in |
* the LAPB control block. |
*/ |
void lapb_transmit_frmr(lapb_cb *lapb) |
{ |
struct sk_buff *skb; |
unsigned char *dptr; |
|
if ((skb = alloc_skb(LAPB_HEADER_LEN + 7, GFP_ATOMIC)) == NULL) |
return; |
|
skb_reserve(skb, LAPB_HEADER_LEN + 1); |
|
if (lapb->mode & LAPB_EXTENDED) { |
dptr = skb_put(skb, 6); |
*dptr++ = LAPB_FRMR; |
*dptr++ = lapb->frmr_data.control[0]; |
*dptr++ = lapb->frmr_data.control[1]; |
*dptr++ = (lapb->vs << 1) & 0xFE; |
*dptr = (lapb->vr << 1) & 0xFE; |
if (lapb->frmr_data.cr == LAPB_RESPONSE) |
*dptr |= 0x01; |
dptr++; |
*dptr++ = lapb->frmr_type; |
|
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X %02X %02X\n", lapb->token, lapb->state, skb->data[1], skb->data[2], skb->data[3], skb->data[4], skb->data[5]); |
#endif |
} else { |
dptr = skb_put(skb, 4); |
*dptr++ = LAPB_FRMR; |
*dptr++ = lapb->frmr_data.control[0]; |
*dptr = (lapb->vs << 1) & 0x0E; |
*dptr |= (lapb->vr << 5) & 0xE0; |
if (lapb->frmr_data.cr == LAPB_RESPONSE) |
*dptr |= 0x10; |
dptr++; |
*dptr++ = lapb->frmr_type; |
|
#if LAPB_DEBUG > 1 |
printk(KERN_DEBUG "lapb: (%p) S%d TX FRMR %02X %02X %02X\n", lapb->token, lapb->state, skb->data[1], skb->data[2], skb->data[3]); |
#endif |
} |
|
lapb_transmit_buffer(lapb, skb, LAPB_RESPONSE); |
} |
/Makefile
0,0 → 1,19
# |
# Makefile for the Linux LAPB layer. |
# |
# Note! Dependencies are done automagically by 'make dep', which also |
# removes any old dependencies. DON'T put your own dependencies here |
# unless it's something special (ie not a .c file). |
# |
# Note 2! The CFLAGS definition is now in the main makefile... |
|
|
O_TARGET := lapb.o |
|
export-objs := lapb_iface.o |
|
obj-y := lapb_in.o lapb_out.o lapb_subr.o lapb_timer.o lapb_iface.o |
obj-m := $(O_TARGET) |
|
include $(TOPDIR)/Rules.make |
|