]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/adsp_Control.c
xnu-1228.3.13.tar.gz
[apple/xnu.git] / bsd / netat / adsp_Control.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * Copyright (c) 1990, 1995-1998 Apple Computer, Inc.
30 * All Rights Reserved.
31 */
32
33/* Control.c
34 * From Mike Shoemaker v01.25 07/02/90 for MacOS
35 * 09/07/95 - Modified for performance (Tuyen Nguyen)
36 * Modified for MP, 1996 by Tuyen Nguyen
37 * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
38 */
39
40#include <sys/errno.h>
41#include <sys/types.h>
42#include <sys/param.h>
43#include <machine/spl.h>
44#include <sys/systm.h>
45#include <sys/kernel.h>
46#include <sys/proc.h>
47#include <sys/filedesc.h>
48#include <sys/fcntl.h>
49#include <sys/mbuf.h>
50#include <sys/time.h>
51#include <sys/socket.h>
52
53#include <netat/sysglue.h>
54#include <netat/appletalk.h>
55#include <netat/ddp.h>
56#include <netat/at_pcb.h>
57#include <netat/debug.h>
58#include <netat/adsp.h>
59#include <netat/adsp_internal.h>
60
61/* # of additional ticks to add to any timer that we're queuing up. For
62 * very short delays (1 and 2), the timer fires before the transmit
63 * even takes place */
64#define TX_DLY 2
65
66int adsp_window = 1;
67
2d21ac55
A
68int attachData(CCBPtr, gbuf_t *mp);
69
1c79356b
A
70/*
71 * CalcRecvWdw
72 *
73 * INPUTS:
74 * sp ADSP Stream
75 * OUTPUTS:
76 * # of bytes in avail in local receive queue
77 */
78int CalcRecvWdw(sp) /* (CCBPtr sp) */
79 CCBPtr sp;
80{
81 int bytes;
82
83 bytes = calcRecvQ(sp);
84 bytes = sp->rbuflen - bytes; /* get what is left */
85
2d21ac55 86 if ((bytes <= 16)) { /* %%% this should be zero */
1c79356b
A
87 sp->rbufFull = 1; /* Save flag that our recv buf is full */
88 return 0;
89 }
90 else
91 return ((bytes+bytes+bytes) >> 2) + 1; /* %%% */
92}
93
2d21ac55 94int
1c79356b
A
95calcRecvQ(sp)
96 CCBPtr sp;
97{
98 int bytes = 0;
99#ifdef AT_Socket
100 register struct mbuf *m, *p;
101
102 if (((sp->gref)->so)->so_rcv.sb_mb)
103 for (p = ((sp->gref)->so)->so_rcv.sb_mb; p; p = p->m_nextpkt)
104 for (m = p; m; m = m->m_next)
105 bytes += m->m_len;
106#else
107 register gbuf_t *mb;
108
109 if (sp->rData) { /* There is data in buffer */
2d21ac55 110 if ((mb = sp->rbuf_mb)) {
1c79356b
A
111 do {
112 bytes += gbuf_msgsize(mb);
113 mb = gbuf_next(mb);
114 } while (mb);
115 }
2d21ac55 116 if ((mb = sp->crbuf_mb))
1c79356b
A
117 bytes += gbuf_msgsize(mb);
118 }
119#endif
120 return bytes;
121}
122
123/*
124 * CheckSend
125 *
126 * Check to see if the transmit PB is available and if there is anything
127 * to transmit. Start off any pending transmit.
128 *
129 * Normally called from the write completion routine
130 *
131 * INPUTS:
132 * sp Connection control block
133 * OUTPUTS:
134 * true if sent a packet
135 */
136void CheckSend(sp) /* (CCBPtr sp) */
137 register CCBPtr sp;
138{
139 int i;
140 int attnMsg; /* True if attention message */
1c79356b
A
141 register gbuf_t *mp; /* send message block */
142#ifdef notdef
143 register gbuf_t *tmp;
144 u_char current;
145#endif
146 char *dp; /* a data pointer */
147 int use_attention_code;
148 int len; /* length used in allocd mblk */
149 int datalen; /* amount of data attached to mblk */
2d21ac55 150 gbuf_t *mprev = 0, *mlist = 0;
1c79356b
A
151
152top:
153
154 if (sp->state == sClosed)
155 return;
156
157 /* get a message block to hold DDP and
158 * ADSP headers + 2 bytes of attention
159 * code if necessary */
160 if ((mp = gbuf_alloc(AT_WR_OFFSET + DDPL_FRAME_LEN + ADSP_FRAME_LEN + ADSP_OPEN_FRAME_LEN + 2,
161 PRI_LO)) == 0) {
162 if (mlist)
163 gbuf_freel(mlist);
164 return; /* can't get buffers... do nothing! */
165 }
1c79356b
A
166 sp->callSend = 0; /* Clear flag */
167 use_attention_code = 0;
168 len = 0;
169 datalen = 0;
170
171 gbuf_rinc(mp,AT_WR_OFFSET);
172 gbuf_wset(mp,DDPL_FRAME_LEN); /* leave room for DDP header */
173
174 if (sp->sendCtl) {
91447636 175 short mask = 0;
1c79356b
A
176
177 i = sp->sendCtl; /* get local copy bitmap of */
178 /* which ctl packets to send. */
179 attnMsg = 0;
180
181 if (i & 0x1E) /* One of the open ctrl packets */
182 {
183
184 /* point past ADSP header (no attention) */
185 dp = ((char *) gbuf_wptr(mp)) + ADSP_FRAME_LEN;
0c530ab8 186 UAL_ASSIGN_HTON(sp->f.pktFirstByteSeq, sp->firstRtmtSeq);
1c79356b 187
0c530ab8
A
188 UAS_ASSIGN_HTON(sp->of.version, netw(0x0100)); /* Fill in open connection parms */
189 UAS_ASSIGN_HTON(sp->of.dstCID, sp->remCID); /* Destination CID */
190 UAL_ASSIGN_HTON(sp->of.pktAttnRecvSeq, sp->attnRecvSeq);
1c79356b
A
191 bcopy((caddr_t) &sp->of, (caddr_t) dp, ADSP_OPEN_FRAME_LEN);
192 len += ADSP_OPEN_FRAME_LEN;
193
194 if (i & B_CTL_OREQ) {
0c530ab8 195 UAS_ASSIGN_HTON(sp->f.CID, sp->locCID);
1c79356b
A
196 mask = B_CTL_OREQ;
197 sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OREQ;
198 } else if (i & B_CTL_OACK) {
0c530ab8 199 UAS_ASSIGN_HTON(sp->f.CID, sp->locCID);
1c79356b
A
200 mask = B_CTL_OACK;
201 sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OACK;
202 } else if (i & B_CTL_OREQACK) {
0c530ab8 203 UAS_ASSIGN_HTON(sp->f.CID, sp->locCID);
1c79356b
A
204 mask = B_CTL_OREQACK;
205 sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_OREQACK;
206 } else /* Deny */
207 {
208 UAS_ASSIGN(sp->f.CID, 0);
209 mask = B_CTL_ODENY;
210 sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_ODENY;
211 UAL_ASSIGN(sp->f.pktFirstByteSeq, 0);
212 }
213
214 if (i & (B_CTL_OREQ | B_CTL_OREQACK))
215 /* Need to start up a timer for it */
216 {
217 /* It's possible that we've received a duplicate
218 * open request. In this case, there will already be
219 * a timer queued up for the request+ack
220 * packet we sent the first time. So remove the timer
221 * and start another.
222 */
223 RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
224 InsertTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer,
225 sp->openInterval+1);
226 }
227 } else {
228 /* seq # of next byte to send */
0c530ab8 229 UAL_ASSIGN_HTON(sp->f.pktFirstByteSeq, sp->sendSeq);
1c79356b
A
230
231 if (i & B_CTL_CLOSE) {
232 sp->state = sClosed; /* Now we're closed */
233 mask = B_CTL_CLOSE;
234 sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_CLOSE;
235 } else if (i & B_CTL_PROBE) {
236 mask = B_CTL_PROBE;
237 sp->f.descriptor =
238 ADSP_CONTROL_BIT | ADSP_CTL_PROBE | ADSP_ACK_REQ_BIT;
239 } else if (i & B_CTL_FRESET) {
240 mask = B_CTL_FRESET;
241 sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_FRESET;
242 InsertTimerElem(&adspGlobal.fastTimers,
243 &sp->ResetTimer, sp->rtmtInterval+TX_DLY);
244 } else if (i & B_CTL_FRESETACK) {
245 mask = B_CTL_FRESETACK;
246 sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_FRESET_ACK;
247 }
248 else if (i & B_CTL_RETRANSMIT) {
249 mask = B_CTL_RETRANSMIT;
250 sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_CTL_RETRANSMIT;
251 }
252 else {
253 dPrintf(D_M_ADSP, D_L_ERROR, ("CheckSend: Control bit error\n"));
254 }
255 } /* non open control packet */
256
257 sp->sendCtl &= ~mask;
258 goto sendit;
259 } /* send control packet */
260
261 if (sp->sendAttnData) /* Send attn ready to go? */
262 {
263 sp->sendAttnData = 0; /* Clear Flags */
264 if (sp->sapb) {
265 sp->sendAttnAck = 0; /* This will also do an Attn Ack */
266
267 attnMsg = 1;
268 sp->f.descriptor = ADSP_ATTENTION_BIT | ADSP_ACK_REQ_BIT;
269 if (gbuf_cont(sp->sapb->mp)) {
270 gbuf_cont(mp) = gbuf_dupm(gbuf_cont(sp->sapb->mp));
271 /* Major hack here. The ADSP Attn code is butted up against
272 * the end of the adsp packet header, and the length is
273 * increased by 2. (There is a pad field behind the adsp
274 * header in the CCB just for this purpose.)
275 */
276 }
277 use_attention_code++;
278
279 sp->f.data[0] = high(sp->sapb->u.attnParams.attnCode);
280 sp->f.data[1] = low(sp->sapb->u.attnParams.attnCode);
281 InsertTimerElem(&adspGlobal.fastTimers, &sp->AttnTimer,
282 sp->rtmtInterval+TX_DLY);
283 goto sendit;
284 }
285 } /* attn data */
286
287 if (sp->sendAttnAck) /* Send attn ack ready to go? */
288 {
289 attnMsg = 1;
290 sp->f.descriptor = ADSP_CONTROL_BIT | ADSP_ATTENTION_BIT;
291 sp->sendAttnAck = 0;
292 goto sendit;
293 } /* attn ack */
294
295 if ((sp->state == sOpen || sp->state == sClosing) && /* Correct state */
296 (!sp->waitingAck) && /* not waiting for an ACK */
297 (sp->sData) && /* have data to send */
298 (GTE(sp->sendWdwSeq,sp->sendSeq)) && /* he has room to accept it */
299 (sp->pktSendCnt < sp->pktSendMax)) /* haven't sent too many pkts
300 * in a row. */
301 {
302 attnMsg = 0;
2d21ac55 303 if ((datalen = attachData(sp, mp))) /* attach data to mp */
1c79356b
A
304 goto sendit; /* if successful, sendit */
305 }
306
307 if (sp->sendDataAck) {
0c530ab8 308 UAL_ASSIGN_HTON(sp->f.pktFirstByteSeq, sp->sendSeq); /* seq # of next byte */
1c79356b
A
309 attnMsg = 0;
310 sp->f.descriptor = ADSP_CONTROL_BIT;
311 goto sendit;
312 }
313
314 /*
315 * Nothing left to do...
316 */
317 if (mp)
318 gbuf_freem(mp);
1c79356b
A
319 if (mlist)
320 adsp_sendddp(sp, mlist, 0, &sp->remoteAddress, DDP_ADSP);
321 return;
322
323sendit:
324
325 if (attnMsg) {
0c530ab8
A
326 UAL_ASSIGN_HTON(sp->f.pktFirstByteSeq, sp->attnSendSeq);
327 UAL_ASSIGN_HTON(sp->f.pktNextRecvSeq, sp->attnRecvSeq);
1c79356b
A
328 UAS_ASSIGN(sp->f.pktRecvWdw, 0); /* Always zero in attn pkt */
329 } else {
330 sp->sendDataAck = 0;
0c530ab8
A
331 UAL_ASSIGN_HTON(sp->f.pktNextRecvSeq, sp->recvSeq);
332 UAS_ASSIGN_HTON(sp->f.pktRecvWdw, CalcRecvWdw(sp));
1c79356b
A
333 }
334 if (use_attention_code) {
335 bcopy((caddr_t) &sp->f, (caddr_t) gbuf_wptr(mp), ADSP_FRAME_LEN + 2);
336 len += ADSP_FRAME_LEN + 2;
337 } else {
338 bcopy((caddr_t) &sp->f, (caddr_t) gbuf_wptr(mp), ADSP_FRAME_LEN);
339 len += ADSP_FRAME_LEN;
340 }
341 gbuf_winc(mp,len); /* update mblk length */
342 if (mlist)
343 gbuf_next(mprev) = mp;
344 else
345 mlist = mp;
346 mprev = mp;
347
348 if (sp->state == sClosed) { /* must have sent a close advice */
349 /* send header + data */
1c79356b
A
350 adsp_sendddp(sp, mlist, 0, &sp->remoteAddress, DDP_ADSP);
351 DoClose(sp, 0, -1); /* complete close! */
352 return;
353 }
1c79356b
A
354 if (sp->state == sClosing) /* See if we were waiting on this write */
355 CheckOkToClose(sp);
356 goto top;
357}
358
359/*
360 * completepb delivers a paramater block with all its appropriate fields
361 * set back to the user.
362 *
363 * The assumptions here are that the PB is not linked to any queue,
364 * that the fields including ioResult are set, and that the
365 * kernel is no longer interested in the mblks that may or
366 * maynot be linked to this pb.
367 */
368void completepb(sp, pb)
369 register CCBPtr sp;
370 register struct adspcmd *pb;
371{
372 if (sp->gref && (sp->gref->info == (caddr_t)sp->sp_mp)) {
373 if (gbuf_len(pb->mp) > sizeof(struct adspcmd))
374 gbuf_wset(pb->mp,sizeof(struct adspcmd));
375 SndMsgUp(sp->gref, pb->mp);
376 NotifyUser(sp);
377 } else
378 gbuf_freem(pb->mp);
379}
380
2d21ac55
A
381
382int
1c79356b
A
383attachData(sp, mp)
384 register CCBPtr sp;
385 register gbuf_t *mp;
386{
387 int seq;
388 int cnt;
389 char eom = 0;
390 int bsize;
391 int diff;
392 char sendAckReq;
393 int partial = 0; /* flag for a partial send */
394 int tcnt = 0;
395 register gbuf_t *smp; /* send data message block */
396 register gbuf_t *psmp; /* previous message block */
397
398 sendAckReq = 0;
399
400 if (LT(sp->sendSeq, sp->firstRtmtSeq)) /* Sanity check on send seq */
401 sp->sendSeq = sp->firstRtmtSeq; /* seq must be oldest in buffer. */
402
403 /* This test and assignment was necessary because the retry VBL could
404 * have fired and reset send Seq to first Rtmt Seq, and then an
405 * expected ACK comes in that bumps first Rtmt Seq up. Then we
406 * have the problem that send Seq is less than first Rtmt Seq.
407 * The easiest fix to this timing dilemma seems to be to reset
408 * sendSeq to first Rtmt Seq if we're sending the first packet.
409 */
0c530ab8 410 UAL_ASSIGN_HTON(sp->f.pktFirstByteSeq, sp->sendSeq);
1c79356b 411
2d21ac55 412 if ((smp = sp->sbuf_mb)) /* Get oldest header */
1c79356b 413 eom = 1;
2d21ac55 414 else if ((smp = sp->csbuf_mb))
1c79356b
A
415 eom = 0;
416
417 if (smp == 0) { /* this shouldn't happen... */
418 sp->sData = 0;
419 return 0;
420 }
421 /*
422 * Must find next byte to transmit
423 */
424 seq = sp->firstRtmtSeq; /* Seq # of oldest in buffer */
425 while ((diff = (sp->sendSeq - seq)) >= ((bsize = gbuf_msgsize(smp)) + eom)) {
426 seq += bsize + eom; /* update sequence # */
427 if (gbuf_next(smp)) { /* if another send buffer */
428 smp = gbuf_next(smp);
429 eom = 1;
430 } else if (smp == sp->csbuf_mb) { /* seen the current one? */
431 smp = 0;
432 break;
433 } else if (sp->csbuf_mb) { /* look at it */
434 smp = sp->csbuf_mb;
435 eom = 0;
436 } else { /* no more buffers */
437 smp = 0;
438 break;
439 }
440 } /* while */
441
442 if (smp) {
443 if (gbuf_next(smp) == 0) /* last block */
444 sendAckReq = 1;
445 cnt = bsize - diff; /* # of bytes in this block */
446 } else
447 cnt = 0;
448
449 /*
450 * Check to see if the number of bytes is less than the 'send
451 * Blocking' setting. If so, then we won't send this data unless
452 * we're flushing. So we set up a timer to force a flush later.
453 */
454 if ((cnt < sp->sendBlocking) && !sp->writeFlush) {
455 InsertTimerElem(&adspGlobal.fastTimers, &sp->FlushTimer,
456 sp->sendInterval);
457 return 0; /* no data to send */
458 }
459
460 if (cnt > ADSP_MAX_DATA_LEN) { /* truncate to one packet */
461 cnt = ADSP_MAX_DATA_LEN;
462 eom = 0;
463 sendAckReq = 0; /* Won't send ack because end of data */
464 partial++;
465 }
466
467 if (smp) {
468 /* trim extra bytes off the beginning of the "block" before the copy */
469 while (diff) {
470 if (gbuf_len(smp) > diff)
471 break;
472 else
473 diff -= gbuf_len(smp);
474 smp = gbuf_cont(smp);
475 }
476 if((gbuf_cont(mp) = gbuf_dupm(smp)) == 0) /* copy the data */
477 return 0;
478 smp = gbuf_cont(mp); /* use the new message blocks */
479 gbuf_rinc(smp,diff); /* and get to the first byte of data to send */
480 }
481 /*
482 * Check to see if this many bytes will close the other end's
483 * receive window. If so, we need to send an ack request along
484 * with this. sendWdwSeq is the seq # of the last byte that
485 * the remote has room for
486 */
487 if ((diff = sp->sendWdwSeq + 1 - sp->sendSeq) <= cnt) {
488 if (diff < cnt) { /* Won't fit exactly */
489 eom = 0; /* so can't send EOM */
490 cnt = diff;
491 partial++;
492 }
493 sendAckReq = 1; /* Make him tell us new recv. window */
494 sp->noXmitFlow = 1; /* Don't do flow control calc. */
495 }
496
497 /* trim extra bytes off the tail of the "block" after the copy */
498 if (partial && smp) {
499 psmp = smp;
500 tcnt = cnt;
501 while (tcnt && smp) { /* while there are message blocks and data */
502 if (tcnt >= gbuf_len(smp)) {
503 tcnt -= gbuf_len(smp);
504 if (tcnt) {
505 psmp = smp;
506 smp = gbuf_cont(smp);
507 } else {
508 if (psmp != smp) { /* not the first item on the list */
509 gbuf_cont(psmp) = 0;
510 gbuf_freem(smp);
511 smp = psmp;
512 } else {
513 gbuf_freem(gbuf_cont(smp));
514 gbuf_cont(smp) = 0;
515 }
516 break;
517 }
518 } else {
519 gbuf_wset(smp,tcnt);
520 if (gbuf_cont(smp)) {
521 gbuf_freem(gbuf_cont(smp));
522 gbuf_cont(smp) = 0;
523 }
524 break;
525 }
526 }
527 }
528
529 sp->sendSeq += cnt + eom; /* Update sendSeq field */
530
531 if (GT(sp->sendSeq, sp->maxSendSeq)) /* Keep track of >st ever sent */
532 sp->maxSendSeq = sp->sendSeq;
533
534 if (eom)
535 sp->f.descriptor = ADSP_EOM_BIT;
536 else
537 sp->f.descriptor = 0;
538
539 if (sendAckReq || (++sp->pktSendCnt >= sp->pktSendMax)) {
540 /* Last packet in a series */
541 sp->f.descriptor |= ADSP_ACK_REQ_BIT; /* We want an ack to this */
542 sp->waitingAck = 1; /* Flag that we're waiting */
543 sp->sendStamp = SysTicks(); /* Save time we sent request */
544 sp->timerSeq = sp->sendSeq; /* Save seq # we want acked */
545 InsertTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer,
546 sp->rtmtInterval+TX_DLY);
547 }
548 return cnt + eom;
549}
550
551
552