xref: /OK3568_Linux_fs/kernel/net/decnet/dn_nsp_in.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * DECnet       An implementation of the DECnet protocol suite for the LINUX
4*4882a593Smuzhiyun  *              operating system.  DECnet is implemented using the  BSD Socket
5*4882a593Smuzhiyun  *              interface as the means of communication with the user level.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *              DECnet Network Services Protocol (Input)
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Author:      Eduardo Marcelo Serrat <emserrat@geocities.com>
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * Changes:
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  *    Steve Whitehouse:  Split into dn_nsp_in.c and dn_nsp_out.c from
14*4882a593Smuzhiyun  *                       original dn_nsp.c.
15*4882a593Smuzhiyun  *    Steve Whitehouse:  Updated to work with my new routing architecture.
16*4882a593Smuzhiyun  *    Steve Whitehouse:  Add changes from Eduardo Serrat's patches.
17*4882a593Smuzhiyun  *    Steve Whitehouse:  Put all ack handling code in a common routine.
18*4882a593Smuzhiyun  *    Steve Whitehouse:  Put other common bits into dn_nsp_rx()
19*4882a593Smuzhiyun  *    Steve Whitehouse:  More checks on skb->len to catch bogus packets
20*4882a593Smuzhiyun  *                       Fixed various race conditions and possible nasties.
21*4882a593Smuzhiyun  *    Steve Whitehouse:  Now handles returned conninit frames.
22*4882a593Smuzhiyun  *     David S. Miller:  New socket locking
23*4882a593Smuzhiyun  *    Steve Whitehouse:  Fixed lockup when socket filtering was enabled.
24*4882a593Smuzhiyun  *         Paul Koning:  Fix to push CC sockets into RUN when acks are
25*4882a593Smuzhiyun  *                       received.
26*4882a593Smuzhiyun  *    Steve Whitehouse:
27*4882a593Smuzhiyun  *   Patrick Caulfield:  Checking conninits for correctness & sending of error
28*4882a593Smuzhiyun  *                       responses.
29*4882a593Smuzhiyun  *    Steve Whitehouse:  Added backlog congestion level return codes.
30*4882a593Smuzhiyun  *   Patrick Caulfield:
31*4882a593Smuzhiyun  *    Steve Whitehouse:  Added flow control support (outbound)
32*4882a593Smuzhiyun  *    Steve Whitehouse:  Prepare for nonlinear skbs
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /******************************************************************************
36*4882a593Smuzhiyun     (c) 1995-1998 E.M. Serrat		emserrat@geocities.com
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun *******************************************************************************/
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #include <linux/errno.h>
41*4882a593Smuzhiyun #include <linux/types.h>
42*4882a593Smuzhiyun #include <linux/socket.h>
43*4882a593Smuzhiyun #include <linux/in.h>
44*4882a593Smuzhiyun #include <linux/kernel.h>
45*4882a593Smuzhiyun #include <linux/timer.h>
46*4882a593Smuzhiyun #include <linux/string.h>
47*4882a593Smuzhiyun #include <linux/sockios.h>
48*4882a593Smuzhiyun #include <linux/net.h>
49*4882a593Smuzhiyun #include <linux/netdevice.h>
50*4882a593Smuzhiyun #include <linux/inet.h>
51*4882a593Smuzhiyun #include <linux/route.h>
52*4882a593Smuzhiyun #include <linux/slab.h>
53*4882a593Smuzhiyun #include <net/sock.h>
54*4882a593Smuzhiyun #include <net/tcp_states.h>
55*4882a593Smuzhiyun #include <linux/fcntl.h>
56*4882a593Smuzhiyun #include <linux/mm.h>
57*4882a593Smuzhiyun #include <linux/termios.h>
58*4882a593Smuzhiyun #include <linux/interrupt.h>
59*4882a593Smuzhiyun #include <linux/proc_fs.h>
60*4882a593Smuzhiyun #include <linux/stat.h>
61*4882a593Smuzhiyun #include <linux/init.h>
62*4882a593Smuzhiyun #include <linux/poll.h>
63*4882a593Smuzhiyun #include <linux/netfilter_decnet.h>
64*4882a593Smuzhiyun #include <net/neighbour.h>
65*4882a593Smuzhiyun #include <net/dst.h>
66*4882a593Smuzhiyun #include <net/dn.h>
67*4882a593Smuzhiyun #include <net/dn_nsp.h>
68*4882a593Smuzhiyun #include <net/dn_dev.h>
69*4882a593Smuzhiyun #include <net/dn_route.h>
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun extern int decnet_log_martians;
72*4882a593Smuzhiyun 
dn_log_martian(struct sk_buff * skb,const char * msg)73*4882a593Smuzhiyun static void dn_log_martian(struct sk_buff *skb, const char *msg)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	if (decnet_log_martians) {
76*4882a593Smuzhiyun 		char *devname = skb->dev ? skb->dev->name : "???";
77*4882a593Smuzhiyun 		struct dn_skb_cb *cb = DN_SKB_CB(skb);
78*4882a593Smuzhiyun 		net_info_ratelimited("DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n",
79*4882a593Smuzhiyun 				     msg, devname,
80*4882a593Smuzhiyun 				     le16_to_cpu(cb->src),
81*4882a593Smuzhiyun 				     le16_to_cpu(cb->dst),
82*4882a593Smuzhiyun 				     le16_to_cpu(cb->src_port),
83*4882a593Smuzhiyun 				     le16_to_cpu(cb->dst_port));
84*4882a593Smuzhiyun 	}
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun /*
88*4882a593Smuzhiyun  * For this function we've flipped the cross-subchannel bit
89*4882a593Smuzhiyun  * if the message is an otherdata or linkservice message. Thus
90*4882a593Smuzhiyun  * we can use it to work out what to update.
91*4882a593Smuzhiyun  */
dn_ack(struct sock * sk,struct sk_buff * skb,unsigned short ack)92*4882a593Smuzhiyun static void dn_ack(struct sock *sk, struct sk_buff *skb, unsigned short ack)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	struct dn_scp *scp = DN_SK(sk);
95*4882a593Smuzhiyun 	unsigned short type = ((ack >> 12) & 0x0003);
96*4882a593Smuzhiyun 	int wakeup = 0;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	switch (type) {
99*4882a593Smuzhiyun 	case 0: /* ACK - Data */
100*4882a593Smuzhiyun 		if (dn_after(ack, scp->ackrcv_dat)) {
101*4882a593Smuzhiyun 			scp->ackrcv_dat = ack & 0x0fff;
102*4882a593Smuzhiyun 			wakeup |= dn_nsp_check_xmit_queue(sk, skb,
103*4882a593Smuzhiyun 							  &scp->data_xmit_queue,
104*4882a593Smuzhiyun 							  ack);
105*4882a593Smuzhiyun 		}
106*4882a593Smuzhiyun 		break;
107*4882a593Smuzhiyun 	case 1: /* NAK - Data */
108*4882a593Smuzhiyun 		break;
109*4882a593Smuzhiyun 	case 2: /* ACK - OtherData */
110*4882a593Smuzhiyun 		if (dn_after(ack, scp->ackrcv_oth)) {
111*4882a593Smuzhiyun 			scp->ackrcv_oth = ack & 0x0fff;
112*4882a593Smuzhiyun 			wakeup |= dn_nsp_check_xmit_queue(sk, skb,
113*4882a593Smuzhiyun 							  &scp->other_xmit_queue,
114*4882a593Smuzhiyun 							  ack);
115*4882a593Smuzhiyun 		}
116*4882a593Smuzhiyun 		break;
117*4882a593Smuzhiyun 	case 3: /* NAK - OtherData */
118*4882a593Smuzhiyun 		break;
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	if (wakeup && !sock_flag(sk, SOCK_DEAD))
122*4882a593Smuzhiyun 		sk->sk_state_change(sk);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun /*
126*4882a593Smuzhiyun  * This function is a universal ack processor.
127*4882a593Smuzhiyun  */
dn_process_ack(struct sock * sk,struct sk_buff * skb,int oth)128*4882a593Smuzhiyun static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth)
129*4882a593Smuzhiyun {
130*4882a593Smuzhiyun 	__le16 *ptr = (__le16 *)skb->data;
131*4882a593Smuzhiyun 	int len = 0;
132*4882a593Smuzhiyun 	unsigned short ack;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	if (skb->len < 2)
135*4882a593Smuzhiyun 		return len;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	if ((ack = le16_to_cpu(*ptr)) & 0x8000) {
138*4882a593Smuzhiyun 		skb_pull(skb, 2);
139*4882a593Smuzhiyun 		ptr++;
140*4882a593Smuzhiyun 		len += 2;
141*4882a593Smuzhiyun 		if ((ack & 0x4000) == 0) {
142*4882a593Smuzhiyun 			if (oth)
143*4882a593Smuzhiyun 				ack ^= 0x2000;
144*4882a593Smuzhiyun 			dn_ack(sk, skb, ack);
145*4882a593Smuzhiyun 		}
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (skb->len < 2)
149*4882a593Smuzhiyun 		return len;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	if ((ack = le16_to_cpu(*ptr)) & 0x8000) {
152*4882a593Smuzhiyun 		skb_pull(skb, 2);
153*4882a593Smuzhiyun 		len += 2;
154*4882a593Smuzhiyun 		if ((ack & 0x4000) == 0) {
155*4882a593Smuzhiyun 			if (oth)
156*4882a593Smuzhiyun 				ack ^= 0x2000;
157*4882a593Smuzhiyun 			dn_ack(sk, skb, ack);
158*4882a593Smuzhiyun 		}
159*4882a593Smuzhiyun 	}
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	return len;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun /**
166*4882a593Smuzhiyun  * dn_check_idf - Check an image data field format is correct.
167*4882a593Smuzhiyun  * @pptr: Pointer to pointer to image data
168*4882a593Smuzhiyun  * @len: Pointer to length of image data
169*4882a593Smuzhiyun  * @max: The maximum allowed length of the data in the image data field
170*4882a593Smuzhiyun  * @follow_on: Check that this many bytes exist beyond the end of the image data
171*4882a593Smuzhiyun  *
172*4882a593Smuzhiyun  * Returns: 0 if ok, -1 on error
173*4882a593Smuzhiyun  */
dn_check_idf(unsigned char ** pptr,int * len,unsigned char max,unsigned char follow_on)174*4882a593Smuzhiyun static inline int dn_check_idf(unsigned char **pptr, int *len, unsigned char max, unsigned char follow_on)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	unsigned char *ptr = *pptr;
177*4882a593Smuzhiyun 	unsigned char flen = *ptr++;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	(*len)--;
180*4882a593Smuzhiyun 	if (flen > max)
181*4882a593Smuzhiyun 		return -1;
182*4882a593Smuzhiyun 	if ((flen + follow_on) > *len)
183*4882a593Smuzhiyun 		return -1;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	*len -= flen;
186*4882a593Smuzhiyun 	*pptr = ptr + flen;
187*4882a593Smuzhiyun 	return 0;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun /*
191*4882a593Smuzhiyun  * Table of reason codes to pass back to node which sent us a badly
192*4882a593Smuzhiyun  * formed message, plus text messages for the log. A zero entry in
193*4882a593Smuzhiyun  * the reason field means "don't reply" otherwise a disc init is sent with
194*4882a593Smuzhiyun  * the specified reason code.
195*4882a593Smuzhiyun  */
196*4882a593Smuzhiyun static struct {
197*4882a593Smuzhiyun 	unsigned short reason;
198*4882a593Smuzhiyun 	const char *text;
199*4882a593Smuzhiyun } ci_err_table[] = {
200*4882a593Smuzhiyun  { 0,             "CI: Truncated message" },
201*4882a593Smuzhiyun  { NSP_REASON_ID, "CI: Destination username error" },
202*4882a593Smuzhiyun  { NSP_REASON_ID, "CI: Destination username type" },
203*4882a593Smuzhiyun  { NSP_REASON_US, "CI: Source username error" },
204*4882a593Smuzhiyun  { 0,             "CI: Truncated at menuver" },
205*4882a593Smuzhiyun  { 0,             "CI: Truncated before access or user data" },
206*4882a593Smuzhiyun  { NSP_REASON_IO, "CI: Access data format error" },
207*4882a593Smuzhiyun  { NSP_REASON_IO, "CI: User data format error" }
208*4882a593Smuzhiyun };
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun /*
211*4882a593Smuzhiyun  * This function uses a slightly different lookup method
212*4882a593Smuzhiyun  * to find its sockets, since it searches on object name/number
213*4882a593Smuzhiyun  * rather than port numbers. Various tests are done to ensure that
214*4882a593Smuzhiyun  * the incoming data is in the correct format before it is queued to
215*4882a593Smuzhiyun  * a socket.
216*4882a593Smuzhiyun  */
dn_find_listener(struct sk_buff * skb,unsigned short * reason)217*4882a593Smuzhiyun static struct sock *dn_find_listener(struct sk_buff *skb, unsigned short *reason)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
220*4882a593Smuzhiyun 	struct nsp_conn_init_msg *msg = (struct nsp_conn_init_msg *)skb->data;
221*4882a593Smuzhiyun 	struct sockaddr_dn dstaddr;
222*4882a593Smuzhiyun 	struct sockaddr_dn srcaddr;
223*4882a593Smuzhiyun 	unsigned char type = 0;
224*4882a593Smuzhiyun 	int dstlen;
225*4882a593Smuzhiyun 	int srclen;
226*4882a593Smuzhiyun 	unsigned char *ptr;
227*4882a593Smuzhiyun 	int len;
228*4882a593Smuzhiyun 	int err = 0;
229*4882a593Smuzhiyun 	unsigned char menuver;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	memset(&dstaddr, 0, sizeof(struct sockaddr_dn));
232*4882a593Smuzhiyun 	memset(&srcaddr, 0, sizeof(struct sockaddr_dn));
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	/*
235*4882a593Smuzhiyun 	 * 1. Decode & remove message header
236*4882a593Smuzhiyun 	 */
237*4882a593Smuzhiyun 	cb->src_port = msg->srcaddr;
238*4882a593Smuzhiyun 	cb->dst_port = msg->dstaddr;
239*4882a593Smuzhiyun 	cb->services = msg->services;
240*4882a593Smuzhiyun 	cb->info     = msg->info;
241*4882a593Smuzhiyun 	cb->segsize  = le16_to_cpu(msg->segsize);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	if (!pskb_may_pull(skb, sizeof(*msg)))
244*4882a593Smuzhiyun 		goto err_out;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	skb_pull(skb, sizeof(*msg));
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	len = skb->len;
249*4882a593Smuzhiyun 	ptr = skb->data;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	/*
252*4882a593Smuzhiyun 	 * 2. Check destination end username format
253*4882a593Smuzhiyun 	 */
254*4882a593Smuzhiyun 	dstlen = dn_username2sockaddr(ptr, len, &dstaddr, &type);
255*4882a593Smuzhiyun 	err++;
256*4882a593Smuzhiyun 	if (dstlen < 0)
257*4882a593Smuzhiyun 		goto err_out;
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	err++;
260*4882a593Smuzhiyun 	if (type > 1)
261*4882a593Smuzhiyun 		goto err_out;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	len -= dstlen;
264*4882a593Smuzhiyun 	ptr += dstlen;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	/*
267*4882a593Smuzhiyun 	 * 3. Check source end username format
268*4882a593Smuzhiyun 	 */
269*4882a593Smuzhiyun 	srclen = dn_username2sockaddr(ptr, len, &srcaddr, &type);
270*4882a593Smuzhiyun 	err++;
271*4882a593Smuzhiyun 	if (srclen < 0)
272*4882a593Smuzhiyun 		goto err_out;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	len -= srclen;
275*4882a593Smuzhiyun 	ptr += srclen;
276*4882a593Smuzhiyun 	err++;
277*4882a593Smuzhiyun 	if (len < 1)
278*4882a593Smuzhiyun 		goto err_out;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	menuver = *ptr;
281*4882a593Smuzhiyun 	ptr++;
282*4882a593Smuzhiyun 	len--;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	/*
285*4882a593Smuzhiyun 	 * 4. Check that optional data actually exists if menuver says it does
286*4882a593Smuzhiyun 	 */
287*4882a593Smuzhiyun 	err++;
288*4882a593Smuzhiyun 	if ((menuver & (DN_MENUVER_ACC | DN_MENUVER_USR)) && (len < 1))
289*4882a593Smuzhiyun 		goto err_out;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/*
292*4882a593Smuzhiyun 	 * 5. Check optional access data format
293*4882a593Smuzhiyun 	 */
294*4882a593Smuzhiyun 	err++;
295*4882a593Smuzhiyun 	if (menuver & DN_MENUVER_ACC) {
296*4882a593Smuzhiyun 		if (dn_check_idf(&ptr, &len, 39, 1))
297*4882a593Smuzhiyun 			goto err_out;
298*4882a593Smuzhiyun 		if (dn_check_idf(&ptr, &len, 39, 1))
299*4882a593Smuzhiyun 			goto err_out;
300*4882a593Smuzhiyun 		if (dn_check_idf(&ptr, &len, 39, (menuver & DN_MENUVER_USR) ? 1 : 0))
301*4882a593Smuzhiyun 			goto err_out;
302*4882a593Smuzhiyun 	}
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	/*
305*4882a593Smuzhiyun 	 * 6. Check optional user data format
306*4882a593Smuzhiyun 	 */
307*4882a593Smuzhiyun 	err++;
308*4882a593Smuzhiyun 	if (menuver & DN_MENUVER_USR) {
309*4882a593Smuzhiyun 		if (dn_check_idf(&ptr, &len, 16, 0))
310*4882a593Smuzhiyun 			goto err_out;
311*4882a593Smuzhiyun 	}
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	/*
314*4882a593Smuzhiyun 	 * 7. Look up socket based on destination end username
315*4882a593Smuzhiyun 	 */
316*4882a593Smuzhiyun 	return dn_sklist_find_listener(&dstaddr);
317*4882a593Smuzhiyun err_out:
318*4882a593Smuzhiyun 	dn_log_martian(skb, ci_err_table[err].text);
319*4882a593Smuzhiyun 	*reason = ci_err_table[err].reason;
320*4882a593Smuzhiyun 	return NULL;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 
dn_nsp_conn_init(struct sock * sk,struct sk_buff * skb)324*4882a593Smuzhiyun static void dn_nsp_conn_init(struct sock *sk, struct sk_buff *skb)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	if (sk_acceptq_is_full(sk)) {
327*4882a593Smuzhiyun 		kfree_skb(skb);
328*4882a593Smuzhiyun 		return;
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	sk_acceptq_added(sk);
332*4882a593Smuzhiyun 	skb_queue_tail(&sk->sk_receive_queue, skb);
333*4882a593Smuzhiyun 	sk->sk_state_change(sk);
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun 
dn_nsp_conn_conf(struct sock * sk,struct sk_buff * skb)336*4882a593Smuzhiyun static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
339*4882a593Smuzhiyun 	struct dn_scp *scp = DN_SK(sk);
340*4882a593Smuzhiyun 	unsigned char *ptr;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	if (skb->len < 4)
343*4882a593Smuzhiyun 		goto out;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	ptr = skb->data;
346*4882a593Smuzhiyun 	cb->services = *ptr++;
347*4882a593Smuzhiyun 	cb->info = *ptr++;
348*4882a593Smuzhiyun 	cb->segsize = le16_to_cpu(*(__le16 *)ptr);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	if ((scp->state == DN_CI) || (scp->state == DN_CD)) {
351*4882a593Smuzhiyun 		scp->persist = 0;
352*4882a593Smuzhiyun 		scp->addrrem = cb->src_port;
353*4882a593Smuzhiyun 		sk->sk_state = TCP_ESTABLISHED;
354*4882a593Smuzhiyun 		scp->state = DN_RUN;
355*4882a593Smuzhiyun 		scp->services_rem = cb->services;
356*4882a593Smuzhiyun 		scp->info_rem = cb->info;
357*4882a593Smuzhiyun 		scp->segsize_rem = cb->segsize;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 		if ((scp->services_rem & NSP_FC_MASK) == NSP_FC_NONE)
360*4882a593Smuzhiyun 			scp->max_window = decnet_no_fc_max_cwnd;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 		if (skb->len > 0) {
363*4882a593Smuzhiyun 			u16 dlen = *skb->data;
364*4882a593Smuzhiyun 			if ((dlen <= 16) && (dlen <= skb->len)) {
365*4882a593Smuzhiyun 				scp->conndata_in.opt_optl = cpu_to_le16(dlen);
366*4882a593Smuzhiyun 				skb_copy_from_linear_data_offset(skb, 1,
367*4882a593Smuzhiyun 					      scp->conndata_in.opt_data, dlen);
368*4882a593Smuzhiyun 			}
369*4882a593Smuzhiyun 		}
370*4882a593Smuzhiyun 		dn_nsp_send_link(sk, DN_NOCHANGE, 0);
371*4882a593Smuzhiyun 		if (!sock_flag(sk, SOCK_DEAD))
372*4882a593Smuzhiyun 			sk->sk_state_change(sk);
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun out:
376*4882a593Smuzhiyun 	kfree_skb(skb);
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun 
dn_nsp_conn_ack(struct sock * sk,struct sk_buff * skb)379*4882a593Smuzhiyun static void dn_nsp_conn_ack(struct sock *sk, struct sk_buff *skb)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	struct dn_scp *scp = DN_SK(sk);
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	if (scp->state == DN_CI) {
384*4882a593Smuzhiyun 		scp->state = DN_CD;
385*4882a593Smuzhiyun 		scp->persist = 0;
386*4882a593Smuzhiyun 	}
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	kfree_skb(skb);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun 
dn_nsp_disc_init(struct sock * sk,struct sk_buff * skb)391*4882a593Smuzhiyun static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun 	struct dn_scp *scp = DN_SK(sk);
394*4882a593Smuzhiyun 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
395*4882a593Smuzhiyun 	unsigned short reason;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	if (skb->len < 2)
398*4882a593Smuzhiyun 		goto out;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	reason = le16_to_cpu(*(__le16 *)skb->data);
401*4882a593Smuzhiyun 	skb_pull(skb, 2);
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	scp->discdata_in.opt_status = cpu_to_le16(reason);
404*4882a593Smuzhiyun 	scp->discdata_in.opt_optl   = 0;
405*4882a593Smuzhiyun 	memset(scp->discdata_in.opt_data, 0, 16);
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	if (skb->len > 0) {
408*4882a593Smuzhiyun 		u16 dlen = *skb->data;
409*4882a593Smuzhiyun 		if ((dlen <= 16) && (dlen <= skb->len)) {
410*4882a593Smuzhiyun 			scp->discdata_in.opt_optl = cpu_to_le16(dlen);
411*4882a593Smuzhiyun 			skb_copy_from_linear_data_offset(skb, 1, scp->discdata_in.opt_data, dlen);
412*4882a593Smuzhiyun 		}
413*4882a593Smuzhiyun 	}
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	scp->addrrem = cb->src_port;
416*4882a593Smuzhiyun 	sk->sk_state = TCP_CLOSE;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	switch (scp->state) {
419*4882a593Smuzhiyun 	case DN_CI:
420*4882a593Smuzhiyun 	case DN_CD:
421*4882a593Smuzhiyun 		scp->state = DN_RJ;
422*4882a593Smuzhiyun 		sk->sk_err = ECONNREFUSED;
423*4882a593Smuzhiyun 		break;
424*4882a593Smuzhiyun 	case DN_RUN:
425*4882a593Smuzhiyun 		sk->sk_shutdown |= SHUTDOWN_MASK;
426*4882a593Smuzhiyun 		scp->state = DN_DN;
427*4882a593Smuzhiyun 		break;
428*4882a593Smuzhiyun 	case DN_DI:
429*4882a593Smuzhiyun 		scp->state = DN_DIC;
430*4882a593Smuzhiyun 		break;
431*4882a593Smuzhiyun 	}
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	if (!sock_flag(sk, SOCK_DEAD)) {
434*4882a593Smuzhiyun 		if (sk->sk_socket->state != SS_UNCONNECTED)
435*4882a593Smuzhiyun 			sk->sk_socket->state = SS_DISCONNECTING;
436*4882a593Smuzhiyun 		sk->sk_state_change(sk);
437*4882a593Smuzhiyun 	}
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	/*
440*4882a593Smuzhiyun 	 * It appears that its possible for remote machines to send disc
441*4882a593Smuzhiyun 	 * init messages with no port identifier if we are in the CI and
442*4882a593Smuzhiyun 	 * possibly also the CD state. Obviously we shouldn't reply with
443*4882a593Smuzhiyun 	 * a message if we don't know what the end point is.
444*4882a593Smuzhiyun 	 */
445*4882a593Smuzhiyun 	if (scp->addrrem) {
446*4882a593Smuzhiyun 		dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, GFP_ATOMIC);
447*4882a593Smuzhiyun 	}
448*4882a593Smuzhiyun 	scp->persist_fxn = dn_destroy_timer;
449*4882a593Smuzhiyun 	scp->persist = dn_nsp_persist(sk);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun out:
452*4882a593Smuzhiyun 	kfree_skb(skb);
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun /*
456*4882a593Smuzhiyun  * disc_conf messages are also called no_resources or no_link
457*4882a593Smuzhiyun  * messages depending upon the "reason" field.
458*4882a593Smuzhiyun  */
dn_nsp_disc_conf(struct sock * sk,struct sk_buff * skb)459*4882a593Smuzhiyun static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	struct dn_scp *scp = DN_SK(sk);
462*4882a593Smuzhiyun 	unsigned short reason;
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	if (skb->len != 2)
465*4882a593Smuzhiyun 		goto out;
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	reason = le16_to_cpu(*(__le16 *)skb->data);
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	sk->sk_state = TCP_CLOSE;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	switch (scp->state) {
472*4882a593Smuzhiyun 	case DN_CI:
473*4882a593Smuzhiyun 		scp->state = DN_NR;
474*4882a593Smuzhiyun 		break;
475*4882a593Smuzhiyun 	case DN_DR:
476*4882a593Smuzhiyun 		if (reason == NSP_REASON_DC)
477*4882a593Smuzhiyun 			scp->state = DN_DRC;
478*4882a593Smuzhiyun 		if (reason == NSP_REASON_NL)
479*4882a593Smuzhiyun 			scp->state = DN_CN;
480*4882a593Smuzhiyun 		break;
481*4882a593Smuzhiyun 	case DN_DI:
482*4882a593Smuzhiyun 		scp->state = DN_DIC;
483*4882a593Smuzhiyun 		break;
484*4882a593Smuzhiyun 	case DN_RUN:
485*4882a593Smuzhiyun 		sk->sk_shutdown |= SHUTDOWN_MASK;
486*4882a593Smuzhiyun 		fallthrough;
487*4882a593Smuzhiyun 	case DN_CC:
488*4882a593Smuzhiyun 		scp->state = DN_CN;
489*4882a593Smuzhiyun 	}
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	if (!sock_flag(sk, SOCK_DEAD)) {
492*4882a593Smuzhiyun 		if (sk->sk_socket->state != SS_UNCONNECTED)
493*4882a593Smuzhiyun 			sk->sk_socket->state = SS_DISCONNECTING;
494*4882a593Smuzhiyun 		sk->sk_state_change(sk);
495*4882a593Smuzhiyun 	}
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	scp->persist_fxn = dn_destroy_timer;
498*4882a593Smuzhiyun 	scp->persist = dn_nsp_persist(sk);
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun out:
501*4882a593Smuzhiyun 	kfree_skb(skb);
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun 
dn_nsp_linkservice(struct sock * sk,struct sk_buff * skb)504*4882a593Smuzhiyun static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun 	struct dn_scp *scp = DN_SK(sk);
507*4882a593Smuzhiyun 	unsigned short segnum;
508*4882a593Smuzhiyun 	unsigned char lsflags;
509*4882a593Smuzhiyun 	signed char fcval;
510*4882a593Smuzhiyun 	int wake_up = 0;
511*4882a593Smuzhiyun 	char *ptr = skb->data;
512*4882a593Smuzhiyun 	unsigned char fctype = scp->services_rem & NSP_FC_MASK;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	if (skb->len != 4)
515*4882a593Smuzhiyun 		goto out;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	segnum = le16_to_cpu(*(__le16 *)ptr);
518*4882a593Smuzhiyun 	ptr += 2;
519*4882a593Smuzhiyun 	lsflags = *(unsigned char *)ptr++;
520*4882a593Smuzhiyun 	fcval = *ptr;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	/*
523*4882a593Smuzhiyun 	 * Here we ignore erronous packets which should really
524*4882a593Smuzhiyun 	 * should cause a connection abort. It is not critical
525*4882a593Smuzhiyun 	 * for now though.
526*4882a593Smuzhiyun 	 */
527*4882a593Smuzhiyun 	if (lsflags & 0xf8)
528*4882a593Smuzhiyun 		goto out;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	if (seq_next(scp->numoth_rcv, segnum)) {
531*4882a593Smuzhiyun 		seq_add(&scp->numoth_rcv, 1);
532*4882a593Smuzhiyun 		switch(lsflags & 0x04) { /* FCVAL INT */
533*4882a593Smuzhiyun 		case 0x00: /* Normal Request */
534*4882a593Smuzhiyun 			switch(lsflags & 0x03) { /* FCVAL MOD */
535*4882a593Smuzhiyun 			case 0x00: /* Request count */
536*4882a593Smuzhiyun 				if (fcval < 0) {
537*4882a593Smuzhiyun 					unsigned char p_fcval = -fcval;
538*4882a593Smuzhiyun 					if ((scp->flowrem_dat > p_fcval) &&
539*4882a593Smuzhiyun 					    (fctype == NSP_FC_SCMC)) {
540*4882a593Smuzhiyun 						scp->flowrem_dat -= p_fcval;
541*4882a593Smuzhiyun 					}
542*4882a593Smuzhiyun 				} else if (fcval > 0) {
543*4882a593Smuzhiyun 					scp->flowrem_dat += fcval;
544*4882a593Smuzhiyun 					wake_up = 1;
545*4882a593Smuzhiyun 				}
546*4882a593Smuzhiyun 				break;
547*4882a593Smuzhiyun 			case 0x01: /* Stop outgoing data */
548*4882a593Smuzhiyun 				scp->flowrem_sw = DN_DONTSEND;
549*4882a593Smuzhiyun 				break;
550*4882a593Smuzhiyun 			case 0x02: /* Ok to start again */
551*4882a593Smuzhiyun 				scp->flowrem_sw = DN_SEND;
552*4882a593Smuzhiyun 				dn_nsp_output(sk);
553*4882a593Smuzhiyun 				wake_up = 1;
554*4882a593Smuzhiyun 			}
555*4882a593Smuzhiyun 			break;
556*4882a593Smuzhiyun 		case 0x04: /* Interrupt Request */
557*4882a593Smuzhiyun 			if (fcval > 0) {
558*4882a593Smuzhiyun 				scp->flowrem_oth += fcval;
559*4882a593Smuzhiyun 				wake_up = 1;
560*4882a593Smuzhiyun 			}
561*4882a593Smuzhiyun 			break;
562*4882a593Smuzhiyun 		}
563*4882a593Smuzhiyun 		if (wake_up && !sock_flag(sk, SOCK_DEAD))
564*4882a593Smuzhiyun 			sk->sk_state_change(sk);
565*4882a593Smuzhiyun 	}
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	dn_nsp_send_oth_ack(sk);
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun out:
570*4882a593Smuzhiyun 	kfree_skb(skb);
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun /*
574*4882a593Smuzhiyun  * Copy of sock_queue_rcv_skb (from sock.h) without
575*4882a593Smuzhiyun  * bh_lock_sock() (its already held when this is called) which
576*4882a593Smuzhiyun  * also allows data and other data to be queued to a socket.
577*4882a593Smuzhiyun  */
dn_queue_skb(struct sock * sk,struct sk_buff * skb,int sig,struct sk_buff_head * queue)578*4882a593Smuzhiyun static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig, struct sk_buff_head *queue)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun 	int err;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 	/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
583*4882a593Smuzhiyun 	   number of warnings when compiling with -W --ANK
584*4882a593Smuzhiyun 	 */
585*4882a593Smuzhiyun 	if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
586*4882a593Smuzhiyun 	    (unsigned int)sk->sk_rcvbuf) {
587*4882a593Smuzhiyun 		err = -ENOMEM;
588*4882a593Smuzhiyun 		goto out;
589*4882a593Smuzhiyun 	}
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	err = sk_filter(sk, skb);
592*4882a593Smuzhiyun 	if (err)
593*4882a593Smuzhiyun 		goto out;
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	skb_set_owner_r(skb, sk);
596*4882a593Smuzhiyun 	skb_queue_tail(queue, skb);
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	if (!sock_flag(sk, SOCK_DEAD))
599*4882a593Smuzhiyun 		sk->sk_data_ready(sk);
600*4882a593Smuzhiyun out:
601*4882a593Smuzhiyun 	return err;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
dn_nsp_otherdata(struct sock * sk,struct sk_buff * skb)604*4882a593Smuzhiyun static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	struct dn_scp *scp = DN_SK(sk);
607*4882a593Smuzhiyun 	unsigned short segnum;
608*4882a593Smuzhiyun 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
609*4882a593Smuzhiyun 	int queued = 0;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	if (skb->len < 2)
612*4882a593Smuzhiyun 		goto out;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data);
615*4882a593Smuzhiyun 	skb_pull(skb, 2);
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	if (seq_next(scp->numoth_rcv, segnum)) {
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 		if (dn_queue_skb(sk, skb, SIGURG, &scp->other_receive_queue) == 0) {
620*4882a593Smuzhiyun 			seq_add(&scp->numoth_rcv, 1);
621*4882a593Smuzhiyun 			scp->other_report = 0;
622*4882a593Smuzhiyun 			queued = 1;
623*4882a593Smuzhiyun 		}
624*4882a593Smuzhiyun 	}
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	dn_nsp_send_oth_ack(sk);
627*4882a593Smuzhiyun out:
628*4882a593Smuzhiyun 	if (!queued)
629*4882a593Smuzhiyun 		kfree_skb(skb);
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun 
dn_nsp_data(struct sock * sk,struct sk_buff * skb)632*4882a593Smuzhiyun static void dn_nsp_data(struct sock *sk, struct sk_buff *skb)
633*4882a593Smuzhiyun {
634*4882a593Smuzhiyun 	int queued = 0;
635*4882a593Smuzhiyun 	unsigned short segnum;
636*4882a593Smuzhiyun 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
637*4882a593Smuzhiyun 	struct dn_scp *scp = DN_SK(sk);
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	if (skb->len < 2)
640*4882a593Smuzhiyun 		goto out;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data);
643*4882a593Smuzhiyun 	skb_pull(skb, 2);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	if (seq_next(scp->numdat_rcv, segnum)) {
646*4882a593Smuzhiyun 		if (dn_queue_skb(sk, skb, SIGIO, &sk->sk_receive_queue) == 0) {
647*4882a593Smuzhiyun 			seq_add(&scp->numdat_rcv, 1);
648*4882a593Smuzhiyun 			queued = 1;
649*4882a593Smuzhiyun 		}
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 		if ((scp->flowloc_sw == DN_SEND) && dn_congested(sk)) {
652*4882a593Smuzhiyun 			scp->flowloc_sw = DN_DONTSEND;
653*4882a593Smuzhiyun 			dn_nsp_send_link(sk, DN_DONTSEND, 0);
654*4882a593Smuzhiyun 		}
655*4882a593Smuzhiyun 	}
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	dn_nsp_send_data_ack(sk);
658*4882a593Smuzhiyun out:
659*4882a593Smuzhiyun 	if (!queued)
660*4882a593Smuzhiyun 		kfree_skb(skb);
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun /*
664*4882a593Smuzhiyun  * If one of our conninit messages is returned, this function
665*4882a593Smuzhiyun  * deals with it. It puts the socket into the NO_COMMUNICATION
666*4882a593Smuzhiyun  * state.
667*4882a593Smuzhiyun  */
dn_returned_conn_init(struct sock * sk,struct sk_buff * skb)668*4882a593Smuzhiyun static void dn_returned_conn_init(struct sock *sk, struct sk_buff *skb)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun 	struct dn_scp *scp = DN_SK(sk);
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	if (scp->state == DN_CI) {
673*4882a593Smuzhiyun 		scp->state = DN_NC;
674*4882a593Smuzhiyun 		sk->sk_state = TCP_CLOSE;
675*4882a593Smuzhiyun 		if (!sock_flag(sk, SOCK_DEAD))
676*4882a593Smuzhiyun 			sk->sk_state_change(sk);
677*4882a593Smuzhiyun 	}
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	kfree_skb(skb);
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun 
dn_nsp_no_socket(struct sk_buff * skb,unsigned short reason)682*4882a593Smuzhiyun static int dn_nsp_no_socket(struct sk_buff *skb, unsigned short reason)
683*4882a593Smuzhiyun {
684*4882a593Smuzhiyun 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
685*4882a593Smuzhiyun 	int ret = NET_RX_DROP;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	/* Must not reply to returned packets */
688*4882a593Smuzhiyun 	if (cb->rt_flags & DN_RT_F_RTS)
689*4882a593Smuzhiyun 		goto out;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	if ((reason != NSP_REASON_OK) && ((cb->nsp_flags & 0x0c) == 0x08)) {
692*4882a593Smuzhiyun 		switch (cb->nsp_flags & 0x70) {
693*4882a593Smuzhiyun 		case 0x10:
694*4882a593Smuzhiyun 		case 0x60: /* (Retransmitted) Connect Init */
695*4882a593Smuzhiyun 			dn_nsp_return_disc(skb, NSP_DISCINIT, reason);
696*4882a593Smuzhiyun 			ret = NET_RX_SUCCESS;
697*4882a593Smuzhiyun 			break;
698*4882a593Smuzhiyun 		case 0x20: /* Connect Confirm */
699*4882a593Smuzhiyun 			dn_nsp_return_disc(skb, NSP_DISCCONF, reason);
700*4882a593Smuzhiyun 			ret = NET_RX_SUCCESS;
701*4882a593Smuzhiyun 			break;
702*4882a593Smuzhiyun 		}
703*4882a593Smuzhiyun 	}
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun out:
706*4882a593Smuzhiyun 	kfree_skb(skb);
707*4882a593Smuzhiyun 	return ret;
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun 
dn_nsp_rx_packet(struct net * net,struct sock * sk2,struct sk_buff * skb)710*4882a593Smuzhiyun static int dn_nsp_rx_packet(struct net *net, struct sock *sk2,
711*4882a593Smuzhiyun 			    struct sk_buff *skb)
712*4882a593Smuzhiyun {
713*4882a593Smuzhiyun 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
714*4882a593Smuzhiyun 	struct sock *sk = NULL;
715*4882a593Smuzhiyun 	unsigned char *ptr = (unsigned char *)skb->data;
716*4882a593Smuzhiyun 	unsigned short reason = NSP_REASON_NL;
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	if (!pskb_may_pull(skb, 2))
719*4882a593Smuzhiyun 		goto free_out;
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	skb_reset_transport_header(skb);
722*4882a593Smuzhiyun 	cb->nsp_flags = *ptr++;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	if (decnet_debug_level & 2)
725*4882a593Smuzhiyun 		printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags);
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	if (cb->nsp_flags & 0x83)
728*4882a593Smuzhiyun 		goto free_out;
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	/*
731*4882a593Smuzhiyun 	 * Filter out conninits and useless packet types
732*4882a593Smuzhiyun 	 */
733*4882a593Smuzhiyun 	if ((cb->nsp_flags & 0x0c) == 0x08) {
734*4882a593Smuzhiyun 		switch (cb->nsp_flags & 0x70) {
735*4882a593Smuzhiyun 		case 0x00: /* NOP */
736*4882a593Smuzhiyun 		case 0x70: /* Reserved */
737*4882a593Smuzhiyun 		case 0x50: /* Reserved, Phase II node init */
738*4882a593Smuzhiyun 			goto free_out;
739*4882a593Smuzhiyun 		case 0x10:
740*4882a593Smuzhiyun 		case 0x60:
741*4882a593Smuzhiyun 			if (unlikely(cb->rt_flags & DN_RT_F_RTS))
742*4882a593Smuzhiyun 				goto free_out;
743*4882a593Smuzhiyun 			sk = dn_find_listener(skb, &reason);
744*4882a593Smuzhiyun 			goto got_it;
745*4882a593Smuzhiyun 		}
746*4882a593Smuzhiyun 	}
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 	if (!pskb_may_pull(skb, 3))
749*4882a593Smuzhiyun 		goto free_out;
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	/*
752*4882a593Smuzhiyun 	 * Grab the destination address.
753*4882a593Smuzhiyun 	 */
754*4882a593Smuzhiyun 	cb->dst_port = *(__le16 *)ptr;
755*4882a593Smuzhiyun 	cb->src_port = 0;
756*4882a593Smuzhiyun 	ptr += 2;
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun 	/*
759*4882a593Smuzhiyun 	 * If not a connack, grab the source address too.
760*4882a593Smuzhiyun 	 */
761*4882a593Smuzhiyun 	if (pskb_may_pull(skb, 5)) {
762*4882a593Smuzhiyun 		cb->src_port = *(__le16 *)ptr;
763*4882a593Smuzhiyun 		ptr += 2;
764*4882a593Smuzhiyun 		skb_pull(skb, 5);
765*4882a593Smuzhiyun 	}
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	/*
768*4882a593Smuzhiyun 	 * Returned packets...
769*4882a593Smuzhiyun 	 * Swap src & dst and look up in the normal way.
770*4882a593Smuzhiyun 	 */
771*4882a593Smuzhiyun 	if (unlikely(cb->rt_flags & DN_RT_F_RTS)) {
772*4882a593Smuzhiyun 		swap(cb->dst_port, cb->src_port);
773*4882a593Smuzhiyun 		swap(cb->dst, cb->src);
774*4882a593Smuzhiyun 	}
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	/*
777*4882a593Smuzhiyun 	 * Find the socket to which this skb is destined.
778*4882a593Smuzhiyun 	 */
779*4882a593Smuzhiyun 	sk = dn_find_by_skb(skb);
780*4882a593Smuzhiyun got_it:
781*4882a593Smuzhiyun 	if (sk != NULL) {
782*4882a593Smuzhiyun 		struct dn_scp *scp = DN_SK(sk);
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 		/* Reset backoff */
785*4882a593Smuzhiyun 		scp->nsp_rxtshift = 0;
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 		/*
788*4882a593Smuzhiyun 		 * We linearize everything except data segments here.
789*4882a593Smuzhiyun 		 */
790*4882a593Smuzhiyun 		if (cb->nsp_flags & ~0x60) {
791*4882a593Smuzhiyun 			if (unlikely(skb_linearize(skb)))
792*4882a593Smuzhiyun 				goto free_out;
793*4882a593Smuzhiyun 		}
794*4882a593Smuzhiyun 
795*4882a593Smuzhiyun 		return sk_receive_skb(sk, skb, 0);
796*4882a593Smuzhiyun 	}
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	return dn_nsp_no_socket(skb, reason);
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun free_out:
801*4882a593Smuzhiyun 	kfree_skb(skb);
802*4882a593Smuzhiyun 	return NET_RX_DROP;
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun 
dn_nsp_rx(struct sk_buff * skb)805*4882a593Smuzhiyun int dn_nsp_rx(struct sk_buff *skb)
806*4882a593Smuzhiyun {
807*4882a593Smuzhiyun 	return NF_HOOK(NFPROTO_DECNET, NF_DN_LOCAL_IN,
808*4882a593Smuzhiyun 		       &init_net, NULL, skb, skb->dev, NULL,
809*4882a593Smuzhiyun 		       dn_nsp_rx_packet);
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun /*
813*4882a593Smuzhiyun  * This is the main receive routine for sockets. It is called
814*4882a593Smuzhiyun  * from the above when the socket is not busy, and also from
815*4882a593Smuzhiyun  * sock_release() when there is a backlog queued up.
816*4882a593Smuzhiyun  */
dn_nsp_backlog_rcv(struct sock * sk,struct sk_buff * skb)817*4882a593Smuzhiyun int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
818*4882a593Smuzhiyun {
819*4882a593Smuzhiyun 	struct dn_scp *scp = DN_SK(sk);
820*4882a593Smuzhiyun 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 	if (cb->rt_flags & DN_RT_F_RTS) {
823*4882a593Smuzhiyun 		if (cb->nsp_flags == 0x18 || cb->nsp_flags == 0x68)
824*4882a593Smuzhiyun 			dn_returned_conn_init(sk, skb);
825*4882a593Smuzhiyun 		else
826*4882a593Smuzhiyun 			kfree_skb(skb);
827*4882a593Smuzhiyun 		return NET_RX_SUCCESS;
828*4882a593Smuzhiyun 	}
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	/*
831*4882a593Smuzhiyun 	 * Control packet.
832*4882a593Smuzhiyun 	 */
833*4882a593Smuzhiyun 	if ((cb->nsp_flags & 0x0c) == 0x08) {
834*4882a593Smuzhiyun 		switch (cb->nsp_flags & 0x70) {
835*4882a593Smuzhiyun 		case 0x10:
836*4882a593Smuzhiyun 		case 0x60:
837*4882a593Smuzhiyun 			dn_nsp_conn_init(sk, skb);
838*4882a593Smuzhiyun 			break;
839*4882a593Smuzhiyun 		case 0x20:
840*4882a593Smuzhiyun 			dn_nsp_conn_conf(sk, skb);
841*4882a593Smuzhiyun 			break;
842*4882a593Smuzhiyun 		case 0x30:
843*4882a593Smuzhiyun 			dn_nsp_disc_init(sk, skb);
844*4882a593Smuzhiyun 			break;
845*4882a593Smuzhiyun 		case 0x40:
846*4882a593Smuzhiyun 			dn_nsp_disc_conf(sk, skb);
847*4882a593Smuzhiyun 			break;
848*4882a593Smuzhiyun 		}
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	} else if (cb->nsp_flags == 0x24) {
851*4882a593Smuzhiyun 		/*
852*4882a593Smuzhiyun 		 * Special for connacks, 'cos they don't have
853*4882a593Smuzhiyun 		 * ack data or ack otherdata info.
854*4882a593Smuzhiyun 		 */
855*4882a593Smuzhiyun 		dn_nsp_conn_ack(sk, skb);
856*4882a593Smuzhiyun 	} else {
857*4882a593Smuzhiyun 		int other = 1;
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 		/* both data and ack frames can kick a CC socket into RUN */
860*4882a593Smuzhiyun 		if ((scp->state == DN_CC) && !sock_flag(sk, SOCK_DEAD)) {
861*4882a593Smuzhiyun 			scp->state = DN_RUN;
862*4882a593Smuzhiyun 			sk->sk_state = TCP_ESTABLISHED;
863*4882a593Smuzhiyun 			sk->sk_state_change(sk);
864*4882a593Smuzhiyun 		}
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 		if ((cb->nsp_flags & 0x1c) == 0)
867*4882a593Smuzhiyun 			other = 0;
868*4882a593Smuzhiyun 		if (cb->nsp_flags == 0x04)
869*4882a593Smuzhiyun 			other = 0;
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 		/*
872*4882a593Smuzhiyun 		 * Read out ack data here, this applies equally
873*4882a593Smuzhiyun 		 * to data, other data, link serivce and both
874*4882a593Smuzhiyun 		 * ack data and ack otherdata.
875*4882a593Smuzhiyun 		 */
876*4882a593Smuzhiyun 		dn_process_ack(sk, skb, other);
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 		/*
879*4882a593Smuzhiyun 		 * If we've some sort of data here then call a
880*4882a593Smuzhiyun 		 * suitable routine for dealing with it, otherwise
881*4882a593Smuzhiyun 		 * the packet is an ack and can be discarded.
882*4882a593Smuzhiyun 		 */
883*4882a593Smuzhiyun 		if ((cb->nsp_flags & 0x0c) == 0) {
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 			if (scp->state != DN_RUN)
886*4882a593Smuzhiyun 				goto free_out;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 			switch (cb->nsp_flags) {
889*4882a593Smuzhiyun 			case 0x10: /* LS */
890*4882a593Smuzhiyun 				dn_nsp_linkservice(sk, skb);
891*4882a593Smuzhiyun 				break;
892*4882a593Smuzhiyun 			case 0x30: /* OD */
893*4882a593Smuzhiyun 				dn_nsp_otherdata(sk, skb);
894*4882a593Smuzhiyun 				break;
895*4882a593Smuzhiyun 			default:
896*4882a593Smuzhiyun 				dn_nsp_data(sk, skb);
897*4882a593Smuzhiyun 			}
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun 		} else { /* Ack, chuck it out here */
900*4882a593Smuzhiyun free_out:
901*4882a593Smuzhiyun 			kfree_skb(skb);
902*4882a593Smuzhiyun 		}
903*4882a593Smuzhiyun 	}
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 	return NET_RX_SUCCESS;
906*4882a593Smuzhiyun }
907