1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Packet.c
30 *
31 * v01.23  All incoming packets come here first    06/21/90 mbs
32 *    Modified for MP, 1996 by Tuyen Nguyen
33 *   Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
34 */
35
36#include <sys/errno.h>
37#include <sys/types.h>
38#include <sys/param.h>
39#include <machine/spl.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/proc.h>
43#include <sys/filedesc.h>
44#include <sys/fcntl.h>
45#include <sys/mbuf.h>
46#include <sys/ioctl.h>
47#include <sys/malloc.h>
48#include <sys/socket.h>
49#include <sys/socketvar.h>
50#include <sys/time.h>
51
52#include <net/if.h>
53
54#include <netat/sysglue.h>
55#include <netat/appletalk.h>
56#include <netat/at_pcb.h>
57#include <netat/ddp.h>
58#include <netat/at_var.h>
59
60#include <netat/adsp.h>
61#include <netat/adsp_internal.h>
62
63extern at_ifaddr_t *ifID_home;
64
65/*
66 * GleanSession
67 *
68 * We just got a packet for this session, glean its address &
69 * reset probe timer
70 *
71 * INPUTS:
72 *    Session
73 * OUTPUTS:
74 *    none
75 */
76static void GleanSession(CCBPtr);
77
78static void GleanSession(sp)		/* (CCBPtr sp) */
79    CCBPtr sp;
80{
81    if (sp->openState == O_STATE_OPEN) {
82	/* This is true for both state = sOpen & sClosing */
83        RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
84	InsertTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer,
85			sp->probeInterval);
86	sp->probeCntr	= 4;
87    }
88
89}
90
91
92/*
93 * The same code handles incoming Open Connection Request,
94 * Open Request + Ack, Open Connection Ack, Open Connection Denial
95 *
96 * We could be in four different states, LISTEN, OPENWAIT, ESTABLISHED,
97 * OPEN.
98 */
99
100/*
101 *
102 * Ok, there are 16 combinations.  8 are do-nothings, 2 have to be
103 * special cased (Open Deny and Req+Ack on Open session)
104 *
105 * Build a table of actions:
106 *    Ignore?
107 *    What to match on (local socket, whole address, DestCID, SrcCID)
108 *    What to send (Ack or Req+Ack)
109 *    Next State (both the ccb state and the open state)
110 */
111
112/*
113 *
114 */
115typedef struct {
116    u_char match;		/* Characteristics that have to match
117				 * (Bit-Mapped, see below) */
118    char action;		/* What to do if CCB matches */
119    char send;			/* What to send in response
120				 * (Bit mapped, same as sendCtl field of
121				 * CCB) */
122    char openState;		/* Next Open state */
123    char state;			/* Next ccb state. */
124    char pad;			/* Too bad we need this to make structure
125				 * even size */
126} TBL, *TBLPtr;
127
128#define M_LSOC		0x01	/* bit  0 - Match on local socket */
129#define M_ADDR		0x02	/* bit  1 - Match on whole address */
130#define M_DCID		0x04	/* bit  2 - Match on DestCID */
131#define M_SCID		0x08	/* bit  3 - Match SrcCID */
132#define M_DCIDZERO	0x10	/* bit  4 - Dest CID must be 0 */
133#define M_SCIDZERO	0x20	/* bit  5 - Src CID must be 0 */
134#define M_FILTER	0x40	/* bit  6 - Match address filter */
135#define M_IGNORE	0x80	/* bit  7 - Ignore */
136
137#define A_COMPLETE	0x01	/* Complete open parameter block */
138#define A_SAVEPARMS	0x02	/* Save connection parameters */
139#define A_OREQACKOPEN	0x04	/* special case for open Req+Ack on
140				 * OPEN session */
141#define A_GLEAN		0x08	/* We'll be talking back to this guy */
142#define A_DENY		0x10	/* We've been denied! */
143
144
145/*
146 * So here's our table
147 */
148
149static TBL tbl[16] = {
150
151/*
152 * For Open Request ($81)
153 *
154 *	LISTENING
155 *		Match on destination socket
156 *		Match on address filter
157 *		Dest CID must be 0
158 *		Glean connection
159 *		Save Open Connection parameters
160 *		Send OREQACK
161 *		Change state to ESTABLISHED
162 */
163	{	M_LSOC + M_DCIDZERO + M_FILTER,
164	 	A_SAVEPARMS + A_GLEAN,
165		B_CTL_OREQACK,
166		O_STATE_ESTABLISHED,
167		sOpening,
168		0
169	},
170
171/*
172 *
173 *	OPENWAIT
174 *		Match on Remote Address & destination socket
175 *		Dest CID must be 0
176 *		Save Open Connection parameters
177 *		Send Ack
178 *		Change state to ESTABLISHED
179 */
180	{	M_LSOC + M_ADDR + M_DCIDZERO,
181	  	A_SAVEPARMS + A_GLEAN,
182	  	B_CTL_OACK,
183	  	O_STATE_ESTABLISHED,
184		sOpening,
185		0
186	},
187/*
188 *
189 *	ESTABLISHED
190 *		Match on Remote Address & SrcCID
191 *		Dest CID must be 0
192 *		Send Req + Ack
193 */
194	{	M_ADDR + M_SCID + M_DCIDZERO,
195		A_GLEAN,
196		B_CTL_OACK,
197		O_STATE_ESTABLISHED,
198		sOpening,
199		0
200	},
201/*
202 *	OPEN
203 *		Ignore
204 */
205	{	M_IGNORE,
206		0,
207		0,
208		0,
209		0,
210		0
211	},
212
213/*
214 *
215 * For Open Ack ($82)
216 *
217 *	LISTENING
218 *		Ignore
219 */
220	{	M_IGNORE,
221		0,
222		0,
223		0,
224		0,
225		0
226	},
227/*
228 *
229 *	OPENWAIT
230 *		Ignore
231 */
232	{	M_IGNORE,
233		0,
234		0,
235		0,
236		0,
237		0
238	},
239/*
240 *
241 *	ESTABLISHED
242 *		Match on SrcCID & DestCID & Address & Local Socket
243 *		Complete Listen or Connect PB
244 *		OPEN
245 */
246	{	M_ADDR + M_DCID + M_SCID + M_LSOC,
247		A_COMPLETE + A_GLEAN,
248		0,
249		O_STATE_OPEN,
250		sOpen,
251		0
252	},
253/*
254 *
255 *	OPEN
256 *		Ignore
257*/
258	{	M_IGNORE,
259		0,
260		0,
261		0,
262		0,
263		0
264	},
265
266/*
267 *
268 * For Open Request + Ack ($83)
269 *
270 *	LISTENING
271 *		Ignore
272*/
273	{	M_IGNORE,
274		0,
275		0,
276		0,
277		0,
278		0
279	},
280/*
281 *
282 *	OPENWAIT
283 *		Match on DestCID & socket
284 *			Do not test remote address -- our open req could have
285 *			been passed to another address by a connection server
286 *		Save Open Connection parameters
287 *		Complete Connect parameter block
288 *		Send Ack
289 *		OPEN
290 */
291	{	M_DCID + M_LSOC,
292		A_COMPLETE + A_SAVEPARMS + A_GLEAN,
293	  	B_CTL_OACK,
294	  	O_STATE_OPEN,
295		sOpen,
296		0
297	},
298/*
299 *
300 *	ESTABLISHED
301 *		Ignore
302 */
303	{	M_IGNORE,
304		0,
305		0,
306		0,
307		0,
308		0
309	},
310/*
311 *
312 *	OPEN
313 *		Match on Remote Address & SrcCID & DestCID & Local Socket
314 *		If we've never gotten any data
315 *		Send Ack & Retransmit
316 */
317	{	M_ADDR + M_DCID + M_SCID + M_LSOC,
318	  	A_OREQACKOPEN + A_GLEAN,
319	  	B_CTL_OACK,
320	  	O_STATE_OPEN,
321		sOpen,
322		0
323	},
324
325/*
326 *
327 *
328 * For Open Deny ($84)
329 *
330 *	LISTENING
331 *		Ignore
332 */
333	{	M_IGNORE,
334		0,
335		0,
336		0,
337		0,
338		0
339	},
340/*
341 *
342 *	OPENWAIT
343 *		Match on DestCID & Address
344 *		Source CID must be 0
345 *		Complete with error
346 */
347	{	M_SCIDZERO + M_DCID + M_ADDR,
348		A_DENY,
349		0,
350		O_STATE_NOTHING,
351		sClosed,
352		0
353	},
354/*
355 *
356 *	ESTABLISHED
357 *		Ignore
358 */
359	{	M_IGNORE,
360		0,
361		0,
362		0,
363		0,
364		0
365	},	/* %%% No we probably don't want to ignore in this case */
366/*
367 *
368 *    OPEN
369 *       Ignore
370 */
371	{	M_IGNORE,
372		0,
373		0,
374		0,
375		0,
376		0
377	}
378};
379
380extern at_ifaddr_t *ifID_table[];
381
382/*
383 * Used to search down queue of sessions for a session waiting for an
384 * open request.
385 */
386typedef struct {
387   AddrUnion	addr;
388   word		dstCID;
389   word		srcCID;
390   byte		socket;
391   byte		descriptor;
392   byte		idx;		/* Index into state tables */
393   TBLPtr	t;		/* Ptr to entry in table above */
394} MATCH, *MATCHPtr;
395
396/*
397 * MatchStream
398 *
399 * Called by Rx connection to find which stream (if any) should get this open
400 * request/ack/req+ack/deny packet.
401 *
402 */
403static boolean MatchStream(CCBPtr, MATCHPtr);
404
405static boolean
406MatchStream(sp, m)		/* (CCBPtr sp, MATCHPtr m) */
407    CCBPtr sp;
408    MATCHPtr m;
409{
410	unsigned char match;
411	struct adspcmd 	*opb;
412
413	if (sp->openState < O_STATE_LISTEN ||
414	    sp->openState > O_STATE_OPEN)
415	    return 0;
416
417
418	m->t = &tbl[sp->openState - O_STATE_LISTEN + m->idx];
419
420	match = m->t->match;	/* Get match criteria */
421
422	if (match & M_IGNORE)	/* Ignore this combination */
423	    return 0;
424
425	if (match & M_LSOC) {	/* Match on Local socket */
426	    if (sp->localSocket != m->socket)
427		return 0;
428	}
429
430	if (match & M_ADDR) {	/* Match on Address */
431	    AddrUnion	addr;
432	    addr = m->addr;	/* Make local copy for efficiency */
433	    if (sp->remoteAddress.a.node != addr.a.node)
434		return 0;
435	    if (sp->remoteAddress.a.socket != addr.a.socket)
436		return 0;
437	    if (sp->remoteAddress.a.net && addr.a.net &&
438		(sp->remoteAddress.a.net != addr.a.net))
439		return 0;
440
441	    /*
442	     * Handle special case to reject self-sent open request
443	     */
444 	    if ((m->srcCID == sp->locCID) &&
445		(addr.a.node == ifID_home->ifThisNode.s_node) &&
446		/* *** was (addr.a.node == ddpcfg.node_addr.node) && *** */
447 		((addr.a.net == 0) ||
448 		 (ifID_home->ifThisNode.s_net == 0) ||
449 		 (ifID_home->ifThisNode.s_net == addr.a.net)) )
450	      /* *** was
451		(NET_VALUE(ddpcfg.node_addr.net) == 0) ||
452 		(NET_VALUE(ddpcfg.node_addr.net) == NET_VALUE(addr.a.net))) )
453		 *** */
454				/* CID's match, and */
455				/* If nodeID matches, and */
456				/* network matches, */
457		return 0;	/* then came from us! */
458	}
459
460	if (match & M_DCID) {	/* Match on DestCID */
461	    if (sp->locCID != m->dstCID)
462		return 0;
463	}
464
465	if (match & M_SCID) {	/* Match on SourceCID */
466	    if (sp->remCID != m->srcCID)
467		return 0;
468	}
469
470	if (match & M_DCIDZERO)	{ /* Destination CID must be 0 */
471	    if (m->dstCID != 0)
472		return 0;
473	}
474
475	if (match & M_SCIDZERO)	/* Source CID must be 0 */
476	{
477	    if (m->srcCID != 0)
478		return 0;
479	}
480
481	if (match & M_FILTER) {	/* Check address filter? */
482	    if ((opb = sp->opb)) /* There should be a param block... */
483	    {
484		AddrUnion	addr;
485		addr = m->addr;	/* Make local copy for efficiency */
486		if ((opb->u.openParams.filterAddress.net &&
487		     addr.a.net &&
488		     opb->u.openParams.filterAddress.net != addr.a.net) ||
489		    (opb->u.openParams.filterAddress.node != 0 &&
490		     opb->u.openParams.filterAddress.node != addr.a.node)||
491		    (opb->u.openParams.filterAddress.socket != 0 &&
492		     opb->u.openParams.filterAddress.socket != addr.a.socket))
493		    return 0;
494	    }
495	}
496
497	return 1;
498}
499
500/*
501 * MatchListener
502 *
503 * Called by rx connection to see which connection listener (if any) should
504 * get this incoming open connection request.
505 *
506 */
507
508static boolean MatchListener(CCBPtr, MATCHPtr);
509
510static boolean MatchListener(sp, m) /* (CCBPtr sp, MATCHPtr m) */
511    CCBPtr sp;
512    MATCHPtr m;
513{
514
515    if ((sp->state == (word)sListening) && /* This CCB is a listener */
516	(sp->localSocket == m->socket))	/* on the right socket */
517	return 1;
518
519    return 0;
520}
521
522/*
523 * RXConnection
524 *
525 * We just received one of the 4 Open Connection packets
526 * Interrupts are masked OFF at this point
527 *
528 * INPUTS:
529 *	spPtr	Place to put ptr to stream (if we found one -- not
530 *						for listeners)
531 *	f	Pointer to ADSP header for packet, data follows behind it
532 *	len	# of byte in ADSP header + data
533 *	addr	Who sent the packet
534 *	dsoc	Where they sent it to
535 *
536 * OUTPUTS:
537 *    Returns 1 if packet was ignored
538 */
539static int RXConnection(
540    __unused gref_t *gref,			/* READ queue */
541    CCBPtr *spPtr,
542    ADSP_FRAMEPtr f,
543    int len,
544    AddrUnion addr,
545    unsigned char dsoc)
546{
547    CCBPtr sp;
548    ADSP_OPEN_DATAPtr op;
549    struct adspcmd *pb;
550    MATCH m;
551    gbuf_t *mp;
552    ADSP_FRAMEPtr adspp;
553    ADSP_OPEN_DATAPtr adspop;
554
555    op = (ADSP_OPEN_DATAPtr)&f->data[0]; /* Point to Open-Connection parms */
556    len -= ADSP_FRAME_LEN;
557
558    if (len < (sizeof(ADSP_OPEN_DATA))) /* Packet too small */
559	return 1;
560
561
562    if (UAS_VALUE(op->version) != netw(0x0100)) { /* Check version num (on even-byte) */
563	/*
564	 * The open request has been denied.  Try to send him a denial.
565	 */
566
567	mp = gbuf_alloc(AT_WR_OFFSET + DDPL_FRAME_LEN + ADSP_FRAME_LEN + ADSP_OPEN_FRAME_LEN,
568		    PRI_LO);
569	gbuf_rinc(mp,AT_WR_OFFSET);
570	gbuf_wset(mp,DDPL_FRAME_LEN);
571	adspp = (ADSP_FRAMEPtr)gbuf_wptr(mp);
572	gbuf_winc(mp,ADSP_FRAME_LEN);
573	bzero((caddr_t) gbuf_rptr(mp),DDPL_FRAME_LEN + ADSP_FRAME_LEN +
574	      ADSP_OPEN_FRAME_LEN);
575	adspp->descriptor = ADSP_CONTROL_BIT | ADSP_CTL_ODENY;
576	adspop = (ADSP_OPEN_DATAPtr)gbuf_wptr(mp);
577	gbuf_winc(mp,ADSP_OPEN_FRAME_LEN);
578	UAS_UAS(adspop->dstCID, f->CID);
579	UAS_ASSIGN_HTON(adspop->version, 0x100);
580	adsp_sendddp(0, mp, DDPL_FRAME_LEN + ADSP_FRAME_LEN +
581		   ADSP_OPEN_FRAME_LEN, &addr, DDP_ADSP);
582
583	return 0;
584    }
585    m.addr = addr;
586    m.socket = dsoc;
587    m.descriptor = f->descriptor;
588    m.srcCID = UAS_VALUE_NTOH(f->CID);
589    m.dstCID = UAS_VALUE_NTOH(op->dstCID);	/* On even-byte boundry */
590    m.idx = ((f->descriptor & ADSP_CONTROL_MASK) - 1) * 4;
591
592    /*
593     * See if we can find a stream that knows what to do with this packet
594     */
595    if ((sp = (CCBPtr)qfind_m((CCB *)AT_ADSP_STREAMS, &m, (ProcPtr)MatchStream)) == 0)
596    {
597	struct adspcmd *p;
598	struct adspcmd *n;
599	/*
600	 * No match, so look for connection listeners if this is an
601	 * open request
602	 */
603	if ((f->descriptor & ADSP_CONTROL_MASK) != (byte)ADSP_CTL_OREQ)
604	    return 1;
605
606	if ((sp = (CCBPtr)qfind_m((CCB *)AT_ADSP_STREAMS, &m,
607				  (ProcPtr)MatchListener)) == 0)
608	    return 1;
609
610	p = (struct adspcmd *)&sp->opb;
611	while ((n = (struct adspcmd *)p->qLink)) /* Hunt down list of listens */
612	{
613	    /* Check address filter */
614	    if (((n->u.openParams.filterAddress.net == 0) ||
615		 (addr.a.net == 0) ||
616		 (n->u.openParams.filterAddress.net == addr.a.net)) &&
617
618		((n->u.openParams.filterAddress.node == 0) ||
619		 (n->u.openParams.filterAddress.node == addr.a.node)) &&
620
621		((n->u.openParams.filterAddress.socket == 0) ||
622		 (n->u.openParams.filterAddress.socket == addr.a.socket))) {
623		p->qLink = n->qLink; /* Unlink this param block */
624		n->u.openParams.remoteCID = m.srcCID;
625		*((AddrUnionPtr)&n->u.openParams.remoteAddress)	= addr;
626		n->u.openParams.sendSeq	= UAL_VALUE_NTOH(f->pktNextRecvSeq);
627		n->u.openParams.sendWindow = UAS_VALUE_NTOH(f->pktRecvWdw);
628		n->u.openParams.attnSendSeq = UAL_VALUE_NTOH(op->pktAttnRecvSeq);
629		n->ioResult = 0;
630		completepb(sp, n); /* complete copy of request */
631				/* complete(n, 0); */
632		return 0;
633	    }			/* found CLListen */
634
635	    p = n;		/* down the list we go... */
636
637	}			/* while */
638
639	return 1;
640    }
641
642    *spPtr = sp;		/* Save ptr to stream we just found */
643
644    sp->openState = m.t->openState; /* Move to next state (may be same) */
645    sp->state = m.t->state;	/* Move to next state (may be same) */
646
647    if (m.t->action & A_SAVEPARMS) { /* Need to Save open-conn parms */
648	sp->firstRtmtSeq = sp->sendSeq = UAL_VALUE_NTOH(f->pktNextRecvSeq);
649	sp->sendWdwSeq = UAL_VALUE_NTOH(f->pktNextRecvSeq) + UAS_VALUE_NTOH(f->pktRecvWdw) - 1;
650	sp->attnSendSeq = UAL_VALUE_NTOH(op->pktAttnRecvSeq); /* on even boundry */
651
652
653	sp->remCID = UAS_VALUE_NTOH(f->CID);	/* Save Source CID as RemCID */
654	UAS_UAS(sp->of.dstCID, f->CID);	/* Save CID in open ctl packet */
655
656	sp->remoteAddress = addr; /* Save his address */
657
658    }
659
660    if (m.t->action & A_DENY) {	/* We've been denied ! */
661	DoClose(sp, errOpenDenied, -1);
662    }
663
664    if (m.t->action & A_OREQACKOPEN) {
665				/* Special case for OREQACK */
666				/* on an open session */
667        RemoveTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer);
668	sp->sendSeq = sp->firstRtmtSeq;
669	sp->pktSendCnt	= 0;
670	sp->waitingAck	= 0;
671	sp->callSend = 1;
672    }
673
674    if (m.t->send) {		/* Need to send a response */
675	sp->sendCtl |= m.t->send;
676	sp->callSend = 1;
677    }
678
679    if (m.t->action & A_COMPLETE) { /* Need to complete open param blk */
680        RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
681
682	if ((pb = sp->opb)) {
683	    sp->opb = 0;
684	    pb->u.openParams.localCID = sp->locCID;
685	    pb->u.openParams.remoteCID = sp->remCID;
686	    pb->u.openParams.remoteAddress =
687		*((at_inet_t *)&sp->remoteAddress);
688	    pb->u.openParams.sendSeq = sp->sendSeq;
689	    pb->u.openParams.sendWindow = sp->sendWdwSeq - sp->sendSeq;
690	    pb->u.openParams.attnSendSeq = sp->attnSendSeq;
691	    pb->ioResult = 0;
692	    completepb(sp, pb);	/* complete(pb, 0); */
693	    return 0;
694	}
695				/* Start probe timer */
696	InsertTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer,
697			sp->probeInterval);
698    }
699    return 0;
700}
701
702/*
703 * ADSPPacket
704 *
705 * When a packet is received by the protocol stack with DDP type equal
706 * to ADSP, then execution comes here
707 *
708 * DS is set to ATALK's DGROUP
709 *
710 * This routine, or one of its children MUST call glean packet
711 *
712 * INPUTS:
713 *    Pointer to DDP header
714 * OUTPUTS:
715 *    none
716 *
717 * Note that the incoming message block (mp) is usually discarded, either
718 * by the "ignored" path, or via the "checksend" path.  The only case
719 * where the message is NOT freed is via the RxData case in the
720 * non control packet switch.  I zero mp after the RxData case succeeds
721 * so that mp will not be freed.
722 */
723int adspPacket(gref, mp)
724    /* (bytePtr data, word len, AddrUnion a, byte dsoc) */
725    gref_t *gref;
726    gbuf_t *mp;
727{
728    unsigned char *bp;
729    int len;
730    AddrUnion a;
731    int dsoc;
732    register DDPX_FRAME *ddp;	/* DDP frame pointer */
733    register ADSP_FRAMEPtr f;	/* Frame */
734    CCBPtr sp;
735
736    sp = 0;			/* No stream */
737    bp = (unsigned char *)gbuf_rptr(mp);
738    ddp = (DDPX_FRAME *)bp;
739    if (ddp->ddpx_type != DDP_ADSP)
740	return -1;
741    f = (ADSP_FRAMEPtr)(bp + DDPL_FRAME_LEN);
742
743    len = UAS_VALUE_NTOH(ddp->ddpx_length) & 0x3ff; /* (ten bits of length) */
744    len -= DDPL_FRAME_LEN;
745    if (len < (sizeof(ADSP_FRAME) - 1))	/* Packet too small */
746	return -1;		/* mark the failure */
747
748    a.a.net = NET_VALUE(ddp->ddpx_snet);
749    a.a.node = ddp->ddpx_snode;
750    a.a.socket = ddp->ddpx_source;
751
752    dsoc = ddp->ddpx_dest;
753
754    if ((sp = (CCBPtr)FindSender(f, a)))
755	GleanSession(sp);
756
757    if (f->descriptor & ADSP_ATTENTION_BIT) { /* ATTN packet */
758	if (sp && RXAttention(sp, mp, f, len))
759	    goto ignore;
760	else
761	    mp = 0;		/* attention data is being held */
762    }				/* ATTENTION BIT */
763
764    else if (f->descriptor & ADSP_CONTROL_BIT) { /* Control packet */
765	switch (f->descriptor & ADSP_CONTROL_MASK) {
766	case ADSP_CTL_PROBE:	/* Probe or acknowledgement */
767	    if (sp)
768		CheckRecvSeq(sp, f);
769	    break;
770
771	case ADSP_CTL_OREQ:	/* Open Connection Request */
772	case ADSP_CTL_OREQACK:	/* Open Request and acknowledgement */
773	case ADSP_CTL_OACK:	/* Open Request acknowledgment */
774	case ADSP_CTL_ODENY:	/* Open Request denial */
775	    if (RXConnection(gref, &sp, f, len, a, dsoc))
776		goto ignore;
777	    break;
778
779	case ADSP_CTL_CLOSE:	/* Close connection advice */
780	    if (sp) {
781		/* This pkt may also ack some data we sent */
782		CheckRecvSeq(sp, f);
783		RxClose(sp);
784		sp = 0;
785	    } else
786		goto ignore;
787	    break;
788
789	case ADSP_CTL_FRESET:	/* Forward Reset */
790				/* May I rot in hell for the code below... */
791	    if (sp && (CheckRecvSeq(sp, f), RXFReset(sp, f)))
792		goto ignore;
793	    break;
794
795	case ADSP_CTL_FRESET_ACK: /* Forward Reset Acknowledgement */
796	    if (sp && (CheckRecvSeq(sp, f), RXFResetAck(sp, f)))
797		goto ignore;
798	    break;
799
800	case ADSP_CTL_RETRANSMIT: /* Retransmit advice */
801	    if (sp) {
802		/* This pkt may also ack some data we sent */
803		CheckRecvSeq(sp, f);
804		RemoveTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer);
805		sp->sendSeq = sp->firstRtmtSeq;
806		sp->pktSendCnt = 0;
807		sp->waitingAck = 0;
808		sp->callSend = 1;
809	    } else
810		goto ignore;
811	    break;
812
813	default:
814	    goto ignore;
815	}			/* switch */
816    }				/* Control packet */
817
818    else {			/* Data Packet */
819	if ((sp == 0) || RXData(sp, mp, f, len))
820	    goto ignore;
821	else
822	    mp = 0;		/* RXData used up the data, DONT free it! */
823    }				/* Data Packet */
824
825    if (mp)
826	gbuf_freem(mp);
827
828	/* incoming data was not ignored */
829    if (sp && sp->callSend)	/* If we have a stream & we need to send */
830	CheckSend(sp);
831
832    return 0;
833
834ignore:
835    gbuf_freem(mp);
836    return 0;
837}
838