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