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