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