patch-2.1.125 linux/net/rose/af_rose.c

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

diff -u --recursive --new-file v2.1.124/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
@@ -57,7 +57,7 @@
 #include <linux/if_arp.h>
 #include <linux/init.h>
 
-int rose_ndevs = 6;
+int rose_ndevs = 10;
 
 int sysctl_rose_restart_request_timeout = ROSE_DEFAULT_T0;
 int sysctl_rose_call_request_timeout    = ROSE_DEFAULT_T1;
@@ -524,7 +524,7 @@
 		sk->protinfo.rose->dest_ndigis = 0;
 		memset(&sk->protinfo.rose->dest_addr, '\0', ROSE_ADDR_LEN);
 		memset(&sk->protinfo.rose->dest_call, '\0', AX25_ADDR_LEN);
-		memset(&sk->protinfo.rose->dest_digi, '\0', AX25_ADDR_LEN);
+		memset(sk->protinfo.rose->dest_digis, '\0', AX25_ADDR_LEN*ROSE_MAX_DIGIS);
 		sk->max_ack_backlog = backlog;
 		sk->state           = TCP_LISTEN;
 		return 0;
@@ -549,6 +549,10 @@
 	sock_init_data(sock, sk);
 	
 	skb_queue_head_init(&rose->ack_queue);
+#ifdef M_BIT
+	skb_queue_head_init(&rose->frag_queue);
+	rose->fraglen    = 0;
+#endif
 
 	sock->ops    = &rose_proto_ops;
 	sk->protocol = protocol;
@@ -583,6 +587,10 @@
 	sock_init_data(NULL, sk);
 
 	skb_queue_head_init(&rose->ack_queue);
+#ifdef M_BIT
+	skb_queue_head_init(&rose->frag_queue);
+	rose->fraglen  = 0;
+#endif
 
 	sk->type     = osk->type;
 	sk->socket   = osk->socket;
@@ -662,16 +670,23 @@
 	struct sockaddr_rose *addr = (struct sockaddr_rose *)uaddr;
 	struct device *dev;
 	ax25_address *user, *source;
+	int n;
 
 	if (sk->zapped == 0)
 		return -EINVAL;
 
-	if (addr_len != sizeof(struct sockaddr_rose))
+	if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose))
 		return -EINVAL;
 
 	if (addr->srose_family != AF_ROSE)
 		return -EINVAL;
 
+	if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1)
+		return -EINVAL;
+
+	if (addr->srose_ndigis > ROSE_MAX_DIGIS)
+		return -EINVAL;
+
 	if ((dev = rose_dev_get(&addr->srose_addr)) == NULL) {
 		SOCK_DEBUG(sk, "ROSE: bind failed: invalid address\n");
 		return -EADDRNOTAVAIL;
@@ -685,13 +700,19 @@
 		user = source;
 	}
 
-	sk->protinfo.rose->source_addr = addr->srose_addr;
-	sk->protinfo.rose->source_call = *user;
-	sk->protinfo.rose->device      = dev;
-
-	if (addr->srose_ndigis == 1) {
-		sk->protinfo.rose->source_ndigis = 1;
-		sk->protinfo.rose->source_digi   = addr->srose_digi;
+	sk->protinfo.rose->source_addr   = addr->srose_addr;
+	sk->protinfo.rose->source_call   = *user;
+	sk->protinfo.rose->device        = dev;
+	sk->protinfo.rose->source_ndigis = addr->srose_ndigis;
+
+	if (addr_len == sizeof(struct full_sockaddr_rose)) {
+		struct full_sockaddr_rose *full_addr = (struct full_sockaddr_rose *)uaddr;
+		for (n = 0 ; n < addr->srose_ndigis ; n++)
+			sk->protinfo.rose->source_digis[n] = full_addr->srose_digis[n];
+	} else {
+		if (sk->protinfo.rose->source_ndigis == 1) {
+			sk->protinfo.rose->source_digis[0] = addr->srose_digi;
+		}
 	}
 
 	rose_insert_socket(sk);
@@ -708,6 +729,7 @@
 	unsigned char cause, diagnostic;
 	ax25_address *user;
 	struct device *dev;
+	int n;
 
 	if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
 		sock->state = SS_CONNECTED;
@@ -725,12 +747,22 @@
 	sk->state   = TCP_CLOSE;
 	sock->state = SS_UNCONNECTED;
 
-	if (addr_len != sizeof(struct sockaddr_rose))
+	if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose))
 		return -EINVAL;
 
 	if (addr->srose_family != AF_ROSE)
 		return -EINVAL;
 
+	if (addr_len == sizeof(struct sockaddr_rose) && addr->srose_ndigis > 1)
+		return -EINVAL;
+
+	if (addr->srose_ndigis > ROSE_MAX_DIGIS)
+		return -EINVAL;
+
+	/* Source + Destination digis should not exceed ROSE_MAX_DIGIS */
+	if ((sk->protinfo.rose->source_ndigis + addr->srose_ndigis) > ROSE_MAX_DIGIS)
+		return -EINVAL;
+
 	if ((sk->protinfo.rose->neighbour = rose_get_neigh(&addr->srose_addr, &cause, &diagnostic)) == NULL)
 		return -ENETUNREACH;
 
@@ -753,13 +785,19 @@
 		rose_insert_socket(sk);		/* Finish the bind */
 	}
 
-	sk->protinfo.rose->dest_addr = addr->srose_addr;
-	sk->protinfo.rose->dest_call = addr->srose_call;
-	sk->protinfo.rose->rand      = ((int)sk->protinfo.rose & 0xFFFF) + sk->protinfo.rose->lci;
-
-	if (addr->srose_ndigis == 1) {
-		sk->protinfo.rose->dest_ndigis = 1;
-		sk->protinfo.rose->dest_digi   = addr->srose_digi;
+	sk->protinfo.rose->dest_addr   = addr->srose_addr;
+	sk->protinfo.rose->dest_call   = addr->srose_call;
+	sk->protinfo.rose->rand        = ((int)sk->protinfo.rose & 0xFFFF) + sk->protinfo.rose->lci;
+	sk->protinfo.rose->dest_ndigis = addr->srose_ndigis;
+
+	if (addr_len == sizeof(struct full_sockaddr_rose)) {
+		struct full_sockaddr_rose *full_addr = (struct full_sockaddr_rose *)uaddr;
+		for (n = 0 ; n < addr->srose_ndigis ; n++)
+			sk->protinfo.rose->dest_digis[n] = full_addr->srose_digis[n];
+	} else {
+		if (sk->protinfo.rose->dest_ndigis == 1) {
+			sk->protinfo.rose->dest_digis[0] = addr->srose_digi;
+		}
 	}
 
 	/* Move to connecting socket, start sending Connect Requests */
@@ -863,6 +901,7 @@
 {
 	struct sockaddr_rose *srose = (struct sockaddr_rose *)uaddr;
 	struct sock *sk = sock->sk;
+	int n;
 
 	if (peer != 0) {
 		if (sk->state != TCP_ESTABLISHED)
@@ -871,21 +910,37 @@
 		srose->srose_ndigis = 0;
 		srose->srose_addr   = sk->protinfo.rose->dest_addr;
 		srose->srose_call   = sk->protinfo.rose->dest_call;
-		if (sk->protinfo.rose->dest_ndigis == 1) {
-			srose->srose_ndigis = 1;
-			srose->srose_digi   = sk->protinfo.rose->dest_digi;
+		srose->srose_ndigis = sk->protinfo.rose->dest_ndigis;
+		if (*uaddr_len >= sizeof(struct full_sockaddr_rose)) {
+			struct full_sockaddr_rose *full_srose = (struct full_sockaddr_rose *)uaddr;
+			for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++)
+				full_srose->srose_digis[n] = sk->protinfo.rose->dest_digis[n];
+			*uaddr_len = sizeof(struct full_sockaddr_rose);
+		} else {
+			if (sk->protinfo.rose->dest_ndigis >= 1) {
+				srose->srose_ndigis = 1;
+				srose->srose_digi = sk->protinfo.rose->dest_digis[0];
+			}
+			*uaddr_len = sizeof(struct sockaddr_rose);
 		}
-		*uaddr_len = sizeof(struct sockaddr_rose);
 	} else {
 		srose->srose_family = AF_ROSE;
 		srose->srose_ndigis = 0;
 		srose->srose_addr   = sk->protinfo.rose->source_addr;
 		srose->srose_call   = sk->protinfo.rose->source_call;
-		if (sk->protinfo.rose->source_ndigis == 1) {
-			srose->srose_ndigis = 1;
-			srose->srose_digi   = sk->protinfo.rose->source_digi;
+		srose->srose_ndigis = sk->protinfo.rose->source_ndigis;
+		if (*uaddr_len >= sizeof(struct full_sockaddr_rose)) {
+			struct full_sockaddr_rose *full_srose = (struct full_sockaddr_rose *)uaddr;
+			for (n = 0 ; n < sk->protinfo.rose->source_ndigis ; n++)
+				full_srose->srose_digis[n] = sk->protinfo.rose->source_digis[n];
+			*uaddr_len = sizeof(struct full_sockaddr_rose);
+		} else {
+			if (sk->protinfo.rose->source_ndigis >= 1) {
+				srose->srose_ndigis = 1;
+				srose->srose_digi = sk->protinfo.rose->source_digis[sk->protinfo.rose->source_ndigis-1];
+			}
+			*uaddr_len = sizeof(struct sockaddr_rose);
 		}
-		*uaddr_len = sizeof(struct sockaddr_rose);
 	}
 
 	return 0;
@@ -895,14 +950,19 @@
 {
 	struct sock *sk;
 	struct sock *make;
-	struct rose_facilities facilities;
+	struct rose_facilities_struct facilities;
+	int n, len;
 
 	skb->sk = NULL;		/* Initially we don't know who it's for */
 
 	/*
 	 *	skb->data points to the rose frame start
 	 */
-	if (!rose_parse_facilities(skb, &facilities)) {
+	memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
+	
+	len  = (((skb->data[3] >> 4) & 0x0F) + 1) / 2;
+	len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
+	if (!rose_parse_facilities(skb->data + len + 4, &facilities)) {
 		rose_transmit_clear_request(neigh, lci, ROSE_INVALID_FACILITY, 76);
 		return 0;
 	}
@@ -924,13 +984,16 @@
 	make->protinfo.rose->dest_addr     = facilities.dest_addr;
 	make->protinfo.rose->dest_call     = facilities.dest_call;
 	make->protinfo.rose->dest_ndigis   = facilities.dest_ndigis;
-	make->protinfo.rose->dest_digi     = facilities.dest_digi;
+	for (n = 0 ; n < facilities.dest_ndigis ; n++)
+		make->protinfo.rose->dest_digis[n] = facilities.dest_digis[n];
 	make->protinfo.rose->source_addr   = facilities.source_addr;
 	make->protinfo.rose->source_call   = facilities.source_call;
 	make->protinfo.rose->source_ndigis = facilities.source_ndigis;
-	make->protinfo.rose->source_digi   = facilities.source_digi;
+	for (n = 0 ; n < facilities.source_ndigis ; n++)
+		make->protinfo.rose->source_digis[n]= facilities.source_digis[n];
 	make->protinfo.rose->neighbour     = neigh;
 	make->protinfo.rose->device        = dev;
+	make->protinfo.rose->facilities    = facilities;
 
 	make->protinfo.rose->neighbour->use++;
 
@@ -968,10 +1031,10 @@
 	struct sock *sk = sock->sk;
 	struct sockaddr_rose *usrose = (struct sockaddr_rose *)msg->msg_name;
 	int err;
-	struct sockaddr_rose srose;
+	struct full_sockaddr_rose srose;
 	struct sk_buff *skb;
 	unsigned char *asmptr;
-	int size, qbit = 0;
+	int n, size, qbit = 0;
 
 	if (msg->msg_flags & ~MSG_DONTWAIT)
 		return -EINVAL;
@@ -988,15 +1051,19 @@
 		return -ENETUNREACH;
 
 	if (usrose != NULL) {
-		if (msg->msg_namelen < sizeof(srose))
+		if (msg->msg_namelen != sizeof(struct sockaddr_rose) && msg->msg_namelen != sizeof(struct full_sockaddr_rose))
 			return -EINVAL;
-		srose = *usrose;
+		memset(&srose, 0, sizeof(struct full_sockaddr_rose));
+		memcpy(&srose, usrose, msg->msg_namelen);
 		if (rosecmp(&sk->protinfo.rose->dest_addr, &srose.srose_addr) != 0 ||
 		    ax25cmp(&sk->protinfo.rose->dest_call, &srose.srose_call) != 0)
 			return -EISCONN;
-		if (srose.srose_ndigis == 1 && sk->protinfo.rose->dest_ndigis == 1) {
-			if (ax25cmp(&sk->protinfo.rose->dest_digi, &srose.srose_digi) != 0)
-				return -EISCONN;
+		if (srose.srose_ndigis != sk->protinfo.rose->dest_ndigis)
+			return -EISCONN;
+		if (srose.srose_ndigis == sk->protinfo.rose->dest_ndigis) {
+			for (n = 0 ; n < srose.srose_ndigis ; n++)
+				if (ax25cmp(&sk->protinfo.rose->dest_digis[n], &srose.srose_digis[n]) != 0)
+					return -EISCONN;
 		}
 		if (srose.srose_family != AF_ROSE)
 			return -EINVAL;
@@ -1007,12 +1074,9 @@
 		srose.srose_family = AF_ROSE;
 		srose.srose_addr   = sk->protinfo.rose->dest_addr;
 		srose.srose_call   = sk->protinfo.rose->dest_call;
-		srose.srose_ndigis = 0;
-
-		if (sk->protinfo.rose->dest_ndigis == 1) {
-			srose.srose_ndigis = 1;
-			srose.srose_digi   = sk->protinfo.rose->dest_digi;
-		}
+		srose.srose_ndigis = sk->protinfo.rose->dest_ndigis;
+		for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++)
+			srose.srose_digis[n] = sk->protinfo.rose->dest_digis[n];
 	}
 
 	SOCK_DEBUG(sk, "ROSE: sendto: Addresses built.\n");
@@ -1068,7 +1132,54 @@
 		return -ENOTCONN;
 	}
 
+#ifdef M_BIT
+#define ROSE_PACLEN (256-ROSE_MIN_LEN)
+	if (skb->len - ROSE_MIN_LEN > ROSE_PACLEN) {
+		unsigned char header[ROSE_MIN_LEN];
+		struct sk_buff *skbn;
+		int frontlen;
+		int lg;
+		
+		/* Save a copy of the Header */
+		memcpy(header, skb->data, ROSE_MIN_LEN);
+		skb_pull(skb, ROSE_MIN_LEN);
+
+		frontlen = skb_headroom(skb);
+
+		while (skb->len > 0) {
+			if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, 0, &err)) == NULL)
+				return err;
+
+			skbn->sk   = sk;
+			skbn->free = 1;
+			skbn->arp  = 1;
+
+			skb_reserve(skbn, frontlen);
+
+			lg = (ROSE_PACLEN > skb->len) ? skb->len : ROSE_PACLEN;
+
+			/* Copy the user data */
+			memcpy(skb_put(skbn, lg), skb->data, lg);
+			skb_pull(skb, lg);
+
+			/* Duplicate the Header */
+			skb_push(skbn, ROSE_MIN_LEN);
+			memcpy(skbn->data, header, ROSE_MIN_LEN);
+
+			if (skb->len > 0)
+				skbn->data[2] |= M_BIT;
+		
+			skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */
+		}
+		
+		skb->free = 1;
+		kfree_skb(skb, FREE_WRITE);
+	} else {
+		skb_queue_tail(&sk->write_queue, skb);		/* Throw it on the queue */
+	}
+#else
 	skb_queue_tail(&sk->write_queue, skb);	/* Shove it onto the queue */
+#endif
 
 	rose_kick(sk);
 
@@ -1084,7 +1195,7 @@
 	int copied, qbit;
 	unsigned char *asmptr;
 	struct sk_buff *skb;
-	int er;
+	int n, er;
 
 	/*
 	 * This works for seqpacket too. The receiver has ordered the queue for
@@ -1120,16 +1231,21 @@
 		srose->srose_family = AF_ROSE;
 		srose->srose_addr   = sk->protinfo.rose->dest_addr;
 		srose->srose_call   = sk->protinfo.rose->dest_call;
-		srose->srose_ndigis = 0;
-
-		if (sk->protinfo.rose->dest_ndigis == 1) {
-			srose->srose_ndigis = 1;
-			srose->srose_digi   = sk->protinfo.rose->dest_digi;
+		srose->srose_ndigis = sk->protinfo.rose->dest_ndigis;
+		if (msg->msg_namelen >= sizeof(struct full_sockaddr_rose)) {
+			struct full_sockaddr_rose *full_srose = (struct full_sockaddr_rose *)msg->msg_name;
+			for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++)
+				full_srose->srose_digis[n] = sk->protinfo.rose->dest_digis[n];
+			msg->msg_namelen = sizeof(struct full_sockaddr_rose);
+		} else {
+			if (sk->protinfo.rose->dest_ndigis >= 1) {
+				srose->srose_ndigis = 1;
+				srose->srose_digi = sk->protinfo.rose->dest_digis[0];
+			}
+			msg->msg_namelen = sizeof(struct sockaddr_rose);
 		}
 	}
 
-	msg->msg_namelen = sizeof(struct sockaddr_rose);
-
 	skb_free_datagram(sk, skb);
 
 	return copied;
@@ -1259,7 +1375,7 @@
 
 	cli();
 
-	len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q inode\n");
+	len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci neigh st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q inode\n");
 
 	for (s = rose_list; s != NULL; s = s->next) {
 		if ((dev = s->protinfo.rose->device) == NULL)
@@ -1276,11 +1392,12 @@
 		else
 			callsign = ax2asc(&s->protinfo.rose->source_call);
 
-		len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
+		len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %05d  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
 			rose2asc(&s->protinfo.rose->source_addr),
 			callsign,
 			devname, 
 			s->protinfo.rose->lci & 0x0FFF,
+			(s->protinfo.rose->neighbour) ? s->protinfo.rose->neighbour->number : 0,
 			s->protinfo.rose->state,
 			s->protinfo.rose->vs,
 			s->protinfo.rose->vr,
@@ -1399,7 +1516,7 @@
 
 	sock_register(&rose_family_ops);
 	register_netdevice_notifier(&rose_dev_notifier);
-	printk(KERN_INFO "G4KLX ROSE for Linux. Version 0.3 for AX25.037 Linux 2.1\n");
+	printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.037 Linux 2.1\n");
 
 	ax25_protocol_register(AX25_P_ROSE, rose_route_frame);
 	ax25_linkfail_register(rose_link_failed);

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