patch-1.3.14 linux/net/ax25/ax25_in.c
Next file: linux/net/ax25/ax25_out.c
Previous file: linux/net/ax25/af_ax25.c
Back to the patch index
Back to the overall index
- Lines: 379
- Date:
Thu Jul 27 19:36:17 1995
- Orig file:
v1.3.13/linux/net/ax25/ax25_in.c
- Orig date:
Fri Jul 7 08:54:56 1995
diff -u --recursive --new-file v1.3.13/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c
@@ -1,5 +1,5 @@
/*
- * AX.25 release 029
+ * AX.25 release 030
*
* This is ALPHA test software. This code may break your machine, randomly fail to work with new
* releases, misbehave and/or generally screw up. It might even work.
@@ -24,6 +24,8 @@
* the sock structure.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* Jonathan(G4KLX) Added IP mode registration.
+ * AX.25 030 Jonathan(G4KLX) Added AX.25 fragment reception.
+ * Upgraded state machine for SABME.
*/
#include <linux/config.h>
@@ -53,6 +55,65 @@
#include <net/netrom.h>
#endif
+static int ax25_rx_iframe(ax25_cb *, struct sk_buff *);
+
+/*
+ * Given a fragment, queue it on the fragment queue and if the fragment
+ * is complete, send it back to ax25_rx_iframe.
+ */
+static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb)
+{
+ struct sk_buff *skbn, *skbo;
+
+ if (ax25->fragno != 0) {
+ if (!(*skb->data & SEG_FIRST)) {
+ if ((ax25->fragno - 1) == (*skb->data & SEG_REM)) {
+ ax25->fragno = *skb->data & SEG_REM;
+ skb_pull(skb, 1);
+ ax25->fraglen += skb->len;
+ skb_queue_tail(&ax25->frag_queue, skb);
+
+ if (ax25->fragno == 0) {
+ if ((skbn = alloc_skb(AX25_MAX_HEADER_LEN + ax25->fraglen, GFP_ATOMIC)) == NULL)
+ return 0;
+
+ skbn->free = 1;
+ skbn->arp = 1;
+
+ if (ax25->sk != NULL) {
+ skbn->sk = ax25->sk;
+ ax25->sk->rmem_alloc += skbn->truesize;
+ }
+
+ skb_reserve(skbn, AX25_MAX_HEADER_LEN);
+
+ while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) {
+ memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+ kfree_skb(skbo, FREE_READ);
+ }
+
+ ax25->fraglen = 0;
+
+ if (ax25_rx_iframe(ax25, skbn) == 0)
+ kfree_skb(skbn, FREE_READ);
+ }
+
+ return 1;
+ }
+ }
+ } else {
+ if (*skb->data & SEG_FIRST) {
+ ax25->fragno = *skb->data & SEG_REM;
+ skb_pull(skb, 1);
+ ax25->fraglen = skb->len;
+ skb_queue_tail(&ax25->frag_queue, skb);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
/*
* This is where all valid I frames are sent to, to be dispatched to
* whichever protocol requires them.
@@ -63,18 +124,18 @@
skb->h.raw = skb->data;
- switch (skb->data[1]) {
+ switch (*skb->data) {
#ifdef CONFIG_NETROM
case AX25_P_NETROM:
- skb_pull(skb, 2);
+ skb_pull(skb, 1); /* Remove PID */
queued = nr_route_frame(skb, ax25);
break;
#endif
#ifdef CONFIG_INET
case AX25_P_IP:
+ skb_pull(skb, 1); /* Remove PID */
+ skb->h.raw = skb->data;
ax25_ip_mode_set(&ax25->dest_addr, ax25->device, 'V');
- skb->h.raw += 2;
- skb_push(skb, skb->dev->hard_header_len);
ip_rcv(skb, skb->dev, NULL); /* Wrong ptype */
queued = 1;
break;
@@ -88,7 +149,12 @@
}
}
break;
-
+
+ case AX25_P_SEGMENT:
+ skb_pull(skb, 1); /* Remove PID */
+ queued = ax25_rx_fragment(ax25, skb);
+ break;
+
default:
break;
}
@@ -101,17 +167,21 @@
* The handling of the timer(s) is in file ax25_timer.c.
* Handling of state 0 and connection release is in ax25.c.
*/
-static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type)
+static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
{
- int pf = skb->data[0] & PF;
-
switch (frametype) {
case SABM:
- ax25_send_control(ax25, UA | pf, C_RESPONSE);
+ ax25->modulus = MODULUS;
+ ax25_send_control(ax25, UA, pf, C_RESPONSE);
+ break;
+
+ case SABME:
+ ax25->modulus = EMODULUS;
+ ax25_send_control(ax25, UA, pf, C_RESPONSE);
break;
case DISC:
- ax25_send_control(ax25, DM | pf, C_RESPONSE);
+ ax25_send_control(ax25, DM, pf, C_RESPONSE);
break;
case UA:
@@ -135,14 +205,18 @@
case DM:
if (pf) {
- ax25_clear_tx_queue(ax25);
- ax25->state = AX25_STATE_0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_CLOSE;
- ax25->sk->err = ECONNREFUSED;
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- ax25->sk->dead = 1;
+ if (ax25->modulus == MODULUS) {
+ ax25_clear_queues(ax25);
+ ax25->state = AX25_STATE_0;
+ if (ax25->sk != NULL) {
+ ax25->sk->state = TCP_CLOSE;
+ ax25->sk->err = ECONNREFUSED;
+ if (!ax25->sk->dead)
+ ax25->sk->state_change(ax25->sk);
+ ax25->sk->dead = 1;
+ }
+ } else {
+ ax25->modulus = MODULUS;
}
}
break;
@@ -159,17 +233,16 @@
* The handling of the timer(s) is in file ax25_timer.c
* Handling of state 0 and connection release is in ax25.c.
*/
-static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type)
+static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
{
- int pf = skb->data[0] & PF;
-
switch (frametype) {
case SABM:
- ax25_send_control(ax25, DM | pf, C_RESPONSE);
+ case SABME:
+ ax25_send_control(ax25, DM, pf, C_RESPONSE);
break;
case DISC:
- ax25_send_control(ax25, UA | pf, C_RESPONSE);
+ ax25_send_control(ax25, UA, pf, C_RESPONSE);
break;
case UA:
@@ -203,7 +276,7 @@
case RNR:
case RR:
if (pf)
- ax25_send_control(ax25, DM | PF, C_RESPONSE);
+ ax25_send_control(ax25, DM, POLLON, C_RESPONSE);
break;
default:
@@ -218,16 +291,25 @@
* The handling of the timer(s) is in file ax25_timer.c
* Handling of state 0 and connection release is in ax25.c.
*/
-static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type)
+static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type)
{
- unsigned short nr = (skb->data[0] >> 5) & 7;
- unsigned short ns = (skb->data[0] >> 1) & 7;
- int pf = skb->data[0] & PF;
int queued = 0;
switch (frametype) {
case SABM:
- ax25_send_control(ax25, UA | pf, C_RESPONSE);
+ ax25->modulus = MODULUS;
+ ax25_send_control(ax25, UA, pf, C_RESPONSE);
+ ax25->condition = 0x00;
+ ax25->t1timer = 0;
+ ax25->t3timer = ax25->t3;
+ ax25->vs = 0;
+ ax25->va = 0;
+ ax25->vr = 0;
+ break;
+
+ case SABME:
+ ax25->modulus = EMODULUS;
+ ax25_send_control(ax25, UA, pf, C_RESPONSE);
ax25->condition = 0x00;
ax25->t1timer = 0;
ax25->t3timer = ax25->t3;
@@ -237,8 +319,8 @@
break;
case DISC:
- ax25_clear_tx_queue(ax25);
- ax25_send_control(ax25, UA | pf, C_RESPONSE);
+ ax25_clear_queues(ax25);
+ ax25_send_control(ax25, UA, pf, C_RESPONSE);
ax25->t3timer = 0;
ax25->state = AX25_STATE_0;
if (ax25->sk != NULL) {
@@ -256,7 +338,7 @@
break;
case DM:
- ax25_clear_tx_queue(ax25);
+ ax25_clear_queues(ax25);
ax25->t3timer = 0;
ax25->state = AX25_STATE_0;
if (ax25->sk) {
@@ -327,7 +409,7 @@
if (pf) ax25_enquiry_response(ax25);
break;
}
- ax25->vr = (ax25->vr + 1) % MODULUS;
+ ax25->vr = (ax25->vr + 1) % ax25->modulus;
ax25->condition &= ~REJECT_CONDITION;
if (pf) {
ax25_enquiry_response(ax25);
@@ -342,7 +424,7 @@
if (pf) ax25_enquiry_response(ax25);
} else {
ax25->condition |= REJECT_CONDITION;
- ax25_send_control(ax25, REJ | pf, C_RESPONSE);
+ ax25_send_control(ax25, REJ, pf, C_RESPONSE);
ax25->condition &= ~ACK_PENDING_CONDITION;
}
}
@@ -366,16 +448,27 @@
* The handling of the timer(s) is in file ax25_timer.c
* Handling of state 0 and connection release is in ax25.c.
*/
-static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type)
+static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type)
{
- unsigned short nr = (skb->data[0] >> 5) & 7;
- unsigned short ns = (skb->data[0] >> 1) & 7;
- int pf = skb->data[0] & PF;
int queued = 0;
switch (frametype) {
case SABM:
- ax25_send_control(ax25, UA | pf, C_RESPONSE);
+ ax25->modulus = MODULUS;
+ ax25_send_control(ax25, UA, pf, C_RESPONSE);
+ ax25->condition = 0x00;
+ ax25->t1timer = 0;
+ ax25->t3timer = ax25->t3;
+ ax25->vs = 0;
+ ax25->va = 0;
+ ax25->vr = 0;
+ ax25->state = AX25_STATE_3;
+ ax25->n2count = 0;
+ break;
+
+ case SABME:
+ ax25->modulus = EMODULUS;
+ ax25_send_control(ax25, UA, pf, C_RESPONSE);
ax25->condition = 0x00;
ax25->t1timer = 0;
ax25->t3timer = ax25->t3;
@@ -387,8 +480,8 @@
break;
case DISC:
- ax25_clear_tx_queue(ax25);
- ax25_send_control(ax25, UA | pf, C_RESPONSE);
+ ax25_clear_queues(ax25);
+ ax25_send_control(ax25, UA, pf, C_RESPONSE);
ax25->t3timer = 0;
ax25->state = AX25_STATE_0;
if (ax25->sk != NULL) {
@@ -406,7 +499,7 @@
break;
case DM:
- ax25_clear_tx_queue(ax25);
+ ax25_clear_queues(ax25);
ax25->t3timer = 0;
ax25->state = AX25_STATE_0;
if (ax25->sk != NULL) {
@@ -518,7 +611,7 @@
if (pf) ax25_enquiry_response(ax25);
break;
}
- ax25->vr = (ax25->vr + 1) % MODULUS;
+ ax25->vr = (ax25->vr + 1) % ax25->modulus;
ax25->condition &= ~REJECT_CONDITION;
if (pf) {
ax25_enquiry_response(ax25);
@@ -533,7 +626,7 @@
if (pf) ax25_enquiry_response(ax25);
} else {
ax25->condition |= REJECT_CONDITION;
- ax25_send_control(ax25, REJ | pf, C_RESPONSE);
+ ax25_send_control(ax25, REJ, pf, C_RESPONSE);
ax25->condition &= ~ACK_PENDING_CONDITION;
}
}
@@ -557,7 +650,7 @@
*/
int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type)
{
- int queued = 0, frametype;
+ int queued = 0, frametype, ns, nr, pf;
if (ax25->state != AX25_STATE_1 && ax25->state != AX25_STATE_2 &&
ax25->state != AX25_STATE_3 && ax25->state != AX25_STATE_4) {
@@ -567,20 +660,20 @@
del_timer(&ax25->timer);
- frametype = ax25_decode(skb->data);
+ frametype = ax25_decode(ax25, skb, &ns, &nr, &pf);
switch (ax25->state) {
case AX25_STATE_1:
- queued = ax25_state1_machine(ax25, skb, frametype, type);
+ queued = ax25_state1_machine(ax25, skb, frametype, pf, type);
break;
case AX25_STATE_2:
- queued = ax25_state2_machine(ax25, skb, frametype, type);
+ queued = ax25_state2_machine(ax25, skb, frametype, pf, type);
break;
case AX25_STATE_3:
- queued = ax25_state3_machine(ax25, skb, frametype, type);
+ queued = ax25_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
break;
case AX25_STATE_4:
- queued = ax25_state4_machine(ax25, skb, frametype, type);
+ queued = ax25_state4_machine(ax25, skb, frametype, ns, nr, pf, type);
break;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this