patch-1.3.14 linux/net/netrom/nr_in.c

Next file: linux/net/netrom/nr_out.c
Previous file: linux/net/netrom/nr_dev.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.13/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c
@@ -20,6 +20,7 @@
  *
  *	History
  *	NET/ROM 001	Jonathan(G4KLX)	Cloned from ax25_in.c
+ *	NET/ROM 003	Jonathan(G4KLX)	Added NET/ROM fragment reception.
  */
 
 #include <linux/config.h>
@@ -47,6 +48,40 @@
 #include <linux/interrupt.h>
 #include <net/netrom.h>
 
+static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+{
+	struct sk_buff *skbo, *skbn = skb;
+
+	if (more) {
+		sk->nr->fraglen += skb->len;
+		skb_queue_tail(&sk->nr->frag_queue, skb);
+		return 0;
+	}
+	
+	if (!more && sk->nr->fraglen > 0) {	/* End of fragment */
+		sk->nr->fraglen += skb->len;
+		skb_queue_tail(&sk->nr->frag_queue, skb);
+
+		if ((skbn = alloc_skb(sk->nr->fraglen, GFP_ATOMIC)) == NULL)
+			return 1;
+
+		skbn->free = 1;
+		skbn->arp  = 1;
+		skbn->sk   = sk;
+		sk->rmem_alloc += skb->truesize;
+			
+		while ((skbo = skb_dequeue(&sk->nr->frag_queue)) != NULL) {
+			memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+
+			kfree_skb(skbo, FREE_READ);
+		}
+
+		sk->nr->fraglen = 0;		
+	}
+
+	return sock_queue_rcv_skb(sk, skbn);
+}
+
 /*
  * State machine for state 1, Awaiting Connection State.
  * The handling of the timer(s) is in file nr_timer.c.
@@ -76,8 +111,8 @@
 				sk->state_change(sk);
 			break;
 
-		case NR_CONNACK + NR_CHOKE_FLAG:
-			nr_clear_tx_queue(sk);
+		case NR_CONNACK | NR_CHOKE_FLAG:
+			nr_clear_queues(sk);
 			sk->nr->state = NR_STATE_0;
 			sk->state     = TCP_CLOSE;
 			sk->err       = ECONNREFUSED;
@@ -153,7 +188,7 @@
 			break;
 
 		case NR_DISCREQ:
-			nr_clear_tx_queue(sk);
+			nr_clear_queues(sk);
 			nr_write_internal(sk, NR_DISCACK);
 			sk->nr->state = NR_STATE_0;
 			sk->state     = TCP_CLOSE;
@@ -164,7 +199,7 @@
 			break;
 
 		case NR_DISCACK:
-			nr_clear_tx_queue(sk);
+			nr_clear_queues(sk);
 			sk->nr->state = NR_STATE_0;
 			sk->state     = TCP_CLOSE;
 			sk->err       = ECONNRESET;
@@ -174,7 +209,7 @@
 			break;
 
 		case NR_INFOACK:
-		case NR_INFOACK + NR_CHOKE_FLAG:
+		case NR_INFOACK | NR_CHOKE_FLAG:
 			if (frametype & NR_CHOKE_FLAG) {
 				sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 				sk->nr->t4timer = nr_default.busy_delay;
@@ -194,8 +229,8 @@
 			}
 			break;
 			
-		case NR_INFOACK + NR_NAK_FLAG:
-		case NR_INFOACK + NR_NAK_FLAG + NR_CHOKE_FLAG:
+		case NR_INFOACK | NR_NAK_FLAG:
+		case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
 			if (frametype & NR_CHOKE_FLAG) {
 				sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 				sk->nr->t4timer = nr_default.busy_delay;
@@ -213,9 +248,9 @@
 			break;
 			
 		case NR_INFO:
-		case NR_INFO + NR_CHOKE_FLAG:
-		case NR_INFO + NR_MORE_FLAG:
-		case NR_INFO + NR_CHOKE_FLAG + NR_MORE_FLAG:
+		case NR_INFO | NR_CHOKE_FLAG:
+		case NR_INFO | NR_MORE_FLAG:
+		case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
 			if (frametype & NR_CHOKE_FLAG) {
 				sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 				sk->nr->t4timer = nr_default.busy_delay;
@@ -243,7 +278,7 @@
 				while ((skbn = skb_dequeue(&sk->nr->reseq_queue)) != NULL) {
 					ns = skbn->data[2];
 					if (ns == sk->nr->vr) {
-						if (sock_queue_rcv_skb(sk, skbn) == 0) {
+						if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
 							sk->nr->vr = (sk->nr->vr + 1) % NR_MODULUS;
 						} else {
 							sk->nr->condition |= OWN_RX_BUSY_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