patch-1.3.14 linux/net/ax25/ax25_out.c
Next file: linux/net/ax25/ax25_route.c
Previous file: linux/net/ax25/ax25_in.c
Back to the patch index
Back to the overall index
- Lines: 192
- Date:
Thu Jul 27 19:36:17 1995
- Orig file:
v1.3.13/linux/net/ax25/ax25_out.c
- Orig date:
Fri Jul 7 08:54:56 1995
diff -u --recursive --new-file v1.3.13/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.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.
@@ -22,6 +22,8 @@
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* Jonathan(G4KLX) Only poll when window is full.
+ * AX.25 030 Jonathan(G4KLX) Added fragmentation to ax25_output.
+ * Added support for extended AX.25.
*/
#include <linux/config.h>
@@ -47,14 +49,67 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
-int ax25_output(ax25_cb *ax25, struct sk_buff *skb)
+/*
+ * All outgoing AX.25 I frames pass via this routine. Therefore this is
+ * where the fragmentation of frames takes place.
+ */
+void ax25_output(ax25_cb *ax25, struct sk_buff *skb)
{
- skb_queue_tail(&ax25->write_queue, skb); /* Throw it on the queue */
+ struct sk_buff *skbn;
+ unsigned char *p;
+ int err, frontlen, mtu, len, fragno, first = 1;
+
+ mtu = ax25->device->mtu;
+
+ if (skb->len > mtu) {
+ mtu -= 2; /* Allow for fragment control info */
+
+ fragno = skb->len / mtu;
+ if (skb->len % mtu == 0) fragno--;
+
+ frontlen = skb_headroom(skb); /* Address space + CTRL */
+
+ while (skb->len > 0) {
+ if (skb->sk != NULL) {
+ if ((skbn = sock_alloc_send_skb(skb->sk, mtu + 2 + frontlen, 0, &err)) == NULL)
+ return;
+ } else {
+ if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL)
+ return;
+ }
+
+ skbn->sk = skb->sk;
+ skbn->free = 1;
+ skbn->arp = 1;
+
+ skb_reserve(skbn, frontlen + 2);
+
+ len = (mtu > skb->len) ? skb->len : mtu;
+
+ memcpy(skb_put(skbn, len), skb->data, len);
+ skb_pull(skb, len);
+
+ p = skb_push(skbn, 2);
+
+ *p++ = AX25_P_SEGMENT;
+
+ *p = fragno--;
+ if (first) {
+ *p |= SEG_FIRST;
+ first = 0;
+ }
+
+ skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */
+ }
+
+ skb->free = 1;
+ kfree_skb(skb, FREE_WRITE);
+ } else {
+ skb_queue_tail(&ax25->write_queue, skb); /* Throw it on the queue */
+ }
if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4)
ax25_kick(ax25);
-
- return 0;
}
/*
@@ -67,13 +122,22 @@
if (skb == NULL)
return;
-
- frame = skb_push(skb, 1); /* KISS + header */
- *frame = I;
- *frame |= poll_bit;
- *frame |= (ax25->vr << 5);
- *frame |= (ax25->vs << 1);
+ if (ax25->modulus == MODULUS) {
+ frame = skb_push(skb, 1);
+
+ *frame = I;
+ *frame |= (poll_bit) ? PF : 0;
+ *frame |= (ax25->vr << 5);
+ *frame |= (ax25->vs << 1);
+ } else {
+ frame = skb_push(skb, 2);
+
+ frame[0] = I;
+ frame[0] |= (ax25->vs << 1);
+ frame[1] = (poll_bit) ? EPF : 0;
+ frame[1] |= (ax25->vr << 1);
+ }
ax25_transmit_buffer(ax25, skb, C_COMMAND);
}
@@ -87,7 +151,7 @@
del_timer(&ax25->timer);
start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs;
- end = (ax25->va + ax25->window) % MODULUS;
+ end = (ax25->va + ax25->window) % ax25->modulus;
if (!(ax25->condition & PEER_RX_BUSY_CONDITION) &&
start != end &&
@@ -111,7 +175,7 @@
return;
}
- next = (ax25->vs + 1) % MODULUS;
+ next = (ax25->vs + 1) % ax25->modulus;
#ifdef notdef
last = (next == end) || skb_peek(&ax25->write_queue) == NULL;
#else
@@ -120,7 +184,7 @@
/*
* Transmit the frame copy.
*/
- ax25_send_iframe(ax25, skbn, (last) ? PF : 0);
+ ax25_send_iframe(ax25, skbn, (last) ? POLLON : POLLOFF);
ax25->vs = next;
@@ -167,7 +231,7 @@
}
ptr = skb_push(skb, size_ax25_addr(ax25->digipeat));
- build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type);
+ build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
skb->arp = 1;
@@ -189,8 +253,12 @@
ax25->condition = 0x00;
ax25->n2count = 0;
- ax25_send_control(ax25, SABM | PF, C_COMMAND);
-
+ if (ax25->modulus == MODULUS) {
+ ax25_send_control(ax25, SABM, POLLON, C_COMMAND);
+ } else {
+ ax25_send_control(ax25, SABME, POLLON, C_COMMAND);
+ }
+
ax25->t3timer = 0;
ax25->t2timer = 0;
ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
@@ -199,9 +267,9 @@
void ax25_transmit_enquiry(ax25_cb *ax25)
{
if (ax25->condition & OWN_RX_BUSY_CONDITION)
- ax25_send_control(ax25, RNR | PF, C_COMMAND);
+ ax25_send_control(ax25, RNR, POLLON, C_COMMAND);
else
- ax25_send_control(ax25, RR | PF, C_COMMAND);
+ ax25_send_control(ax25, RR, POLLON, C_COMMAND);
ax25->condition &= ~ACK_PENDING_CONDITION;
@@ -211,9 +279,9 @@
void ax25_enquiry_response(ax25_cb *ax25)
{
if (ax25->condition & OWN_RX_BUSY_CONDITION)
- ax25_send_control(ax25, RNR | PF, C_RESPONSE);
+ ax25_send_control(ax25, RNR, POLLON, C_RESPONSE);
else
- ax25_send_control(ax25, RR | PF, C_RESPONSE);
+ ax25_send_control(ax25, RR, POLLON, C_RESPONSE);
ax25->condition &= ~ACK_PENDING_CONDITION;
}
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