patch-2.0.36 linux/net/rose/rose_subr.c

Next file: linux/net/rose/rose_timer.c
Previous file: linux/net/rose/rose_route.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.35/linux/net/rose/rose_subr.c linux/net/rose/rose_subr.c
@@ -46,6 +46,36 @@
 
 	while ((skb = skb_dequeue(&sk->write_queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
+
+	while ((skb = skb_dequeue(&sk->protinfo.rose->ack_queue)) != NULL)
+		kfree_skb(skb, FREE_WRITE);
+
+#ifdef M_BIT
+	while ((skb = skb_dequeue(&sk->protinfo.rose->frag_queue)) != NULL)
+		kfree_skb(skb, FREE_READ);
+#endif
+}
+
+/*
+ * 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 rose_frames_acked(struct sock *sk, unsigned short nr)
+{
+	struct sk_buff *skb;
+
+	/*
+	 * Remove all the ack-ed frames from the ack queue.
+	 */
+	if (sk->protinfo.rose->va != nr) {
+
+		while (skb_peek(&sk->protinfo.rose->ack_queue) != NULL && sk->protinfo.rose->va != nr) {
+			skb = skb_dequeue(&sk->protinfo.rose->ack_queue);
+			kfree_skb(skb, FREE_WRITE);
+			sk->protinfo.rose->va = (sk->protinfo.rose->va + 1) % ROSE_MODULUS;
+		}
+	}
 }
 
 /*
@@ -75,7 +105,7 @@
 	struct sk_buff *skb;
 	unsigned char  *dptr;
 	unsigned char  lci1, lci2;
-	char buffer[100];
+	char buffer[250];
 	int len, faclen = 0;
 
 	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
@@ -83,14 +113,32 @@
 	switch (frametype) {
 		case ROSE_CALL_REQUEST:
 			len   += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
+			/* facilities */
 			faclen = rose_create_facilities(buffer, sk->protinfo.rose);
 			len   += faclen;
 			break;
 		case ROSE_CALL_ACCEPTED:
-		case ROSE_CLEAR_REQUEST:
 		case ROSE_RESET_REQUEST:
 			len   += 2;
 			break;
+		case ROSE_CLEAR_REQUEST:
+			len   += 3;
+			/* facilities */
+			faclen = 3 + 2 + AX25_ADDR_LEN + 3 + ROSE_ADDR_LEN;
+			dptr = buffer;
+			*dptr++ = faclen-1;	/* Facilities length */
+			*dptr++ = 0;
+			*dptr++ = FAC_NATIONAL;
+			*dptr++ = FAC_NATIONAL_FAIL_CALL;
+			*dptr++ = AX25_ADDR_LEN;
+			memcpy(dptr, &rose_callsign, AX25_ADDR_LEN);
+			dptr += AX25_ADDR_LEN;
+			*dptr++ = FAC_NATIONAL_FAIL_ADD;
+			*dptr++ = ROSE_ADDR_LEN + 1;
+			*dptr++ = ROSE_ADDR_LEN * 2;
+			memcpy(dptr, &sk->protinfo.rose->source_addr, ROSE_ADDR_LEN);
+			len   += faclen;
+			break;
 	}
 
 	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
@@ -137,6 +185,9 @@
 			*dptr++ = frametype;
 			*dptr++ = sk->protinfo.rose->cause;
 			*dptr++ = sk->protinfo.rose->diagnostic;
+			*dptr++ = 0x00;		/* Address length */
+			memcpy(dptr, buffer, faclen);
+			dptr   += faclen;
 			break;
 
 		case ROSE_RESET_REQUEST:
@@ -144,7 +195,7 @@
 			*dptr++ = lci2;
 			*dptr++ = frametype;
 			*dptr++ = ROSE_DTE_ORIGINATED;
-			*dptr++ = 0;
+			*dptr++ = 0x00;		/* Address length */
 			break;
 
 		case ROSE_RR:
@@ -209,9 +260,11 @@
 	return ROSE_ILLEGAL;
 }
 
-static int rose_parse_national(unsigned char *p, struct rose_facilities *facilities, int len)
+static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *facilities, int len)
 {
-	unsigned char l, n = 0;
+	unsigned char *pt;
+	unsigned char l, lg, n = 0;
+	int fac_national_digis_received = 0;
 
 	do {
 		switch (*p & 0xC0) {
@@ -238,12 +291,33 @@
 			case 0xC0:
 				l = p[1];
 				if (*p == FAC_NATIONAL_DEST_DIGI) {
-					memcpy(&facilities->source_digi, p + 2, AX25_ADDR_LEN);
-					facilities->source_ndigis = 1;
+					if (!fac_national_digis_received) {
+						memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN);
+						facilities->source_ndigis = 1;
+					}
+				}
+				else if (*p == FAC_NATIONAL_SRC_DIGI) {
+					if (!fac_national_digis_received) {
+						memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
+						facilities->dest_ndigis = 1;
+					}
+				}
+				else if (*p == FAC_NATIONAL_FAIL_CALL) {
+					memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
+				}
+				else if (*p == FAC_NATIONAL_FAIL_ADD) {
+					memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
 				}
-				if (*p == FAC_NATIONAL_SRC_DIGI) {
-					memcpy(&facilities->dest_digi,   p + 2, AX25_ADDR_LEN);
-					facilities->dest_ndigis = 1;
+				else if (*p == FAC_NATIONAL_DIGIS) {
+					fac_national_digis_received = 1;
+					facilities->source_ndigis = 0;
+					facilities->dest_ndigis   = 0;
+					for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) {
+						if (pt[6] & AX25_HBIT)
+							memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN);
+						else
+							memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN);
+					}
 				}
 				p   += l + 2;
 				n   += l + 2;
@@ -255,7 +329,7 @@
 	return n;
 }
 
-static int rose_parse_ccitt(unsigned char *p, struct rose_facilities *facilities, int len)
+static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *facilities, int len)
 {
 	unsigned char l, n = 0;
 	char callsign[11];
@@ -288,7 +362,7 @@
 					callsign[l - 10] = '\0';
 					facilities->source_call = *asc2ax(callsign);
 				}
-				if (*p == FAC_CCITT_SRC_NSAP) {
+				else if (*p == FAC_CCITT_SRC_NSAP) {
 					memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN);
 					memcpy(callsign, p + 12, l - 10);
 					callsign[l - 10] = '\0';
@@ -304,17 +378,9 @@
 	return n;
 }
 
-int rose_parse_facilities(struct sk_buff *skb, struct rose_facilities *facilities)
+int rose_parse_facilities(unsigned char *p, struct rose_facilities_struct *facilities)
 {
 	int facilities_len, len;
-	unsigned char *p;
-
-	memset(facilities, 0x00, sizeof(struct rose_facilities));
-
-	len  = (((skb->data[3] >> 4) & 0x0F) + 1) / 2;
-	len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
-
-	p = skb->data + len + 4;
 
 	facilities_len = *p++;
 
@@ -327,25 +393,25 @@
 			p++;
 
 			switch (*p) {
-				case FAC_NATIONAL:		/* National */
+				case FAC_NATIONAL:		/* National 0x00 */
 					len = rose_parse_national(p + 1, facilities, facilities_len - 1);
 					facilities_len -= len + 1;
 					p += len + 1;
 					break;
 
-				case FAC_CCITT:		/* CCITT */
+				case FAC_CCITT:		/* CCITT 0x0F */
 					len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1);
 					facilities_len -= len + 1;
 					p += len + 1;
 					break;
 
 				default:
-					printk(KERN_DEBUG "rose_parse_facilities: unknown facilities family %02X\n", *p);
 					facilities_len--;
 					p++;
 					break;
 			}
-		}
+		} 
+		else break;	/* Error in facilities format */
 	}
 
 	return 1;
@@ -356,6 +422,7 @@
 	unsigned char *p = buffer + 1;
 	char *callsign;
 	int len;
+	int nb;
 
 	/* National Facilities */
 	if (rose->rand != 0 || rose->source_ndigis == 1 || rose->dest_ndigis == 1) {
@@ -368,19 +435,43 @@
 			*p++ = (rose->rand >> 0) & 0xFF;
 		}
 
-		if (rose->source_ndigis == 1) {
+		/* Sent before older facilities */
+		if ((rose->source_ndigis > 0) || (rose->dest_ndigis > 0)) {
+			int maxdigi = 0;
+			*p++ = FAC_NATIONAL_DIGIS;
+			*p++ = AX25_ADDR_LEN * (rose->source_ndigis + rose->dest_ndigis);
+			for (nb = 0 ; nb < rose->source_ndigis ; nb++) {
+				if (++maxdigi >= ROSE_MAX_DIGIS)
+					break;
+				memcpy(p, &rose->source_digis[nb], AX25_ADDR_LEN);
+				p[6] |= AX25_HBIT;
+				p += AX25_ADDR_LEN;
+			}
+			for (nb = 0 ; nb < rose->dest_ndigis ; nb++) {
+				if (++maxdigi >= ROSE_MAX_DIGIS)
+					break;
+				memcpy(p, &rose->dest_digis[nb], AX25_ADDR_LEN);
+				p[6] &= ~AX25_HBIT;
+				p += AX25_ADDR_LEN;
+			}
+		}
+
+		/* For compatibility */
+		if (rose->source_ndigis > 0) {
 			*p++ = FAC_NATIONAL_SRC_DIGI;
 			*p++ = AX25_ADDR_LEN;
-			memcpy(p, &rose->source_digi, AX25_ADDR_LEN);
+			memcpy(p, &rose->source_digis[0], AX25_ADDR_LEN);
 			p   += AX25_ADDR_LEN;
 		}
 
-		if (rose->dest_ndigis == 1) {
+		/* For compatibility */
+		if (rose->dest_ndigis > 0) {
 			*p++ = FAC_NATIONAL_DEST_DIGI;
 			*p++ = AX25_ADDR_LEN;
-			memcpy(p, &rose->dest_digi, AX25_ADDR_LEN);
+			memcpy(p, &rose->dest_digis[0], AX25_ADDR_LEN);
 			p   += AX25_ADDR_LEN;
 		}
+		
 	}
 
 	*p++ = 0x00;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov