patch-2.1.22 linux/net/ax25/af_ax25.c

Next file: linux/net/ax25/ax25_in.c
Previous file: linux/net/appletalk/ddp.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.21/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
@@ -90,6 +90,8 @@
  *						format.
  *			Hans(PE1AYX)		Fixed interface to IP layer.
  *			Alan(GW4PTS)		Added asynchronous support.
+ *			Frederic(F1OAT)		Support for pseudo-digipeating.
+ *			Jonathan(G4KLX)		Support for packet forwarding.
  *
  *	To do:
  *		Restructure the ax25_rcv code to be cleaner/faster and
@@ -136,7 +138,7 @@
  */
 ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}};
 
-ax25_cb *volatile ax25_list = NULL;
+ax25_cb *ax25_list = NULL;
 
 static struct proto_ops ax25_proto_ops;
 
@@ -228,6 +230,26 @@
 }
 
 /*
+ *	Compare two AX.25 digipeater paths.
+ */
+static int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2)
+{
+	int i;
+
+	if (digi1->ndigi != digi2->ndigi)
+		return 1;
+
+	if (digi1->lastrepeat != digi2->lastrepeat)
+		return 1;
+
+	for (i = 0; i < digi1->ndigi; i++)
+		if (ax25cmp(&digi1->calls[i], &digi2->calls[i]) != 0)
+			return 1;
+
+	return 0;
+}
+
+/*
  *	Free an allocated ax25 control block. This is done to centralise
  *	the MOD count code.
  */
@@ -343,7 +365,7 @@
  *	Find a socket that wants to accept the SABM we have just
  *	received.
  */
-static struct sock *ax25_find_listener(ax25_address *addr, struct device *dev, int type)
+static struct sock *ax25_find_listener(ax25_address *addr, int digi, struct device *dev, int type)
 {
 	unsigned long flags;
 	ax25_cb *s;
@@ -352,6 +374,8 @@
 	cli();
 
 	for (s = ax25_list; s != NULL; s = s->next) {
+		if ((s->iamdigi && !digi) || (!s->iamdigi && digi))
+			continue;
 		if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == type && s->sk->state == TCP_LISTEN) {
 			/* If device is null we match any device */
 			if (s->device == NULL || s->device == dev) {
@@ -393,7 +417,7 @@
  *	floating AX.25 control blocks or non Raw socket bound control blocks.
  */
 
-static ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, struct device *dev)
+static ax25_cb *ax25_find_cb(ax25_address *my_addr, ax25_address *dest_addr, ax25_digi *digi, struct device *dev)
 {
 	ax25_cb *s;
 	unsigned long flags;
@@ -405,6 +429,12 @@
 		if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET)
 			continue;
 		if (ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->device == dev) {
+			if (digi != NULL) {
+				if (s->digipeat == NULL && digi->ndigi != 0)
+					continue;
+				if (s->digipeat != NULL && ax25digicmp(s->digipeat, digi) != 0)
+					continue;
+			}
 			restore_flags(flags);
 			return s;
 		}
@@ -418,7 +448,6 @@
 /*
  *	Look for any matching address - RAW sockets can bind to arbitrary names
  */
-
 static struct sock *ax25_addr_match(ax25_address *addr)
 {
 	unsigned long flags;
@@ -615,13 +644,13 @@
 	if ((dev = ax25rtr_get_dev(&ax25_ctl.port_addr)) == NULL)
 		return -ENODEV;
 
-	if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, dev)) == NULL)
+	if ((ax25 = ax25_find_cb(&ax25_ctl.source_addr, &ax25_ctl.dest_addr, NULL, dev)) == NULL)
 		return -ENOTCONN;
 
 	switch (ax25_ctl.cmd) {
 		case AX25_KILL:
 			ax25_clear_queues(ax25);
-			ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
+			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 
 			ax25->state = AX25_STATE_0;
 			if (ax25->sk != NULL) {
@@ -638,7 +667,7 @@
 	  		break;
 
 	  	case AX25_WINDOW:
-	  		if (ax25->modulus == MODULUS) {
+	  		if (ax25->modulus == AX25_MODULUS) {
 	  			if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
 	  				return -EINVAL;
 	  		} else {
@@ -651,8 +680,8 @@
 	  	case AX25_T1:
   			if (ax25_ctl.arg < 1)
   				return -EINVAL;
-  			ax25->rtt = (ax25_ctl.arg * PR_SLOWHZ) / 2;
-  			ax25->t1 = ax25_ctl.arg * PR_SLOWHZ;
+  			ax25->rtt = (ax25_ctl.arg * AX25_SLOWHZ) / 2;
+  			ax25->t1 = ax25_ctl.arg * AX25_SLOWHZ;
   			save_flags(flags); cli();
   			if (ax25->t1timer > ax25->t1)
   				ax25->t1timer = ax25->t1;
@@ -663,7 +692,7 @@
 	  		if (ax25_ctl.arg < 1)
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
-	  		ax25->t2 = ax25_ctl.arg * PR_SLOWHZ;
+	  		ax25->t2 = ax25_ctl.arg * AX25_SLOWHZ;
 	  		if (ax25->t2timer > ax25->t2)
 	  			ax25->t2timer = ax25->t2;
 	  		restore_flags(flags);
@@ -680,7 +709,7 @@
 	  		if (ax25_ctl.arg < 0)
 	  			return -EINVAL;
 	  		save_flags(flags); cli();
-	  		ax25->t3 = ax25_ctl.arg * PR_SLOWHZ;
+	  		ax25->t3 = ax25_ctl.arg * AX25_SLOWHZ;
 	  		if (ax25->t3timer != 0)
 	  			ax25->t3timer = ax25->t3;
 	  		restore_flags(flags);
@@ -690,7 +719,7 @@
 	  		if (ax25_ctl.arg < 0)
 	  			return -EINVAL;
 			save_flags(flags); cli();
-	  		ax25->idle = ax25_ctl.arg * PR_SLOWHZ * 60;
+	  		ax25->idle = ax25_ctl.arg * AX25_SLOWHZ * 60;
 	  		if (ax25->idletimer != 0)
 	  			ax25->idletimer = ax25->idle;
 	  		restore_flags(flags);
@@ -750,10 +779,10 @@
 	ax25->idle    = AX25_DEF_IDLE;
 
 	if (AX25_DEF_AXDEFMODE) {
-		ax25->modulus = EMODULUS;
+		ax25->modulus = AX25_EMODULUS;
 		ax25->window  = AX25_DEF_EWINDOW;
 	} else {
-		ax25->modulus = MODULUS;
+		ax25->modulus = AX25_MODULUS;
 		ax25->window  = AX25_DEF_WINDOW;
 	}
 
@@ -802,10 +831,10 @@
 	ax25->idle     = ax25_dev_get_value(dev, AX25_VALUES_IDLE);
 
 	if (ax25_dev_get_value(dev, AX25_VALUES_AXDEFMODE)) {
-		ax25->modulus = EMODULUS;
+		ax25->modulus = AX25_EMODULUS;
 		ax25->window  = ax25_dev_get_value(dev, AX25_VALUES_EWINDOW);
 	} else {
-		ax25->modulus = MODULUS;
+		ax25->modulus = AX25_MODULUS;
 		ax25->window  = ax25_dev_get_value(dev, AX25_VALUES_WINDOW);
 	}
 
@@ -914,19 +943,13 @@
  *	Handling for system calls applied via the various interfaces to an
  *	AX25 socket object
  */
-static int ax25_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
-	return -EINVAL;
-}
 
 static int ax25_setsockopt(struct socket *sock, int level, int optname,
 	char *optval, int optlen)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	int err, opt;
 
-	sk = (struct sock *)sock->sk;
-
 	if (level != SOL_AX25)
 		return -EOPNOTSUPP;
 
@@ -940,7 +963,7 @@
 
 	switch (optname) {
 		case AX25_WINDOW:
-			if (sk->protinfo.ax25->modulus == MODULUS) {
+			if (sk->protinfo.ax25->modulus == AX25_MODULUS) {
 				if (opt < 1 || opt > 7)
 					return -EINVAL;
 			} else {
@@ -953,13 +976,13 @@
 		case AX25_T1:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.ax25->rtt = (opt * PR_SLOWHZ) / 2;
+			sk->protinfo.ax25->rtt = (opt * AX25_SLOWHZ) / 2;
 			return 0;
 
 		case AX25_T2:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.ax25->t2 = opt * PR_SLOWHZ;
+			sk->protinfo.ax25->t2 = opt * AX25_SLOWHZ;
 			return 0;
 
 		case AX25_N2:
@@ -971,13 +994,13 @@
 		case AX25_T3:
 			if (opt < 1)
 				return -EINVAL;
-			sk->protinfo.ax25->t3 = opt * PR_SLOWHZ;
+			sk->protinfo.ax25->t3 = opt * AX25_SLOWHZ;
 			return 0;
 
 		case AX25_IDLE:
 			if (opt < 0)
 				return -EINVAL;
-			sk->protinfo.ax25->idle = opt * PR_SLOWHZ * 60;
+			sk->protinfo.ax25->idle = opt * AX25_SLOWHZ * 60;
 			return 0;
 
 		case AX25_BACKOFF:
@@ -985,13 +1008,17 @@
 			return 0;
 
 		case AX25_EXTSEQ:
-			sk->protinfo.ax25->modulus = opt ? EMODULUS : MODULUS;
+			sk->protinfo.ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS;
 			return 0;
 
 		case AX25_HDRINCL:
 			sk->protinfo.ax25->hdrincl = opt ? 1 : 0;
 			return 0;
 
+		case AX25_IAMDIGI:
+			sk->protinfo.ax25->iamdigi = opt ? 1 : 0;
+			return 0;
+
 		case AX25_PACLEN:
 			if (opt < 16 || opt > 65535)
 				return -EINVAL;
@@ -1006,12 +1033,10 @@
 static int ax25_getsockopt(struct socket *sock, int level, int optname,
 	char *optval, int *optlen)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	int val = 0;
 	int err;
 
-	sk = (struct sock *)sock->sk;
-
 	if (level != SOL_AX25)
 		return -EOPNOTSUPP;
 
@@ -1021,11 +1046,11 @@
 			break;
 
 		case AX25_T1:
-			val = (sk->protinfo.ax25->t1 * 2) / PR_SLOWHZ;
+			val = (sk->protinfo.ax25->t1 * 2) / AX25_SLOWHZ;
 			break;
 
 		case AX25_T2:
-			val = sk->protinfo.ax25->t2 / PR_SLOWHZ;
+			val = sk->protinfo.ax25->t2 / AX25_SLOWHZ;
 			break;
 
 		case AX25_N2:
@@ -1033,11 +1058,11 @@
 			break;
 
 		case AX25_T3:
-			val = sk->protinfo.ax25->t3 / PR_SLOWHZ;
+			val = sk->protinfo.ax25->t3 / AX25_SLOWHZ;
 			break;
 
 		case AX25_IDLE:
-			val = sk->protinfo.ax25->idle / (PR_SLOWHZ * 60);
+			val = sk->protinfo.ax25->idle / (AX25_SLOWHZ * 60);
 			break;
 
 		case AX25_BACKOFF:
@@ -1045,13 +1070,17 @@
 			break;
 
 		case AX25_EXTSEQ:
-			val = (sk->protinfo.ax25->modulus == EMODULUS);
+			val = (sk->protinfo.ax25->modulus == AX25_EMODULUS);
 			break;
 
 		case AX25_HDRINCL:
 			val = sk->protinfo.ax25->hdrincl;
 			break;
 
+		case AX25_IAMDIGI:
+			val = sk->protinfo.ax25->iamdigi;
+			break;
+
 		case AX25_PACLEN:
 			val = sk->protinfo.ax25->paclen;
 			break;
@@ -1075,7 +1104,7 @@
 
 static int ax25_listen(struct socket *sock, int backlog)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 
 	if (sk->type == SOCK_SEQPACKET && sk->state != TCP_LISTEN) {
 		sk->max_ack_backlog = backlog;
@@ -1086,30 +1115,6 @@
 	return -EOPNOTSUPP;
 }
 
-static void def_callback1(struct sock *sk)
-{
-	if (!sk->dead)
-		wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
-	if (!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,1);
-	}
-}
-
-static void def_callback3(struct sock *sk, int len)
-{
-	if (!sk->dead)
-	{
-		wake_up_interruptible(sk->sleep);
-		sock_wake_async(sk->socket,2);
-	}
-}
-
 static int ax25_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
@@ -1131,13 +1136,23 @@
 				case AX25_P_ARP:
 				case AX25_P_IP:
 #endif
-#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
+#ifdef CONFIG_NETROM
 				case AX25_P_NETROM:
 #endif
-#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
+#ifdef CONFIG_ROSE
 				case AX25_P_ROSE:
 #endif
 					return -ESOCKTNOSUPPORT;
+#ifdef CONFIG_NETROM_MODULE
+				case AX25_P_NETROM:
+					if (ax25_protocol_is_registered(AX25_P_NETROM))
+						return -ESOCKTNOSUPPORT;
+#endif
+#ifdef CONFIG_ROSE_MODULE
+				case AX25_P_ROSE:
+					if (ax25_protocol_is_registered(AX25_P_ROSE))
+						return -ESOCKTNOSUPPORT;
+#endif
 				default:
 					break;
 			}
@@ -1156,33 +1171,12 @@
 		return -ENOMEM;
 	}
 
+	sock_init_data(sock,sk);
+	
 	sock->ops = &ax25_proto_ops;
 
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->back_log);
-
-	sk->socket        = sock;
-	sk->type          = sock->type;
 	sk->protocol      = protocol;
-	sk->next          = NULL;
-	sk->allocation	  = GFP_KERNEL;
-	sk->rcvbuf        = SK_RMEM_MAX;
-	sk->sndbuf        = SK_WMEM_MAX;
-	sk->state         = TCP_CLOSE;
-	sk->priority      = SOPRI_NORMAL;
 	sk->mtu           = AX25_MTU;	/* 256 */
-	sk->zapped        = 1;
-
-	sk->state_change = def_callback1;
-	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback3;
-	sk->error_report = def_callback1;
-
-	if (sock != NULL) {
-		sock->sk  = sk;
-		sk->sleep = &sock->wait;
-	}
 
 	ax25->sk          = sk;
 	sk->protinfo.ax25 = ax25;
@@ -1219,11 +1213,8 @@
 			return NULL;
 	}
 
-	skb_queue_head_init(&sk->receive_queue);
-	skb_queue_head_init(&sk->write_queue);
-	skb_queue_head_init(&sk->back_log);
-
-	sk->next        = NULL;
+	sock_init_data(NULL,sk);
+	
 	sk->priority    = osk->priority;
 	sk->protocol    = osk->protocol;
 	sk->rcvbuf      = osk->rcvbuf;
@@ -1234,14 +1225,10 @@
 	sk->sleep       = osk->sleep;
 	sk->zapped      = osk->zapped;
 
-	sk->state_change = def_callback1;
-	sk->data_ready   = def_callback2;
-	sk->write_space  = def_callback3;
-	sk->error_report = def_callback1;
-
 	ax25->modulus = osk->protinfo.ax25->modulus;
 	ax25->backoff = osk->protinfo.ax25->backoff;
 	ax25->hdrincl = osk->protinfo.ax25->hdrincl;
+	ax25->iamdigi = osk->protinfo.ax25->iamdigi;
 	ax25->rtt     = osk->protinfo.ax25->rtt;
 	ax25->t1      = osk->protinfo.ax25->t1;
 	ax25->t2      = osk->protinfo.ax25->t2;
@@ -1273,14 +1260,17 @@
 
 static int ax25_dup(struct socket *newsock, struct socket *oldsock)
 {
-	struct sock *sk = (struct sock *)oldsock->sk;
+	struct sock *sk = oldsock->sk;
+
+	if (sk == NULL || newsock == NULL)
+		return -EINVAL;
 
 	return ax25_create(newsock, sk->protocol);
 }
 
 static int ax25_release(struct socket *sock, struct socket *peer)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 
 	if (sk == NULL) return 0;
 
@@ -1295,7 +1285,7 @@
 				break;
 
 			case AX25_STATE_1:
-				ax25_send_control(sk->protinfo.ax25, DISC, POLLON, C_COMMAND);
+				ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 				sk->protinfo.ax25->state = AX25_STATE_0;
 				sk->state                = TCP_CLOSE;
 				sk->shutdown            |= SEND_SHUTDOWN;
@@ -1306,9 +1296,9 @@
 
 			case AX25_STATE_2:
 				if (sk->protinfo.ax25->dama_slave)
-					ax25_send_control(sk->protinfo.ax25, DISC, POLLON, C_COMMAND);
+					ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 				else
-					ax25_send_control(sk->protinfo.ax25, DM, POLLON, C_RESPONSE);
+					ax25_send_control(sk->protinfo.ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
 				sk->protinfo.ax25->state = AX25_STATE_0;
 				sk->state                = TCP_CLOSE;
 				sk->shutdown            |= SEND_SHUTDOWN;
@@ -1322,7 +1312,7 @@
 				ax25_clear_queues(sk->protinfo.ax25);
 				sk->protinfo.ax25->n2count = 0;
 				if (!sk->protinfo.ax25->dama_slave) {
-					ax25_send_control(sk->protinfo.ax25, DISC, POLLON, C_COMMAND);
+					ax25_send_control(sk->protinfo.ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 					sk->protinfo.ax25->t3timer = 0;
 				} else {
 					sk->protinfo.ax25->t3timer = sk->protinfo.ax25->t3;	/* DAMA slave timeout */
@@ -1358,24 +1348,23 @@
  *	digipeated via a local address as source. This is a hack until we add
  *	BSD 4.4 ADDIFADDR type support. It is however small and trivially backward
  *	compatible 8)
- *
- *	FIXME: Check family
  */
 static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
 	struct device *dev;
 	ax25_address *call;
 
-	sk = (struct sock *)sock->sk;
-
 	if (sk->zapped == 0)
 		return -EINVAL;
 
 	if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 		return -EINVAL;
 
+	if (addr->fsa_ax25.sax25_family != AF_AX25)
+		return -EINVAL;
+
 	call = ax25_findbyuid(current->euid);
 	if (call == NULL && ax25_uid_policy && !suser())
 		return -EACCES;
@@ -1424,14 +1413,12 @@
 }
 
 /*
- *	FIXME: nonblock behaviour looks like it may have a bug. Also check
- *	the family in the connect.
+ *	FIXME: nonblock behaviour looks like it may have a bug.
  */
- 
 static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
 	int addr_len, int flags)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr;
 	int err;
 
@@ -1454,6 +1441,9 @@
 	if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 		return -EINVAL;
 
+	if (addr->sax25_family != AF_AX25)
+		return -EINVAL;
+
 	/*
 	 *	Handle digi-peaters to be used.
 	 */
@@ -1470,15 +1460,19 @@
 				return -ENOBUFS;
 		}
 
-		sk->protinfo.ax25->digipeat->ndigi = addr->sax25_ndigis;
+		sk->protinfo.ax25->digipeat->ndigi      = addr->sax25_ndigis;
+		sk->protinfo.ax25->digipeat->lastrepeat = -1;
 
 		while (ct < addr->sax25_ndigis) {
-			sk->protinfo.ax25->digipeat->repeated[ct] = 0;
+			if ((fsa->fsa_digipeater[ct].ax25_call[6] & AX25_HBIT) && sk->protinfo.ax25->iamdigi) {
+				sk->protinfo.ax25->digipeat->repeated[ct] = 1;
+				sk->protinfo.ax25->digipeat->lastrepeat   = ct;
+			} else {
+				sk->protinfo.ax25->digipeat->repeated[ct] = 0;
+			}
 			sk->protinfo.ax25->digipeat->calls[ct]    = fsa->fsa_digipeater[ct];
 			ct++;
 		}
-
-		sk->protinfo.ax25->digipeat->lastrepeat = 0;
 	}
 
 	/*
@@ -1496,7 +1490,7 @@
 			return -EHOSTUNREACH;
 	}
 
-	if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &addr->sax25_call, sk->protinfo.ax25->device) != NULL)
+	if (sk->type == SOCK_SEQPACKET && ax25_find_cb(&sk->protinfo.ax25->source_addr, &addr->sax25_call, NULL, sk->protinfo.ax25->device) != NULL)
 		return -EADDRINUSE;			/* Already such a connection */
 
 	sk->protinfo.ax25->dest_addr = addr->sax25_call;
@@ -1560,12 +1554,13 @@
 	struct sock *newsk;
 	struct sk_buff *skb;
 
-	if (newsock->sk)
-		sk_free(newsock->sk);
+	if (newsock->sk != NULL)
+		ax25_destroy_socket(newsock->sk->protinfo.ax25);
 
 	newsock->sk = NULL;
 
-	sk = (struct sock *)sock->sk;
+	if ((sk = sock->sk) == NULL)
+		return -EINVAL;
 
 	if (sk->type != SOCK_SEQPACKET)
 		return -EOPNOTSUPP;
@@ -1582,7 +1577,7 @@
 		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
 			if (flags & O_NONBLOCK) {
 				sti();
-				return 0;
+				return -EWOULDBLOCK;
 			}
 			interruptible_sleep_on(sk->sleep);
 			if (current->signal & ~current->blocked) {
@@ -1609,11 +1604,9 @@
 	int *uaddr_len, int peer)
 {
 	struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr;
-	struct sock *sk;
+	struct sock *sk = sock->sk;
 	unsigned char ndigi, i;
 
-	sk = (struct sock *)sock->sk;
-
 	if (peer != 0) {
 		if (sk->state != TCP_ESTABLISHED)
 			return -ENOTCONN;
@@ -1649,9 +1642,10 @@
 	struct sock *make;
 	struct sock *sk;
 	int type = 0;
-	ax25_digi dp;
+	ax25_digi dp, reverse_dp;
 	ax25_cb *ax25;
 	ax25_address src, dest;
+	ax25_address *next_digi = NULL;
 	struct sock *raw;
 	int mine = 0;
 	int dama;
@@ -1682,6 +1676,7 @@
 	 *	Ours perhaps ?
 	 */
 	if (dp.lastrepeat + 1 < dp.ndigi) {		/* Not yet digipeated completely */
+		next_digi = &dp.calls[dp.lastrepeat + 1];
 		if (ax25cmp(&dp.calls[dp.lastrepeat + 1], dev_addr) == 0) {
 			struct device *dev_out = dev;
 
@@ -1713,7 +1708,7 @@
 				return 0;
 			}
 
-			build_ax25_addr(skb->data, &src, &dest, &dp, type, MODULUS);
+			build_ax25_addr(skb->data, &src, &dest, &dp, type, AX25_MODULUS);
 #ifdef CONFIG_FIREWALL
 			if (call_fw_firewall(PF_AX25, skb->dev, skb->data, NULL) != FW_ACCEPT) {
 				kfree_skb(skb, FREE_READ);
@@ -1724,11 +1719,9 @@
 			skb->dev = dev_out;
 			skb->priority = SOPRI_NORMAL;
 			ax25_queue_xmit(skb);
-		} else {
-			kfree_skb(skb, FREE_READ);
-		}
 
-		return 0;
+			return 0;
+		}
 	}
 
 	/*
@@ -1737,14 +1730,15 @@
 	skb_pull(skb, size_ax25_addr(&dp));
 
 	/* For our port addresses ? */
-	if (ax25cmp(&dest, dev_addr) == 0)
+	if (ax25cmp(&dest, dev_addr) == 0 && dp.lastrepeat + 1 == dp.ndigi)
 		mine = 1;
 
 	/* Also match on any registered callsign from L3/4 */
-	if (!mine && ax25_listen_mine(&dest, dev))
+	if (!mine && ax25_listen_mine(&dest, dev) && dp.lastrepeat + 1 == dp.ndigi)
 		mine = 1;
 
-	if ((*skb->data & ~0x10) == LAPB_UI) {	/* UI frame - bypass LAPB processing */
+	/* UI frame - bypass LAPB processing */
+	if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
 		skb->h.raw = skb->data + 2;		/* skip control and pid */
 
 		if ((raw = ax25_addr_match(&dest)) != NULL)
@@ -1786,8 +1780,8 @@
 						 *	Remove the control and PID.
 						 */
 						skb_pull(skb, 2);
-						skb_queue_tail(&sk->receive_queue, skb);
 						skb_set_owner_r(skb, sk);
+						skb_queue_tail(&sk->receive_queue, skb);
 						if (!sk->dead)
 							sk->data_ready(sk, skb->len);
 					}
@@ -1818,7 +1812,9 @@
 
 	/* AX.25 state 1-4 */
 
-	if ((ax25 = ax25_find_cb(&dest, &src, dev)) != NULL) {
+	ax25_digi_invert(&dp, &reverse_dp);
+
+	if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) {
 		/*
 		 *	Process the frame. If it is queued up internally it returns one otherwise we
 		 *	free it immediately. This routine itself wakes the user context layers so we
@@ -1834,12 +1830,12 @@
 
 	/* a) received not a SABM(E) */
 
-	if ((*skb->data & ~PF) != SABM && (*skb->data & ~PF) != SABME) {
+	if ((*skb->data & ~AX25_PF) != AX25_SABM && (*skb->data & ~AX25_PF) != AX25_SABME) {
 		/*
 		 *	Never reply to a DM. Also ignore any connects for
 		 *	addresses that are not our interfaces and not a socket.
 		 */
-		if ((*skb->data & ~PF) != DM && mine)
+		if ((*skb->data & ~AX25_PF) != AX25_DM && mine)
 			ax25_return_dm(dev, &src, &dest, &dp);
 
 		kfree_skb(skb, FREE_READ);
@@ -1848,7 +1844,12 @@
 
 	/* b) received SABM(E) */
 
-	if ((sk = ax25_find_listener(&dest, dev, SOCK_SEQPACKET)) != NULL) {
+	if (dp.lastrepeat + 1 == dp.ndigi)
+		sk = ax25_find_listener(&dest, 0, dev, SOCK_SEQPACKET);
+	else
+		sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET);
+
+	if (sk != NULL) {
 		if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, dev)) == NULL) {
 			if (mine)
 				ax25_return_dm(dev, &src, &dest, &dp);
@@ -1901,20 +1902,20 @@
 		}
 	} else {
 		/* Reverse the source SABM's path */
-		ax25_digi_invert(&dp, ax25->digipeat);
+		*ax25->digipeat = reverse_dp;
 	}
 
-	if ((*skb->data & ~PF) == SABME) {
-		ax25->modulus = EMODULUS;
+	if ((*skb->data & ~AX25_PF) == AX25_SABME) {
+		ax25->modulus = AX25_EMODULUS;
 		ax25->window  = ax25_dev_get_value(dev, AX25_VALUES_EWINDOW);
 	} else {
-		ax25->modulus = MODULUS;
+		ax25->modulus = AX25_MODULUS;
 		ax25->window  = ax25_dev_get_value(dev, AX25_VALUES_WINDOW);
 	}
 
 	ax25->device = dev;
 
-	ax25_send_control(ax25, UA, POLLON, C_RESPONSE);
+	ax25_send_control(ax25, AX25_UA, AX25_POLLON, AX25_RESPONSE);
 
 	if (dama) ax25_dama_on(ax25);	/* bke 951121 */
 
@@ -1957,7 +1958,7 @@
 static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 	struct scm_cookie *scm)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
 	int err;
 	struct sockaddr_ax25 sax;
@@ -1968,21 +1969,21 @@
 	ax25_digi dtmp;
 	int lv;
 	int addr_len = msg->msg_namelen;
-	
+
 	if (msg->msg_flags & ~MSG_DONTWAIT)
 		return -EINVAL;
 
 	if (sk->zapped)
 		return -EADDRNOTAVAIL;
-		
+
 	if (sk->shutdown & SEND_SHUTDOWN) {
 		send_sig(SIGPIPE, current, 0);
 		return -EPIPE;
 	}
-		
+
 	if (sk->protinfo.ax25->device == NULL)
 		return -ENETUNREACH;
-		
+
 	if (usax) {
 		if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
 			return -EINVAL;
@@ -2040,8 +2041,7 @@
 	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
-	skb->sk   = sk;
-	skb->arp  = 1;
+	skb->arp = 1;
 
 	skb_reserve(skb, size - len);
 
@@ -2078,7 +2078,7 @@
 		}
 
 		/* Build an AX.25 header */
-		asmptr += (lv = build_ax25_addr(asmptr, &sk->protinfo.ax25->source_addr, &sax.sax25_call, dp, C_COMMAND, MODULUS));
+		asmptr += (lv = build_ax25_addr(asmptr, &sk->protinfo.ax25->source_addr, &sax.sax25_call, dp, AX25_COMMAND, AX25_MODULUS));
 
 		if (sk->debug)
 			printk("Built header (%d bytes)\n",lv);
@@ -2088,7 +2088,7 @@
 		if (sk->debug)
 			printk("base=%p pos=%p\n", skb->data, asmptr);
 
-		*asmptr = LAPB_UI;
+		*asmptr = AX25_UI;
 
 		/* Datagram frames go straight out of the door as UI */
 		skb->dev      = sk->protinfo.ax25->device;
@@ -2104,7 +2104,7 @@
 static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags,
 	struct scm_cookie *scm)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
 	struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;
 	int copied, length;
 	struct sk_buff *skb;
@@ -2179,7 +2179,8 @@
 
 static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
-	struct sock *sk = (struct sock *)sock->sk;
+	struct sock *sk = sock->sk;
+	struct ax25_info_struct ax25_info;
 	int err;
 	long amount = 0;
 
@@ -2248,6 +2249,36 @@
 				return -EPERM;
 			return ax25_ctl_ioctl(cmd, (void *)arg);
 
+		case SIOCAX25GETINFO:
+			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(ax25_info))) != 0)
+				return err;
+			ax25_info.t1        = sk->protinfo.ax25->t1;
+			ax25_info.t2        = sk->protinfo.ax25->t2;
+			ax25_info.t3        = sk->protinfo.ax25->t3;
+			ax25_info.idle      = sk->protinfo.ax25->idle;
+			ax25_info.n2        = sk->protinfo.ax25->n2;
+			ax25_info.t1timer   = sk->protinfo.ax25->t1timer;
+			ax25_info.t2timer   = sk->protinfo.ax25->t2timer;
+			ax25_info.t3timer   = sk->protinfo.ax25->t3timer;
+			ax25_info.idletimer = sk->protinfo.ax25->idletimer;
+			ax25_info.n2count   = sk->protinfo.ax25->n2count;
+			ax25_info.state     = sk->protinfo.ax25->state;
+			ax25_info.rcv_q     = sk->rmem_alloc;
+			ax25_info.snd_q     = sk->wmem_alloc;
+			copy_to_user((void *)arg, &ax25_info, sizeof(ax25_info));
+			return 0;
+
+		case SIOCAX25ADDFWD:
+		case SIOCAX25DELFWD: {
+			struct ax25_fwd_struct ax25_fwd;
+			if (!suser())
+				return -EPERM;
+			if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(ax25_fwd))) != 0)
+				return err;
+			copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd));
+			return ax25_fwd_ioctl(cmd, &ax25_fwd);
+		}
+
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
 		case SIOCGIFDSTADDR:
@@ -2294,16 +2325,16 @@
 			ax2asc(&ax25->source_addr), devname,
 			ax25->state,
 			ax25->vs, ax25->vr, ax25->va,
-			ax25->t1timer / PR_SLOWHZ,
-			ax25->t1      / PR_SLOWHZ,
-			ax25->t2timer / PR_SLOWHZ,
-			ax25->t2      / PR_SLOWHZ,
-			ax25->t3timer / PR_SLOWHZ,
-			ax25->t3      / PR_SLOWHZ,
-			ax25->idletimer / (PR_SLOWHZ * 60),
-			ax25->idle      / (PR_SLOWHZ * 60),
+			ax25->t1timer / AX25_SLOWHZ,
+			ax25->t1      / AX25_SLOWHZ,
+			ax25->t2timer / AX25_SLOWHZ,
+			ax25->t2      / AX25_SLOWHZ,
+			ax25->t3timer / AX25_SLOWHZ,
+			ax25->t3      / AX25_SLOWHZ,
+			ax25->idletimer / (AX25_SLOWHZ * 60),
+			ax25->idle      / (AX25_SLOWHZ * 60),
 			ax25->n2count, ax25->n2,
-			ax25->rtt     / PR_SLOWHZ,
+			ax25->rtt     / AX25_SLOWHZ,
 			ax25->window,
 			ax25->paclen);
 
@@ -2360,7 +2391,7 @@
 	ax25_shutdown,
 	ax25_setsockopt,
 	ax25_getsockopt,
-	ax25_fcntl,
+	sock_no_fcntl,
 	ax25_sendmsg,
 	ax25_recvmsg
 };
@@ -2384,7 +2415,6 @@
 
 EXPORT_SYMBOL(ax25_encapsulate);
 EXPORT_SYMBOL(ax25_rebuild_header);
-#if defined(CONFIG_NETROM_MODULE) || defined(CONFIG_ROSE_MODULE)
 EXPORT_SYMBOL(ax25_findbyuid);
 EXPORT_SYMBOL(ax25_link_up);
 EXPORT_SYMBOL(ax25_linkfail_register);
@@ -2399,7 +2429,6 @@
 EXPORT_SYMBOL(ax2asc);
 EXPORT_SYMBOL(asc2ax);
 EXPORT_SYMBOL(null_ax25_address);
-#endif
 
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry proc_ax25_route = {
@@ -2440,7 +2469,8 @@
 }
 
 /*
- *	A small shim to dev_queue_xmit to add the KISS control byte.
+ *	A small shim to dev_queue_xmit to add the KISS control byte, and do
+ *	any packet forwarding in operation.
  */
 void ax25_queue_xmit(struct sk_buff *skb)
 {
@@ -2454,6 +2484,7 @@
 #endif
 
 	skb->protocol = htons(ETH_P_AX25);
+	skb->dev      = ax25_fwd_dev(skb->dev);
 
 	ptr = skb_push(skb, 1);
 	*ptr++ = 0;			/* KISS */
@@ -2482,9 +2513,9 @@
 	if (daddr != NULL)
 		memcpy(buff, daddr, dev->addr_len);	/* Address specified */
 
-  	buff[6] &= ~LAPB_C;
-  	buff[6] &= ~LAPB_E;
-  	buff[6] |= SSSID_SPARE;
+  	buff[6] &= ~AX25_CBIT;
+  	buff[6] &= ~AX25_EBIT;
+  	buff[6] |= AX25_SSSID_SPARE;
   	buff += AX25_ADDR_LEN;
 
   	if (saddr != NULL)
@@ -2492,19 +2523,18 @@
   	else
   		memcpy(buff, dev->dev_addr, dev->addr_len);
 
-  	buff[6] &= ~LAPB_C;
-  	buff[6] |= LAPB_E;
-  	buff[6] |= SSSID_SPARE;
+  	buff[6] &= ~AX25_CBIT;
+  	buff[6] |= AX25_EBIT;
+  	buff[6] |= AX25_SSSID_SPARE;
   	buff   += AX25_ADDR_LEN;
 
-  	*buff++ = LAPB_UI;	/* UI */
+  	*buff++ = AX25_UI;	/* UI */
 
   	/* Append a suitable AX.25 PID */
   	switch (type) {
   		case ETH_P_IP:
   			*buff++ = AX25_P_IP;
  			break;
-
   		case ETH_P_ARP:
   			*buff++ = AX25_P_ARP;
   			break;
@@ -2548,8 +2578,8 @@
 				return 1;
 			}
 
-			if (ourskb->sk != NULL)
-				skb_set_owner_w(ourskb, ourskb->sk);
+			if (skb->sk != NULL)
+				skb_set_owner_w(ourskb, skb->sk);
 
 			kfree_skb(skb, FREE_WRITE);
 
@@ -2561,13 +2591,13 @@
 		}
 	}
 
-  	bp[7]  &= ~LAPB_C;
-  	bp[7]  &= ~LAPB_E;
-  	bp[7]  |= SSSID_SPARE;
-
-  	bp[14] &= ~LAPB_C;
-  	bp[14] |= LAPB_E;
-  	bp[14] |= SSSID_SPARE;
+  	bp[7]  &= ~AX25_CBIT;
+  	bp[7]  &= ~AX25_EBIT;
+  	bp[7]  |= AX25_SSSID_SPARE;
+
+  	bp[14] &= ~AX25_CBIT;
+  	bp[14] |= AX25_EBIT;
+  	bp[14] |= AX25_SSSID_SPARE;
 
   	/*
   	 * dl1bke 960317: we use ax25_queue_xmit here to allow mode datagram

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