]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netat/adsp_Packet.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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.
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>
43 #include <sys/filedesc.h>
44 #include <sys/fcntl.h>
46 #include <sys/ioctl.h>
47 #include <sys/malloc.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
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>
60 #include <netat/adsp.h>
61 #include <netat/adsp_internal.h>
63 extern at_ifaddr_t
*ifID_home
;
68 * We just got a packet for this session, glean its address &
76 static void GleanSession(sp
) /* (CCBPtr sp) */
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
,
91 * The same code handles incoming Open Connection Request,
92 * Open Request + Ack, Open Connection Ack, Open Connection Denial
94 * We could be in four different states, LISTEN, OPENWAIT, ESTABLISHED,
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)
103 * Build a table of actions:
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)
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
120 char openState
; /* Next Open state */
121 char state
; /* Next ccb state. */
122 char pad
; /* Too bad we need this to make structure
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 */
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
139 #define A_GLEAN 0x08 /* We'll be talking back to this guy */
140 #define A_DENY 0x10 /* We've been denied! */
144 * So here's our table
147 static TBL tbl
[16] = {
150 * For Open Request ($81)
153 * Match on destination socket
154 * Match on address filter
157 * Save Open Connection parameters
159 * Change state to ESTABLISHED
161 { M_LSOC
+ M_DCIDZERO
+ M_FILTER
,
162 A_SAVEPARMS
+ A_GLEAN
,
172 * Match on Remote Address & destination socket
174 * Save Open Connection parameters
176 * Change state to ESTABLISHED
178 { M_LSOC
+ M_ADDR
+ M_DCIDZERO
,
179 A_SAVEPARMS
+ A_GLEAN
,
188 * Match on Remote Address & SrcCID
192 { M_ADDR
+ M_SCID
+ M_DCIDZERO
,
240 * Match on SrcCID & DestCID & Address & Local Socket
241 * Complete Listen or Connect PB
244 { M_ADDR
+ M_DCID
+ M_SCID
+ M_LSOC
,
245 A_COMPLETE
+ A_GLEAN
,
266 * For Open Request + Ack ($83)
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
290 A_COMPLETE
+ A_SAVEPARMS
+ A_GLEAN
,
311 * Match on Remote Address & SrcCID & DestCID & Local Socket
312 * If we've never gotten any data
313 * Send Ack & Retransmit
315 { M_ADDR
+ M_DCID
+ M_SCID
+ M_LSOC
,
316 A_OREQACKOPEN
+ A_GLEAN
,
326 * For Open Deny ($84)
341 * Match on DestCID & Address
342 * Source CID must be 0
343 * Complete with error
345 { M_SCIDZERO
+ M_DCID
+ M_ADDR
,
363 }, /* %%% No we probably don't want to ignore in this case */
378 extern at_ifaddr_t
*ifID_table
[];
381 * Used to search down queue of sessions for a session waiting for an
390 byte idx
; /* Index into state tables */
391 TBLPtr t
; /* Ptr to entry in table above */
397 * Called by Rx connection to find which stream (if any) should get this open
398 * request/ack/req+ack/deny packet.
403 MatchStream(sp
, m
) /* (CCBPtr sp, MATCHPtr m) */
410 if (sp
->openState
< O_STATE_LISTEN
||
411 sp
->openState
> O_STATE_OPEN
)
415 m
->t
= &tbl
[sp
->openState
- O_STATE_LISTEN
+ m
->idx
];
417 match
= m
->t
->match
; /* Get match criteria */
419 if (match
& M_IGNORE
) /* Ignore this combination */
422 if (match
& M_LSOC
) { /* Match on Local socket */
423 if (sp
->localSocket
!= m
->socket
)
427 if (match
& M_ADDR
) { /* Match on Address */
429 addr
= m
->addr
; /* Make local copy for efficiency */
430 if (sp
->remoteAddress
.a
.node
!= addr
.a
.node
)
432 if (sp
->remoteAddress
.a
.socket
!= addr
.a
.socket
)
434 if (sp
->remoteAddress
.a
.net
&& addr
.a
.net
&&
435 (sp
->remoteAddress
.a
.net
!= addr
.a
.net
))
439 * Handle special case to reject self-sent open request
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
)) )
448 (NET_VALUE(ddpcfg.node_addr.net) == 0) ||
449 (NET_VALUE(ddpcfg.node_addr.net) == NET_VALUE(addr.a.net))) )
451 /* CID's match, and */
452 /* If nodeID matches, and */
453 /* network matches, */
454 return 0; /* then came from us! */
457 if (match
& M_DCID
) { /* Match on DestCID */
458 if (sp
->locCID
!= m
->dstCID
)
462 if (match
& M_SCID
) { /* Match on SourceCID */
463 if (sp
->remCID
!= m
->srcCID
)
467 if (match
& M_DCIDZERO
) { /* Destination CID must be 0 */
472 if (match
& M_SCIDZERO
) /* Source CID must be 0 */
478 if (match
& M_FILTER
) { /* Check address filter? */
479 if ((opb
= sp
->opb
)) /* There should be a param block... */
482 addr
= m
->addr
; /* Make local copy for efficiency */
483 if ((opb
->u
.openParams
.filterAddress
.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
))
500 * Called by rx connection to see which connection listener (if any) should
501 * get this incoming open connection request.
505 static boolean
MatchListener(sp
, m
) /* (CCBPtr sp, MATCHPtr m) */
510 if ((sp
->state
== (word
)sListening
) && /* This CCB is a listener */
511 (sp
->localSocket
== m
->socket
)) /* on the right socket */
520 * We just received one of the 4 Open Connection packets
521 * Interrupts are masked OFF at this point
524 * spPtr Place to put ptr to stream (if we found one -- not
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
532 * Returns 1 if packet was ignored
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 */
544 ADSP_OPEN_DATAPtr op
;
549 ADSP_OPEN_DATAPtr adspop
;
552 op
= (ADSP_OPEN_DATAPtr
)&f
->data
[0]; /* Point to Open-Connection parms */
553 len
-= ADSP_FRAME_LEN
;
555 if (len
< (sizeof(ADSP_OPEN_DATA
))) /* Packet too small */
559 if (UAS_VALUE(op
->version
) != netw(0x0100)) { /* Check version num (on even-byte) */
561 * The open request has been denied. Try to send him a denial.
564 mp
= gbuf_alloc(AT_WR_OFFSET
+ DDPL_FRAME_LEN
+ ADSP_FRAME_LEN
+ ADSP_OPEN_FRAME_LEN
,
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
);
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;
590 * See if we can find a stream that knows what to do with this packet
592 if ((sp
= (CCBPtr
)qfind_m(AT_ADSP_STREAMS
, &m
, (ProcPtr
)MatchStream
)) == 0)
597 * No match, so look for connection listeners if this is an
600 if ((f
->descriptor
& ADSP_CONTROL_MASK
) != (byte
)ADSP_CTL_OREQ
)
603 if ((sp
= (CCBPtr
)qfind_m(AT_ADSP_STREAMS
, &m
,
604 (ProcPtr
)MatchListener
)) == 0)
607 ATDISABLE(s
, sp
->lock
);
608 p
= (struct adspcmd
*)&sp
->opb
;
609 while (n
= (struct adspcmd
*)p
->qLink
) /* Hunt down list of listens */
611 /* Check address filter */
612 if (((n
->u
.openParams
.filterAddress
.net
== 0) ||
614 (n
->u
.openParams
.filterAddress
.net
== addr
.a
.net
)) &&
616 ((n
->u
.openParams
.filterAddress
.node
== 0) ||
617 (n
->u
.openParams
.filterAddress
.node
== addr
.a
.node
)) &&
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
));
628 ATENABLE(s
, sp
->lock
);
629 completepb(sp
, n
); /* complete copy of request */
630 /* complete(n, 0); */
632 } /* found CLListen */
634 p
= n
; /* down the list we go... */
638 ATENABLE(s
, sp
->lock
);
642 *spPtr
= sp
; /* Save ptr to stream we just found */
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) */
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 */
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 */
657 sp
->remoteAddress
= addr
; /* Save his address */
660 ATENABLE(s
, sp
->lock
);
662 if (m
.t
->action
& A_DENY
) { /* We've been denied ! */
663 DoClose(sp
, errOpenDenied
, -1);
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
;
676 if (m
.t
->send
) { /* Need to send a response */
677 sp
->sendCtl
|= m
.t
->send
;
681 if (m
.t
->action
& A_COMPLETE
) { /* Need to complete open param blk */
682 RemoveTimerElem(&adspGlobal
.slowTimers
, &sp
->ProbeTimer
);
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
;
694 completepb(sp
, pb
); /* complete(pb, 0); */
697 /* Start probe timer */
698 InsertTimerElem(&adspGlobal
.slowTimers
, &sp
->ProbeTimer
,
707 * When a packet is received by the protocol stack with DDP type equal
708 * to ADSP, then execution comes here
710 * DS is set to ATALK's DGROUP
712 * This routine, or one of its children MUST call glean packet
715 * Pointer to DDP header
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.
725 int adspPacket(gref
, mp
)
726 /* (bytePtr data, word len, AddrUnion a, byte dsoc) */
735 register DDPX_FRAME
*ddp
; /* DDP frame pointer */
736 register ADSP_FRAMEPtr f
; /* Frame */
739 sp
= 0; /* No stream */
740 bp
= (unsigned char *)gbuf_rptr(mp
);
741 ddp
= (DDPX_FRAME
*)bp
;
742 if (ddp
->ddpx_type
!= DDP_ADSP
)
744 f
= (ADSP_FRAMEPtr
)(bp
+ DDPL_FRAME_LEN
);
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 */
751 a
.a
.net
= NET_VALUE(ddp
->ddpx_snet
);
752 a
.a
.node
= ddp
->ddpx_snode
;
753 a
.a
.socket
= ddp
->ddpx_source
;
755 dsoc
= ddp
->ddpx_dest
;
757 if (sp
= (CCBPtr
)FindSender(f
, a
))
760 if (f
->descriptor
& ADSP_ATTENTION_BIT
) { /* ATTN packet */
761 if (sp
&& RXAttention(sp
, mp
, f
, len
))
764 mp
= 0; /* attention data is being held */
765 } /* ATTENTION BIT */
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 */
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
))
782 case ADSP_CTL_CLOSE
: /* Close connection advice */
784 /* This pkt may also ack some data we sent */
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
)))
798 case ADSP_CTL_FRESET_ACK
: /* Forward Reset Acknowledgement */
799 if (sp
&& (CheckRecvSeq(sp
, f
), RXFResetAck(sp
, f
)))
803 case ADSP_CTL_RETRANSMIT
: /* Retransmit advice */
805 /* This pkt may also ack some data we sent */
807 RemoveTimerElem(&adspGlobal
.fastTimers
, &sp
->RetryTimer
);
808 ATDISABLE(s
, sp
->lock
);
809 sp
->sendSeq
= sp
->firstRtmtSeq
;
813 ATENABLE(s
, sp
->lock
);
821 } /* Control packet */
823 else { /* Data Packet */
824 if ((sp
== 0) || RXData(sp
, mp
, f
, len
))
827 mp
= 0; /* RXData used up the data, DONT free it! */
833 checksend
: /* incoming data was not ignored */
834 if (sp
&& sp
->callSend
) /* If we have a stream & we need to send */