patch-2.4.1 linux/net/decnet/af_decnet.c

Next file: linux/net/decnet/dn_dev.c
Previous file: linux/net/decnet/TODO
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
@@ -35,6 +35,7 @@
  *         Arnaldo C. Melo: use capable, not suser
  *        Steve Whitehouse: Removed unused code. Fix to use sk->allocation
  *                          when required.
+ *       Patrick Caulfield: /proc/net/decnet now has object name/number
  */
 
 
@@ -128,8 +129,6 @@
 #include <net/dn_fib.h>
 #include <net/dn_neigh.h>
 
-#define MAX(a,b) ((a)>(b)?(a):(b))
-
 static void dn_keepalive(struct sock *sk);
 
 /*
@@ -141,15 +140,15 @@
 
 static struct proto_ops dn_proto_ops;
 rwlock_t dn_hash_lock = RW_LOCK_UNLOCKED;
-static struct sock *dn_sklist = NULL;
-static struct sock *dn_wild_sk = NULL;
+static struct sock *dn_sklist;
+static struct sock *dn_wild_sk;
 
 static int __dn_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen, int flags);
 static int __dn_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen, int flags);
 
 static struct sock **dn_find_list(struct sock *sk)
 {
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 
 	if (scp->addr.sdn_flags & SDF_WILD)
 		return dn_wild_sk ? NULL : &dn_wild_sk;
@@ -159,7 +158,7 @@
 
 static unsigned short port_alloc(struct sock *sk)
 {
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 static unsigned short port = 0x2000;
 
 	if (port == 0)
@@ -177,12 +176,17 @@
  */
 static int dn_hash_sock(struct sock *sk)
 {
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 	struct sock **skp;
 	int rv = -EUSERS;
 
-	write_lock_bh(&dn_hash_lock);
+	if (sk->next)
+		BUG();
+	if (sk->pprev)
+		BUG();
 
+	write_lock_bh(&dn_hash_lock);
+	
 	if (!scp->addrloc && !port_alloc(sk))
 		goto out;
 
@@ -327,7 +331,7 @@
 
 	read_lock(&dn_hash_lock);
 	for(sk = dn_sklist; sk != NULL; sk = sk->next) {
-		struct dn_scp *scp = &sk->protinfo.dn;
+		struct dn_scp *scp = DN_SK(sk);
 		if (sk->state != TCP_LISTEN)
 			continue;
 		if (scp->addr.sdn_objnum) {
@@ -355,13 +359,13 @@
 
 struct sock *dn_find_by_skb(struct sk_buff *skb)
 {
-	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
+	struct dn_skb_cb *cb = DN_SKB_CB(skb);
 	struct sock *sk;
 	struct dn_scp *scp;
 
 	read_lock(&dn_hash_lock);
 	for(sk = dn_sklist; sk != NULL; sk = sk->next) {
-		scp = &sk->protinfo.dn;
+		scp = DN_SK(sk);
 		if (cb->src != dn_saddr2dn(&scp->peer))
 			continue;
 		if (cb->dst_port != scp->addrloc)
@@ -383,7 +387,7 @@
 
 static void dn_destruct(struct sock *sk)
 {
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 
 	skb_queue_purge(&scp->data_xmit_queue);
 	skb_queue_purge(&scp->other_xmit_queue);
@@ -394,25 +398,26 @@
 	MOD_DEC_USE_COUNT;
 }
 
-struct sock *dn_alloc_sock(struct socket *sock, int flags)
+struct sock *dn_alloc_sock(struct socket *sock, int gfp)
 {
 	struct sock *sk;
 	struct dn_scp *scp;
 
-	if  ((sk = sk_alloc(PF_DECnet, flags, 1)) == NULL) 
+	if  ((sk = sk_alloc(PF_DECnet, gfp, 1)) == NULL) 
 		goto no_sock;
 
 	if (sock) {
 			sock->ops = &dn_proto_ops;
 	}
 	sock_init_data(sock,sk);
-	scp = &sk->protinfo.dn;
+	scp = DN_SK(sk);
 
 	sk->backlog_rcv = dn_nsp_backlog_rcv;
 	sk->destruct    = dn_destruct;
 	sk->no_check    = 1;
 	sk->family      = PF_DECnet;
 	sk->protocol    = 0;
+	sk->allocation  = gfp;
 
 	/* Initialization of DECnet Session Control Port		*/
 	scp->state	= DN_O;		/* Open			*/
@@ -424,13 +429,25 @@
 	scp->ackrcv_oth = 0;		/* Last oth data ack rec*/
         scp->flowrem_sw = DN_SEND;
 	scp->flowloc_sw = DN_SEND;
+	scp->flowrem_dat = 0;
+	scp->flowrem_oth = 1;
+	scp->flowloc_dat = 0;
+	scp->flowloc_oth = 1;
+	scp->services_rem = 0;
+	scp->services_loc = 1 | NSP_FC_NONE;
+	scp->info_rem = 0;
+	scp->info_loc = 0x03; /* NSP version 4.1 */
+	scp->segsize_rem = 230; /* Default: Updated by remote segsize */
+	scp->segsize_loc = 1450; /* Best guess for ethernet */
+	scp->nonagle = 0;
+	scp->multi_ireq = 1;
 	scp->accept_mode = ACC_IMMED;
 	scp->addr.sdn_family    = AF_DECnet;
 	scp->peer.sdn_family    = AF_DECnet;
 	scp->accessdata.acc_accl = 5;
 	memcpy(scp->accessdata.acc_acc, "LINUX", 5);
-	scp->mss = 1460;
 
+	scp->max_window   = NSP_MAX_WINDOW;
 	scp->snd_window   = NSP_MIN_WINDOW;
 	scp->nsp_srtt     = NSP_INITIAL_SRTT;
 	scp->nsp_rttvar   = NSP_INITIAL_RTTVAR;
@@ -464,7 +481,7 @@
  */
 static void dn_keepalive(struct sock *sk)
 {
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 
 	/*
 	 * By checking the other_data transmit queue is empty
@@ -472,7 +489,7 @@
 	 * many of these keepalive frames.
 	 */
 	if (skb_queue_len(&scp->other_xmit_queue) == 0)
-		dn_nsp_send_lnk(sk, DN_NOCHANGE);
+		dn_nsp_send_link(sk, DN_NOCHANGE, 0);
 }
 
 
@@ -485,7 +502,7 @@
  */
 int dn_destroy_timer(struct sock *sk)
 {
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 
 	scp->persist = dn_nsp_persist(sk);
 
@@ -527,7 +544,7 @@
 
 static void dn_destroy_sock(struct sock *sk)
 {
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 
 	scp->nsp_rxtshift = 0; /* reset back off */
 
@@ -674,7 +691,7 @@
 static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
 	struct sock *sk = sock->sk;
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 	struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;
 	struct net_device *dev;
 	int rv;
@@ -722,11 +739,8 @@
 	memcpy(&scp->addr, saddr, addr_len);
 	sk->zapped = 0;
 
-	if ((rv = dn_hash_sock(sk)) == 0)
-		goto out;
-
-	sk->zapped = 1;
-out:
+	if ((rv = dn_hash_sock(sk)) != 0)
+		sk->zapped = 1;
 
         return rv;
 }
@@ -735,7 +749,7 @@
 static int dn_auto_bind(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 
 	sk->zapped = 0;
 
@@ -769,7 +783,7 @@
 {
 	struct sockaddr_dn *addr = (struct sockaddr_dn *)uaddr;
 	struct sock *sk = sock->sk;
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 	int err = -EISCONN;
 
 	lock_sock(sk);
@@ -788,7 +802,7 @@
 	}
 
 	err = -EINVAL;
-	if (sk->protinfo.dn.state != DN_O)
+	if (DN_SK(sk)->state != DN_O)
 		goto out;
 
 	if (addr_len != sizeof(struct sockaddr_dn))
@@ -812,7 +826,7 @@
 
 	sk->state   = TCP_SYN_SENT;
 	sock->state = SS_CONNECTING;
-	sk->protinfo.dn.state = DN_CI;
+	DN_SK(sk)->state = DN_CI;
 
 	dn_nsp_send_conninit(sk, NSP_CI);
 
@@ -853,7 +867,7 @@
         return err;
 }
 
-static int dn_access_copy(struct sk_buff *skb, struct accessdata_dn *acc)
+static void dn_access_copy(struct sk_buff *skb, struct accessdata_dn *acc)
 {
         unsigned char *ptr = skb->data;
 
@@ -870,10 +884,9 @@
 
         skb_pull(skb, acc->acc_accl + acc->acc_passl + acc->acc_userl + 3);
 
-	return 0;
 }
 
-static int dn_user_copy(struct sk_buff *skb, struct optdata_dn *opt)
+static void dn_user_copy(struct sk_buff *skb, struct optdata_dn *opt)
 {
         unsigned char *ptr = skb->data;
         
@@ -882,7 +895,6 @@
         memcpy(opt->opt_data, ptr, opt->opt_optl);
         skb_pull(skb, opt->opt_optl + 1);
 
-	return 0;
 }
 
 
@@ -910,7 +922,7 @@
                         return -ERESTARTSYS; /* But of course you don't! */
         }
 
-        if ((sk->protinfo.dn.state != DN_RUN) && (sk->protinfo.dn.state != DN_DRC)) {
+        if ((DN_SK(sk)->state != DN_RUN) && (DN_SK(sk)->state != DN_DRC)) {
                 sock->state = SS_UNCONNECTED;
                 return sock_error(sk);
         }
@@ -937,7 +949,7 @@
 		return -EINVAL;
 	}
 
-	if (sk->protinfo.dn.state != DN_O) {
+	if (DN_SK(sk)->state != DN_O) {
 		release_sock(sk);
 		return -EINVAL;
 	}
@@ -967,7 +979,7 @@
                 }
         } while (skb == NULL);
 
-	cb = (struct dn_skb_cb *)skb->cb;
+	cb = DN_SKB_CB(skb);
 
 	if ((newsk = dn_alloc_sock(newsock, sk->allocation)) == NULL) {
 		release_sock(sk);
@@ -980,50 +992,52 @@
 	dst_release(xchg(&newsk->dst_cache, skb->dst));
 	skb->dst = NULL;
 
-        newsk->protinfo.dn.state      = DN_CR;
-	newsk->protinfo.dn.addrrem    = cb->src_port;
-	newsk->protinfo.dn.mss        = cb->segsize;
-	newsk->protinfo.dn.accept_mode = sk->protinfo.dn.accept_mode;
+        DN_SK(newsk)->state        = DN_CR;
+	DN_SK(newsk)->addrrem      = cb->src_port;
+	DN_SK(newsk)->services_rem = cb->services;
+	DN_SK(newsk)->info_rem     = cb->info;
+	DN_SK(newsk)->segsize_rem  = cb->segsize;
+	DN_SK(newsk)->accept_mode  = DN_SK(sk)->accept_mode;
 	
-	if (newsk->protinfo.dn.mss < 230)
-		newsk->protinfo.dn.mss = 230;
+	if (DN_SK(newsk)->segsize_rem < 230)
+		DN_SK(newsk)->segsize_rem = 230;
 
 	newsk->state  = TCP_LISTEN;
 	newsk->zapped = 0;
 
-	memcpy(&newsk->protinfo.dn.addr, &sk->protinfo.dn.addr, sizeof(struct sockaddr_dn));
+	memcpy(&(DN_SK(newsk)->addr), &(DN_SK(sk)->addr), sizeof(struct sockaddr_dn));
 
 	/*
 	 * If we are listening on a wild socket, we don't want
 	 * the newly created socket on the wrong hash queue.
 	 */
-	newsk->protinfo.dn.addr.sdn_flags &= ~SDF_WILD;
+	DN_SK(newsk)->addr.sdn_flags &= ~SDF_WILD;
 
-	skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &newsk->protinfo.dn.addr, &type));
-	skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &newsk->protinfo.dn.peer, &type));
-	*(dn_address *)newsk->protinfo.dn.peer.sdn_add.a_addr = cb->src;
-	*(dn_address *)newsk->protinfo.dn.addr.sdn_add.a_addr = cb->dst;
+	skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->addr), &type));
+	skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &(DN_SK(newsk)->peer), &type));
+	*(dn_address *)(DN_SK(newsk)->peer.sdn_add.a_addr) = cb->src;
+	*(dn_address *)(DN_SK(newsk)->addr.sdn_add.a_addr) = cb->dst;
 
 	menuver = *skb->data;
 	skb_pull(skb, 1);
 
 	if (menuver & DN_MENUVER_ACC)
-		dn_access_copy(skb, &newsk->protinfo.dn.accessdata);
+		dn_access_copy(skb, &(DN_SK(newsk)->accessdata));
 
 	if (menuver & DN_MENUVER_USR)
-		dn_user_copy(skb, &newsk->protinfo.dn.conndata_in);
+		dn_user_copy(skb, &(DN_SK(newsk)->conndata_in));
 
 	if (menuver & DN_MENUVER_PRX)
-		newsk->protinfo.dn.peer.sdn_flags |= SDF_PROXY;
+		DN_SK(newsk)->peer.sdn_flags |= SDF_PROXY;
 
 	if (menuver & DN_MENUVER_UIC)
-		newsk->protinfo.dn.peer.sdn_flags |= SDF_UICPROXY;
+		DN_SK(newsk)->peer.sdn_flags |= SDF_UICPROXY;
 
 	kfree_skb(skb);
 
-	memcpy(&newsk->protinfo.dn.conndata_out, &sk->protinfo.dn.conndata_out,
+	memcpy(&(DN_SK(newsk)->conndata_out), &(DN_SK(sk)->conndata_out),
 		sizeof(struct optdata_dn));
-	memcpy(&newsk->protinfo.dn.discdata_out, &sk->protinfo.dn.discdata_out,
+	memcpy(&(DN_SK(newsk)->discdata_out), &(DN_SK(sk)->discdata_out),
 		sizeof(struct optdata_dn));
 
 	lock_sock(newsk);
@@ -1031,9 +1045,13 @@
 
 	dn_send_conn_ack(newsk);
 
-	if (newsk->protinfo.dn.accept_mode == ACC_IMMED) {
-		newsk->protinfo.dn.state = DN_CC;
-        	dn_send_conn_conf(newsk, newsk->allocation);
+	/*
+	 * Here we use sk->allocation since although the conn conf is
+	 * for the newsk, the context is the old socket.
+	 */
+	if (DN_SK(newsk)->accept_mode == ACC_IMMED) {
+		DN_SK(newsk)->state = DN_CC;
+        	dn_send_conn_conf(newsk, sk->allocation);
 		err = dn_wait_accept(newsock, flags);
 	}
 
@@ -1046,7 +1064,7 @@
 {
 	struct sockaddr_dn *sa = (struct sockaddr_dn *)uaddr;
 	struct sock *sk = sock->sk;
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 
 	*uaddr_len = sizeof(struct sockaddr_dn);
 
@@ -1070,7 +1088,7 @@
 static unsigned int dn_poll(struct file *file, struct socket *sock, poll_table  *wait)
 {
 	struct sock *sk = sock->sk;
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 	int mask = datagram_poll(file, sock, wait);
 
 	if (skb_queue_len(&scp->other_receive_queue))
@@ -1082,100 +1100,32 @@
 static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 	int err = -EOPNOTSUPP;
 	unsigned long amount = 0;
 	struct sk_buff *skb;
+	int val;
 
-#if 0
-	struct dn_naddr dnaddr;
-#endif
 	switch(cmd)
 	{
 	case SIOCGIFADDR:
 	case SIOCSIFADDR:
 		return dn_dev_ioctl(cmd, (void *)arg);
 
+	case SIOCATMARK:
+		lock_sock(sk);
+		val = (skb_queue_len(&scp->other_receive_queue) != 0);
+		if (scp->state != DN_RUN)
+			val = -ENOTCONN;
+		release_sock(sk);
+		return val;
+
 #ifdef CONFIG_DECNET_ROUTER
 	case SIOCADDRT:
 	case SIOCDELRT:
 		return dn_fib_ioctl(sock, cmd, arg);
 #endif /* CONFIG_DECNET_ROUTER */
 
-#if 0
-	case SIOCSIFADDR:
-		if (!capable(CAP_NET_ADMIN))    return -EPERM;
-
-		if ((err = copy_from_user(devname, ioarg->devname, 5)) != 0)
-			break;
-		if ((err = copy_from_user(addr, ioarg->exec_addr, 6)) != 0)
-			break;
-		if ((dev = dev_get(devname)) == NULL) {
-			err = -ENODEV;
-			break;
-		}
-		if (dev->dn_ptr == NULL) {
-			err = -ENODEV;
-			break;
-		}
-
-		dn_dev_devices_off();
-
-		decnet_default_device = dev;
-		memcpy(decnet_ether_address, addr, ETH_ALEN);
-		decnet_address = dn_htons(dn_eth2dn(decnet_ether_address));
-
-		dn_dev_devices_on();
-
-		break;
-
-	case SIOCGIFADDR:
-		if (decnet_default_device)
-			strcpy(devname, decnet_default_device->name);
-		else
-			memset(devname, 0, 6);
-
-		if ((err = copy_to_user(ioarg->devname, devname, 5)) != 0)
-			break;
-
-		if ((err = copy_to_user(ioarg->exec_addr, decnet_ether_address, 6)) != 0)
-			break;
-
-		break;
-#endif
-
-#if 0
-	case SIOCSNETADDR:
-		if (!capable(CAP_NET_ADMIN)) {
-			err = -EPERM;
-			break;
-		}
-
-		if ((err = copy_from_user(&dnaddr, (void *)arg, sizeof(struct dn_naddr))) != 0)
-			break;
-
-		if (dnaddr.a_len != ETH_ALEN) {
-			err = -EINVAL;
-			break;
-		}
-
-		dn_dev_devices_off();
-
-		memcpy(decnet_ether_address, dnaddr.a_addr, ETH_ALEN);
-		decnet_address = dn_htons(dn_eth2dn(decnet_ether_address));
-
-		dn_dev_devices_on();
-		break;
-
-	case SIOCGNETADDR:
-		dnaddr.a_len = ETH_ALEN;
-		memcpy(dnaddr.a_addr, decnet_ether_address, ETH_ALEN);
-
-		if ((err = copy_to_user((void *)arg, &dnaddr, sizeof(struct dn_naddr))) != 0)
-			break;
-
-		break;
-#endif
 	case OSIOCSNETADDR:
 		if (!capable(CAP_NET_ADMIN)) {
 			err = -EPERM;
@@ -1237,7 +1187,7 @@
 	if (sk->zapped)
 		goto out;
 
-	if ((sk->protinfo.dn.state != DN_O) || (sk->state == TCP_LISTEN))
+	if ((DN_SK(sk)->state != DN_O) || (sk->state == TCP_LISTEN))
 		goto out;
 
 	sk->max_ack_backlog = backlog;
@@ -1255,7 +1205,7 @@
 static int dn_shutdown(struct socket *sock, int how)
 {
 	struct sock *sk = sock->sk;
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 	int err = -ENOTCONN;
 
 	lock_sock(sk);
@@ -1300,14 +1250,27 @@
 static int __dn_setsockopt(struct socket *sock, int level,int optname, char *optval, int optlen, int flags) 
 {
 	struct	sock *sk = sock->sk;
-	struct dn_scp *scp = &sk->protinfo.dn;
-	struct optdata_dn opt;
-	struct accessdata_dn acc;
+	struct dn_scp *scp = DN_SK(sk);
+	union {
+		struct optdata_dn opt;
+		struct accessdata_dn acc;
+		int mode;
+		unsigned long win;
+		int val;
+		unsigned char services;
+		unsigned char info;
+	} u;
 	int err;
 
 	if (optlen && !optval)
 		return -EINVAL;
 
+	if (optlen > sizeof(u))
+		return -EINVAL;
+
+	if (copy_from_user(&u, optval, optlen))
+		return -EFAULT;
+
 	switch(optname) {
 		case DSO_CONDATA:
 			if (sock->state == SS_CONNECTED) 
@@ -1318,29 +1281,23 @@
 			if (optlen != sizeof(struct optdata_dn))
 				return -EINVAL;
 
-			if (copy_from_user(&opt, optval, optlen))
-				return -EFAULT;
-
-			if (opt.opt_optl > 16)
+			if (u.opt.opt_optl > 16)
 				return -EINVAL;
 
-			memcpy(&scp->conndata_out, &opt, sizeof(struct optdata_dn));
+			memcpy(&scp->conndata_out, &u.opt, optlen);
 			break;
 
 		case DSO_DISDATA:
-	   	        if (sock->state != SS_CONNECTED && sk->protinfo.dn.accept_mode == ACC_IMMED)
+	   	        if (sock->state != SS_CONNECTED && scp->accept_mode == ACC_IMMED)
 				return -ENOTCONN;
 
 			if (optlen != sizeof(struct optdata_dn))
 				return -EINVAL;
 
-			if (copy_from_user(&opt, optval, sizeof(struct optdata_dn)))
-				return -EFAULT;
-
-			if (opt.opt_optl > 16)
+			if (u.opt.opt_optl > 16)
 				return -EINVAL;
 
-			memcpy(&scp->discdata_out, &opt, sizeof(struct optdata_dn));
+			memcpy(&scp->discdata_out, &u.opt, optlen);
 			break;
 
 		case DSO_CONACCESS:
@@ -1352,15 +1309,12 @@
 			if (optlen != sizeof(struct accessdata_dn))
 				return -EINVAL;
 
-			if (copy_from_user(&acc, optval, sizeof(struct accessdata_dn)))
-				return -EFAULT;
-
-			if ((acc.acc_accl > DN_MAXACCL) ||
-					(acc.acc_passl > DN_MAXACCL) ||
-					(acc.acc_userl > DN_MAXACCL))
+			if ((u.acc.acc_accl > DN_MAXACCL) ||
+					(u.acc.acc_passl > DN_MAXACCL) ||
+					(u.acc.acc_userl > DN_MAXACCL))
 				return -EINVAL;
 
-			memcpy(&scp->accessdata, &acc, sizeof(struct accessdata_dn));
+			memcpy(&scp->accessdata, &u.acc, optlen);
 			break;
 
 		case DSO_ACCEPTMODE:
@@ -1372,16 +1326,10 @@
 			if (optlen != sizeof(int))
 				return -EINVAL;
 
-			{
-				int mode;
-
-				if (get_user(mode, optval))
-					return -EFAULT;
-				if ((mode != ACC_IMMED) && (mode != ACC_DEFER))
-					return -EINVAL;
+			if ((u.mode != ACC_IMMED) && (u.mode != ACC_DEFER))
+				return -EINVAL;
 
-				scp->accept_mode = (unsigned char)mode;
-			}
+			scp->accept_mode = (unsigned char)u.mode;
 			break;
 
 		case DSO_CONACCEPT:
@@ -1411,8 +1359,55 @@
 		case DSO_LINKINFO:
 		case DSO_STREAM:
 		case DSO_SEQPACKET:
-
 			return -ENOPROTOOPT;
+
+		case DSO_MAXWINDOW:
+			if (optlen != sizeof(unsigned long))
+				return -EINVAL;
+			if (u.win > NSP_MAX_WINDOW)
+				u.win = NSP_MAX_WINDOW;
+			if (u.win == 0)
+				return -EINVAL;
+			scp->max_window = u.win;
+			if (scp->snd_window > u.win)
+				scp->snd_window = u.win;
+			break;
+
+		case DSO_NODELAY:
+			if (optlen != sizeof(int))
+				return -EINVAL;
+			if (scp->nonagle == 2)
+				return -EINVAL;
+			scp->nonagle = (u.val == 0) ? 0 : 1;
+			/* if (scp->nonagle == 1) { Push pending frames } */
+			break;
+
+		case DSO_CORK:
+			if (optlen != sizeof(int))
+				return -EINVAL;
+			if (scp->nonagle == 1)
+				return -EINVAL;
+			scp->nonagle = (u.val == 0) ? 0 : 2;
+			/* if (scp->nonagle == 0) { Push pending frames } */
+			break;
+
+		case DSO_SERVICES:
+			if (optlen != sizeof(unsigned char))
+				return -EINVAL;
+			if ((u.services & ~NSP_FC_MASK) != 0x01)
+				return -EINVAL;
+			if ((u.services & NSP_FC_MASK) == NSP_FC_MASK)
+				return -EINVAL;
+			scp->services_loc = u.services;
+			break;
+
+		case DSO_INFO:
+			if (optlen != sizeof(unsigned char))
+				return -EINVAL;
+			if (u.info & 0xfc)
+				return -EINVAL;
+			scp->info_loc = u.info;
+			break;
 	}
 
 	return 0;
@@ -1433,44 +1428,40 @@
 static int __dn_getsockopt(struct socket *sock, int level,int optname, char *optval,int *optlen, int flags)
 {
 	struct	sock *sk = sock->sk;
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 	struct linkinfo_dn link;
-	int mode = scp->accept_mode;
+	int r_len = *optlen;
+	void *r_data = NULL;
+	int val;
 
 	switch(optname) {
 		case DSO_CONDATA:
-			if (*optlen != sizeof(struct optdata_dn))
-				return -EINVAL;
-
-			if (copy_to_user(optval, &scp->conndata_in, sizeof(struct optdata_dn)))
-				return -EFAULT;
+			if (r_len > sizeof(struct optdata_dn))
+				r_len = sizeof(struct optdata_dn);
+			r_data = &scp->conndata_in;
 			break;
 
 		case DSO_DISDATA:
-			if (*optlen != sizeof(struct optdata_dn))
-				return -EINVAL;
-
-			if (copy_to_user(optval, &scp->discdata_in, sizeof(struct optdata_dn)))
-				return -EFAULT;
-
+			if (r_len > sizeof(struct optdata_dn))
+				r_len = sizeof(struct optdata_dn);
+			r_data = &scp->discdata_in;
 			break;
 
 		case DSO_CONACCESS:
-			if (*optlen != sizeof(struct accessdata_dn))
-				return -EINVAL;
-
-			if (copy_to_user(optval, &scp->accessdata, sizeof(struct accessdata_dn)))
-				return -EFAULT;
+			if (r_len > sizeof(struct accessdata_dn))
+				r_len = sizeof(struct accessdata_dn);
+			r_data = &scp->accessdata;
 			break;
 
 		case DSO_ACCEPTMODE:
-			if (put_user(mode, optval))
-				return -EFAULT;
+			if (r_len > sizeof(unsigned char))
+				r_len = sizeof(unsigned char);
+			r_data = &scp->accept_mode;
 			break;
 
 		case DSO_LINKINFO:
-			if (*optlen != sizeof(struct linkinfo_dn))
-				return -EINVAL;
+			if (r_len > sizeof(struct linkinfo_dn))
+				r_len = sizeof(struct linkinfo_dn);
 
 			switch(sock->state) {
 				case SS_CONNECTING:
@@ -1486,10 +1477,8 @@
 					link.idn_linkstate = LL_INACTIVE;
 			}
 
-			link.idn_segsize = scp->mss;
-
-			if (copy_to_user(optval, &link, sizeof(struct linkinfo_dn)))
-				return -EFAULT;
+			link.idn_segsize = scp->segsize_rem;
+			r_data = &link;
 			break;
 
 		default:
@@ -1508,6 +1497,45 @@
 		case DSO_CONACCEPT:
 		case DSO_CONREJECT:
         		return -ENOPROTOOPT;
+
+		case DSO_MAXWINDOW:
+			if (r_len > sizeof(unsigned long))
+				r_len = sizeof(unsigned long);
+			r_data = &scp->max_window;
+			break;
+
+		case DSO_NODELAY:
+			if (r_len > sizeof(int))
+				r_len = sizeof(int);
+			val = (scp->nonagle == 1);
+			r_data = &val;
+			break;
+
+		case DSO_CORK:
+			if (r_len > sizeof(int))
+				r_len = sizeof(int);
+			val = (scp->nonagle == 2);
+			r_data = &val;
+			break;
+
+		case DSO_SERVICES:
+			if (r_len > sizeof(unsigned char))
+				r_len = sizeof(unsigned char);
+			r_data = &scp->services_rem;
+			break;
+
+		case DSO_INFO:
+			if (r_len > sizeof(unsigned char))
+				r_len = sizeof(unsigned char);
+			r_data = &scp->info_rem;
+			break;
+	}
+
+	if (r_data) {
+		if (copy_to_user(optval, r_data, r_len))
+			return -EFAULT;
+		if (put_user(r_len, optlen))
+			return -EFAULT;
 	}
 
 	return 0;
@@ -1520,7 +1548,7 @@
  */
 static int dn_wait_run(struct sock *sk, int flags)
 {
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 	int err = 0;
 
 	switch(scp->state) {
@@ -1572,7 +1600,7 @@
 		return skb_queue_len(q) ? 1 : 0;
 
 	while(skb != (struct sk_buff *)q) {
-		struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
+		struct dn_skb_cb *cb = DN_SKB_CB(skb);
 		len += skb->len;
 
 		if (cb->nsp_flags & 0x40) {
@@ -1599,7 +1627,7 @@
 	int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
-	struct dn_scp *scp = &sk->protinfo.dn;
+	struct dn_scp *scp = DN_SK(sk);
 	struct sk_buff_head *queue = &sk->receive_queue;
 	int target = size > 1 ? 1 : 0;
 	int copied = 0;
@@ -1681,7 +1709,7 @@
 
 	for(skb = queue->next; skb != (struct sk_buff *)queue; skb = nskb) {
 		int chunk = skb->len;
-		cb = (struct dn_skb_cb *)skb->cb;
+		cb = DN_SKB_CB(skb);
 
 		if ((chunk + copied) > size)
 			chunk = size - copied;
@@ -1693,7 +1721,7 @@
 		copied += chunk;
 
 		if (!(flags & MSG_PEEK))
-			skb->len -= chunk;
+			skb_pull(skb, chunk);
 
 		eor = cb->nsp_flags & 0x40;
 		nskb = skb->next;
@@ -1707,7 +1735,7 @@
 			 */
 			if ((scp->flowloc_sw == DN_DONTSEND) && !dn_congested(sk)) {
 				scp->flowloc_sw = DN_SEND;
-				dn_nsp_send_lnk(sk, DN_SEND);
+				dn_nsp_send_link(sk, DN_SEND, 0);
 			}
 		}
 
@@ -1727,6 +1755,7 @@
 
 	rv = copied;
 
+
 	if (eor && (sk->type == SOCK_SEQPACKET))
 		msg->msg_flags |= MSG_EOR;
 
@@ -1745,16 +1774,31 @@
 }
 
 
+static inline int dn_queue_too_long(struct dn_scp *scp, struct sk_buff_head *queue, int flags)
+{
+	unsigned char fctype = scp->services_rem & NSP_FC_MASK;
+	if (skb_queue_len(queue) >= scp->snd_window)
+		return 1;
+	if (fctype != NSP_FC_NONE) {
+		if (flags & MSG_OOB) {
+			if (scp->flowrem_oth == 0)
+				return 1;
+		} else {
+			if (scp->flowrem_dat == 0)
+				return 1;
+		}
+	}
+	return 0;
+}
+
 static int dn_sendmsg(struct socket *sock, struct msghdr *msg, int size, 
 	   struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
-	struct dn_scp *scp = &sk->protinfo.dn;
-	int mss = scp->mss;
-	int mtu = 230 - 11; /* maximum value thats always safe */
+	struct dn_scp *scp = DN_SK(sk);
+	int mss;
 	struct sk_buff_head *queue = &scp->data_xmit_queue;
 	int flags = msg->msg_flags;
-	unsigned short numseg = 0;
 	int err = 0;
 	int sent = 0;
 	int addr_len = msg->msg_namelen;
@@ -1765,6 +1809,7 @@
 	unsigned char *ptr;
 	unsigned short ack;
 	int len;
+	unsigned char fctype;
 
 	if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR))
 		return -EOPNOTSUPP;
@@ -1801,16 +1846,19 @@
 	if ((flags & MSG_TRYHARD) && sk->dst_cache)
 		dst_negative_advice(&sk->dst_cache);
 
+	mss = scp->segsize_rem;
+	fctype = scp->services_rem & NSP_FC_MASK;
+
 	if (sk->dst_cache && sk->dst_cache->neighbour) {
 		struct dn_neigh *dn = (struct dn_neigh *)sk->dst_cache->neighbour;
-		if (dn->blksize > 230)
-			mtu = dn->blksize - 11;
+		if (dn->blksize < (mss + 11))
+			mss = dn->blksize - 11;
 	}
 
 	/*
 	 * The only difference between SEQPACKET & STREAM sockets under DECnet
-	 * AFAIK is that SEQPACKET sockets set the MSG_EOR flag for the last
-	 * session control message segment.
+	 * is that SEQPACKET sockets set the MSG_EOR flag for the last
+	 * session control message segment. 
 	 */
 
 	if (flags & MSG_OOB) {
@@ -1822,9 +1870,6 @@
 		}
 	}
 
-	if (mss < mtu)
-		mtu = mss;
-
 	scp->persist_fxn = dn_nsp_xmit_timeout;
 
 	while(sent < size) {
@@ -1842,14 +1887,14 @@
 		 */
 		len = size - sent;
 
-		if (len > mtu)
-			len = mtu;
+		if (len > mss)
+			len = mss;
 
 		/*
 		 * Wait for queue size to go down below the window
 		 * size.
 		 */
-		if (skb_queue_len(queue) >= scp->snd_window) {
+		if (dn_queue_too_long(scp, queue, flags)) {
 			if (flags & MSG_DONTWAIT) {
 				err = -EWOULDBLOCK;
 				goto out;
@@ -1857,7 +1902,7 @@
 
 			SOCK_SLEEP_PRE(sk)
 
-			if (skb_queue_len(queue) >= scp->snd_window)
+			if (dn_queue_too_long(scp, queue, flags))
 				schedule();
 
 			SOCK_SLEEP_POST(sk)
@@ -1876,7 +1921,7 @@
 		if (!skb)
 			continue;
 
-		cb = (struct dn_skb_cb *)skb->cb;
+		cb = DN_SKB_CB(skb);
 
 		ptr = skb_put(skb, 9);
 
@@ -1886,26 +1931,34 @@
 		}
 
 		if (flags & MSG_OOB) {
-			cb->segnum = scp->numoth++;
-			scp->numoth &= 0x0fff;
+			cb->segnum = scp->numoth;
+			seq_add(&scp->numoth, 1);
 			msgflg = 0x30;
-			ack = scp->ackxmt_oth | 0x8000;
+			ack = (scp->numoth_rcv & 0x0FFF) | 0x8000;
+			scp->ackxmt_oth = scp->numoth_rcv;
+			if (fctype != NSP_FC_NONE)
+				scp->flowrem_oth--;
 		} else {
-			cb->segnum = scp->numdat++;
-			scp->numdat &= 0x0fff;
+			cb->segnum = scp->numdat;
+			seq_add(&scp->numdat, 1);
 			msgflg = 0x00;
 			if (sock->type == SOCK_STREAM)
 				msgflg = 0x60;
-			if (scp->seg_size == 0)
+			if (scp->seg_total == 0)
 				msgflg |= 0x20;
 
-			scp->seg_size += len;
+			scp->seg_total += len;
 		
 			if (((sent + len) == size) && (flags & MSG_EOR)) {
 				msgflg |= 0x40;
-				scp->seg_size = 0;
+				scp->seg_total = 0;
+				if (fctype == NSP_FC_SCMC)
+					scp->flowrem_dat--;
 			}
-			ack = scp->ackxmt_dat | 0x8000;
+			ack = (scp->numdat_rcv & 0x0FFF) | 0x8000;
+			scp->ackxmt_dat = scp->numdat_rcv;
+			if (fctype == NSP_FC_SRC)
+				scp->flowrem_dat--;
 		}
 
 		*ptr++ = msgflg;
@@ -1918,8 +1971,7 @@
 		*(__u16 *)ptr = dn_htons(cb->segnum);
 
 		sent += len;
-		dn_nsp_queue_xmit(sk, skb, flags & MSG_OOB);
-		numseg++;
+		dn_nsp_queue_xmit(sk, skb, sk->allocation, flags & MSG_OOB);
 		skb = NULL;
 
 		scp->persist = dn_nsp_persist(sk);
@@ -1955,21 +2007,38 @@
 }
 
 static struct notifier_block dn_dev_notifier = {
-	dn_device_event,
-	0
+	notifier_call:	dn_device_event,
 };
 
 extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *);
 
-static struct packet_type dn_dix_packet_type = 
-{
-	__constant_htons(ETH_P_DNA_RT),
-	NULL,		/* All devices */
-	dn_route_rcv,
-	(void*)1,
-	NULL,
+static struct packet_type dn_dix_packet_type = {
+	type:		__constant_htons(ETH_P_DNA_RT),
+	dev:		NULL,		/* All devices */
+	func:		dn_route_rcv,
+	data:		(void*)1,
 };
 
+#define IS_NOT_PRINTABLE(x) ((x) < 32 || (x) > 126)
+
+static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf)
+{
+	int i;
+    
+	switch (dn_ntohs(dn->sdn_objnamel)) {
+		case 0:
+			sprintf(buf, "%d", dn->sdn_objnum);
+			break;
+		default:
+			for (i = 0; i < dn_ntohs(dn->sdn_objnamel); i++) {
+				buf[i] = dn->sdn_objname[i];
+				if (IS_NOT_PRINTABLE(buf[i]))
+					buf[i] = '.';
+			}
+			buf[i] = 0;
+    	}
+}
+
 static int dn_get_info(char *buffer, char **start, off_t offset, int length)
 {
 	struct sock *sk;
@@ -1979,15 +2048,20 @@
 	off_t begin = 0;
 	char buf1[DN_ASCBUF_LEN];
 	char buf2[DN_ASCBUF_LEN];
+	char local_object[DN_MAXOBJL+3];
+	char remote_object[DN_MAXOBJL+3];
 
-	len += sprintf(buffer + len, "Local                             Remote\n");
+	len += sprintf(buffer + len, "Local                                              Remote\n");
 
 	read_lock(&dn_hash_lock);
 	for(sk = dn_sklist; sk != NULL; sk = sk->next) {
-		scp = &sk->protinfo.dn;
+		scp = DN_SK(sk);
+
+		dn_printable_object(&scp->addr, local_object);
+		dn_printable_object(&scp->peer, remote_object);
 
 		len += sprintf(buffer + len,
-				"%6s/%04X %04d:%04d %04d:%04d %01d %6s/%04X %04d:%04d %04d:%04d %01d %4s %s\n",
+				"%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
 				dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
 				scp->addrloc,
 				scp->numdat,
@@ -1995,6 +2069,7 @@
 				scp->ackxmt_dat,
 				scp->ackxmt_oth,
 				scp->flowloc_sw,
+				local_object,
 				dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
 				scp->addrrem,
 				scp->numdat_rcv,
@@ -2002,6 +2077,7 @@
 				scp->ackrcv_dat,
 				scp->ackrcv_oth,
 				scp->flowrem_sw,
+				remote_object,
 				dn_state2asc(scp->state),
 				((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
 
@@ -2026,8 +2102,8 @@
 
 
 static struct net_proto_family	dn_family_ops = {
-	AF_DECnet,
-	dn_create
+	family:		AF_DECnet,
+	create:		dn_create,
 };
 
 static struct proto_ops dn_proto_ops = {
@@ -2067,6 +2143,7 @@
 MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
 #endif
 
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.4.0-test12s (C) 1995-2000 Linux DECnet Project Team\n";
 
 static int __init decnet_init(void)
 {
@@ -2085,7 +2162,7 @@
 	dn_dn2eth(decnet_ether_address, dn_ntohs(decnet_address));
 #endif
 
-        printk(KERN_INFO "NET4: DECnet for Linux: V.2.4.0-test10s (C) 1995-2000 Linux DECnet Project Team\n");
+        printk(banner);
 
 	sock_register(&dn_family_ops);
 	dev_add_pack(&dn_dix_packet_type);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)