patch-2.0.36 linux/net/rose/rose_in.c
Next file: linux/net/rose/rose_link.c
Previous file: linux/net/rose/changes.doc
Back to the patch index
Back to the overall index
- Lines: 253
- Date:
Sun Nov 15 10:33:22 1998
- Orig file:
v2.0.35/linux/net/rose/rose_in.c
- Orig date:
Sun Nov 15 10:50:02 1998
diff -u --recursive --new-file v2.0.35/linux/net/rose/rose_in.c linux/net/rose/rose_in.c
@@ -17,7 +17,6 @@
*
* History
* ROSE 001 Jonathan(G4KLX) Cloned from nr_in.c
- * ROSE 003 Jonathan(G4KLX) Removed M bit processing.
*/
#include <linux/config.h>
@@ -45,6 +44,45 @@
#include <linux/interrupt.h>
#include <net/rose.h>
+static int rose_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+{
+ struct sk_buff *skbo, *skbn = skb;
+
+ if (more) {
+ sk->protinfo.rose->fraglen += skb->len;
+ skb_queue_tail(&sk->protinfo.rose->frag_queue, skb);
+ return 0;
+ }
+
+ if (!more && sk->protinfo.rose->fraglen > 0) { /* End of fragment */
+ sk->protinfo.rose->fraglen += skb->len;
+ skb_queue_tail(&sk->protinfo.rose->frag_queue, skb);
+
+ if ((skbn = alloc_skb(sk->protinfo.rose->fraglen, GFP_ATOMIC)) == NULL)
+ return 1;
+
+ skbn->free = 1;
+ skbn->arp = 1;
+ skbn->sk = sk;
+ skbn->h.raw = skbn->data;
+
+ skbo = skb_dequeue(&sk->protinfo.rose->frag_queue);
+ memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+ kfree_skb(skbo, FREE_READ);
+
+ while ((skbo = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL) {
+ skb_pull(skbo, ROSE_MIN_LEN);
+ memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+ kfree_skb(skbo, FREE_READ);
+ }
+
+ sk->protinfo.rose->fraglen = 0;
+ }
+
+ /* printk("FBB : lg=%ld\n", skbn->len); */
+ return sock_queue_rcv_skb(sk, skbn);
+}
+
/*
* State machine for state 1, Awaiting Call Accepted State.
* The handling of the timer(s) is in file rose_timer.c.
@@ -52,6 +90,8 @@
*/
static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{
+ int len;
+
switch (frametype) {
case ROSE_CALL_ACCEPTED:
@@ -80,6 +120,18 @@
if (!sk->dead)
sk->state_change(sk);
sk->dead = 1;
+ len = 5; /* Minimum size of the frame data */
+ if (skb->len > len) {
+ /* Address block */
+ len += 1;
+ len += (((skb->data[5] >> 4) & 0x0F) + 1) / 2;
+ len += (((skb->data[5] >> 0) & 0x0F) + 1) / 2;
+
+ if (skb->len > len) {
+ /* Facilities */
+ rose_parse_facilities(skb->data + len, &sk->protinfo.rose->facilities);
+ }
+ }
break;
default:
@@ -96,12 +148,27 @@
*/
static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{
+ int len;
+
switch (frametype) {
case ROSE_CLEAR_REQUEST:
rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
sk->protinfo.rose->cause = skb->data[3];
sk->protinfo.rose->diagnostic = skb->data[4];
+ len = 5;
+ if (skb->len > len) {
+ /* Address block */
+ len += 1;
+ len += (((skb->data[5] >> 4) & 0x0F) + 1) / 2;
+ len += (((skb->data[5] >> 0) & 0x0F) + 1) / 2;
+
+ if (skb->len > len) {
+ /* Facilities */
+ rose_parse_facilities(skb->data + len, &sk->protinfo.rose->facilities);
+ }
+ }
+ /* fall in next case ... */
case ROSE_CLEAR_CONFIRMATION:
rose_clear_queues(sk);
sk->protinfo.rose->neighbour->use--;
@@ -129,6 +196,7 @@
static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m)
{
int queued = 0;
+ int len;
switch (frametype) {
@@ -155,14 +223,22 @@
if (!sk->dead)
sk->state_change(sk);
sk->dead = 1;
+ len = 5;
+ if (skb->len > len) {
+ /* Address block */
+ len += 1;
+ len += (((skb->data[5] >> 4) & 0x0F) + 1) / 2;
+ len += (((skb->data[5] >> 0) & 0x0F) + 1) / 2;
+
+ if (skb->len > len) {
+ /* Facilities */
+ rose_parse_facilities(skb->data + len, &sk->protinfo.rose->facilities);
+ }
+ }
break;
case ROSE_RR:
case ROSE_RNR:
- if (frametype == ROSE_RNR)
- sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY;
- else
- sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
if (!rose_validate_nr(sk, nr)) {
rose_clear_queues(sk);
rose_write_internal(sk, ROSE_RESET_REQUEST);
@@ -174,10 +250,12 @@
sk->protinfo.rose->state = ROSE_STATE_4;
sk->protinfo.rose->timer = sk->protinfo.rose->t2;
} else {
- if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
- sk->protinfo.rose->va = nr;
- } else {
- rose_check_iframes_acked(sk, nr);
+ rose_frames_acked(sk, nr);
+ /* F6FBB : only set the flag ! */
+ if (frametype == ROSE_RNR)
+ sk->protinfo.rose->condition |= ROSE_COND_PEER_RX_BUSY;
+ else {
+ sk->protinfo.rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
}
}
break;
@@ -196,18 +274,26 @@
sk->protinfo.rose->timer = sk->protinfo.rose->t2;
break;
}
- if (sk->protinfo.rose->condition & ROSE_COND_PEER_RX_BUSY) {
- sk->protinfo.rose->va = nr;
- } else {
- rose_check_iframes_acked(sk, nr);
- }
- if (sk->protinfo.rose->condition & ROSE_COND_OWN_RX_BUSY)
- break;
+ rose_frames_acked(sk, nr);
if (ns == sk->protinfo.rose->vr) {
- if (sock_queue_rcv_skb(sk, skb) == 0) {
+ if (rose_queue_rx_frame(sk, skb, m) == 0) {
sk->protinfo.rose->vr = (sk->protinfo.rose->vr + 1) % ROSE_MODULUS;
queued = 1;
} else {
+ /* should never happen ! */
+ rose_clear_queues(sk);
+ rose_write_internal(sk, ROSE_RESET_REQUEST);
+ sk->protinfo.rose->condition = 0x00;
+ sk->protinfo.rose->vs = 0;
+ sk->protinfo.rose->vr = 0;
+ sk->protinfo.rose->va = 0;
+ sk->protinfo.rose->vl = 0;
+ sk->protinfo.rose->state = ROSE_STATE_4;
+ sk->protinfo.rose->timer = sk->protinfo.rose->t2;
+ break;
+ }
+ /* F6FBB : check if room enough for a full window */
+ if (sk->rmem_alloc > (sk->rcvbuf - ROSE_MAX_WINDOW_LEN)) {
sk->protinfo.rose->condition |= ROSE_COND_OWN_RX_BUSY;
}
}
@@ -240,6 +326,8 @@
*/
static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{
+ int len;
+
switch (frametype) {
case ROSE_RESET_REQUEST:
@@ -268,6 +356,18 @@
if (!sk->dead)
sk->state_change(sk);
sk->dead = 1;
+ len = 5;
+ if (skb->len > len) {
+ /* Address block */
+ len += 1;
+ len += (((skb->data[5] >> 4) & 0x0F) + 1) / 2;
+ len += (((skb->data[5] >> 0) & 0x0F) + 1) / 2;
+
+ if (skb->len > len) {
+ /* Facilities */
+ rose_parse_facilities(skb->data + len, &sk->protinfo.rose->facilities);
+ }
+ }
break;
default:
@@ -284,6 +384,8 @@
*/
static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int frametype)
{
+ int len;
+
switch (frametype) {
case ROSE_CLEAR_REQUEST:
@@ -299,6 +401,18 @@
if (!sk->dead)
sk->state_change(sk);
sk->dead = 1;
+ len = 5;
+ if (skb->len > len) {
+ /* Address block */
+ len += 1;
+ len += (((skb->data[5] >> 4) & 0x0F) + 1) / 2;
+ len += (((skb->data[5] >> 0) & 0x0F) + 1) / 2;
+
+ if (skb->len > len) {
+ /* Facilities */
+ rose_parse_facilities(skb->data + len, &sk->protinfo.rose->facilities);
+ }
+ }
break;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov