]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/adsp_stream.c
xnu-344.tar.gz
[apple/xnu.git] / bsd / netat / adsp_stream.c
CommitLineData
1c79356b
A
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 * Copyright (c) 1995-1998 Apple Computer, Inc.
24 * All Rights Reserved.
25 */
26
27/*
28 * 09/07/95 - Modified for performance (Tuyen Nguyen)
29 * Modified for MP, 1996 by Tuyen Nguyen
30 * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
31 */
32#include <sys/errno.h>
33#include <sys/types.h>
34#include <sys/param.h>
35#include <machine/spl.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/proc.h>
39#include <sys/filedesc.h>
40#include <sys/fcntl.h>
41#include <sys/mbuf.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/time.h>
45#include <sys/ioctl.h>
46#include <sys/malloc.h>
47
48#include <net/if.h>
49
50#include <netat/sysglue.h>
51#include <netat/appletalk.h>
52#include <netat/ddp.h>
53#include <netat/at_snmp.h>
54#include <netat/at_pcb.h>
55#include <netat/debug.h>
56#include <netat/at_var.h>
57#include <netat/adsp.h>
58#include <netat/adsp_internal.h>
59
60void SndMsgUp();
61void adsp_rput();
62static void adsp_iocack();
63static void adsp_iocnak();
64void adsp_dequeue_ccb();
65unsigned char adspAssignSocket();
66int adspallocate(), adsprelease();
67int adspInited = 0;
68
69atlock_t adspall_lock;
70atlock_t adspgen_lock;
71GLOBAL adspGlobal;
72
73/**********/
74
75int adsp_pidM[256];
76char adsp_inputC[256];
77CCB *adsp_inputQ[256];
78
79extern at_ifaddr_t *ifID_home;
80
81CCB *ccb_used_list;
82
83void adsp_input(mp)
84 gbuf_t *mp;
85{
86 gref_t *gref;
87 CCBPtr sp;
88 at_ddp_t *p;
89 int s, l;
90 gbuf_t *mb;
91
92 switch (gbuf_type(mp)) {
93 case MSG_DATA:
94 p = (at_ddp_t *)gbuf_rptr(mp);
95 ATDISABLE(s, adspall_lock);
96 sp = adsp_inputQ[p->dst_socket];
97 if ((sp == 0) || (sp->gref==0) || (sp->state==sClosed))
98 {
99 ATENABLE(s, adspall_lock);
100 gbuf_freem(mp);
101 return;
102 }
103 else if (sp->otccbLink != 0) {
104 do {
105 if ((sp->remoteAddress.a.node == p->src_node)
106 && (sp->remoteAddress.a.socket == p->src_socket)
107 && (sp->remoteAddress.a.net == NET_VALUE(p->src_net)))
108 break;
109 } while ((sp = sp->otccbLink) != 0);
110 if (sp == 0)
111 {
112 ATENABLE(s, adspall_lock);
113 gbuf_freem(mp);
114 return;
115 }
116 }
117 if (sp->lockFlag) {
118 gbuf_next(mp) = 0;
119 if (sp->deferred_mb) {
120 for (mb=sp->deferred_mb; gbuf_next(mb); mb=gbuf_next(mb)) ;
121 gbuf_next(mb) = mp;
122 } else
123 sp->deferred_mb = mp;
124 ATENABLE(s, adspall_lock);
125 return;
126 }
127 ATDISABLE(l, sp->lockRemove);
128 sp->lockFlag = 1;
129 ATENABLE(l, adspall_lock);
130 while (mp) {
131 adsp_rput(sp->gref, mp);
132 if ((mp = sp->deferred_mb) != 0) {
133 sp->deferred_mb = gbuf_next(mp);
134 gbuf_next(mp) = 0;
135 }
136 }
137 sp->lockFlag = 0;
138 ATENABLE(s, sp->lockRemove);
139 return;
140
141 case MSG_IOCACK:
142 case MSG_IOCNAK:
143 gref = (gref_t *)((ioc_t *)gbuf_rptr(mp))->ioc_private;
144 break;
145
146 case MSG_IOCTL:
147#ifdef APPLETALK_DEBUG
148 kprintf("unexpected MSG_IOCTL in adsp_input()");
149#endif
150 /* fall through */
151
152 default:
153 gbuf_freem(mp);
154 return;
155 }
156
157 adsp_rput(gref, mp);
158}
159
160/**********/
161int adsp_readable(gref)
162 gref_t *gref;
163{
164 int rc;
165 CCBPtr sp;
166
167 if (gref->info == 0)
168 /*
169 * we don't have the structure we need to determine
170 * if there's data available... we return readable in
171 * this case to keep from hanging up in the select
172 * a subsequent read will run into the same missing data
173 * structure and return an error... the ATselect code does
174 * this if it can't retrieve the 'gref' structure from the
175 * file table for the fd specified
176 */
177 return(1);
178
179 sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
180 rc = sp->rData;
181
182 return rc;
183}
184
185int adsp_writeable(gref)
186 gref_t *gref;
187{
188 int s, rc;
189 CCBPtr sp;
190
191 if (gref->info == 0)
192 /*
193 * we don't have the structure we need to determine
194 * if there's room available... we return writeable in
195 * this case to keep from hanging up in the select
196 * a subsequent write will run into the same missing data
197 * structure and return an error... the ATselect code does
198 * this if it can't retrieve the 'gref' structure from the
199 * file table for the fd specified
200 */
201 return(1);
202
203 sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
204 ATDISABLE(s, sp->lock);
205 rc = CalcSendQFree(sp);
206 ATENABLE(s, sp->lock);
207
208 return rc;
209}
210
211static void adsp_init()
212{
213 adspInited++;
214 InitGlobals();
215 ccb_used_list = 0;
216 bzero(adsp_pidM, sizeof(adsp_pidM));
217 bzero(adsp_inputC, sizeof(adsp_inputC));
218 bzero(adsp_inputQ, sizeof(adsp_inputQ));
219}
220
221/*
222 * Description:
223 * ADSP open and close routines. These routines
224 * initalize and release the ADSP structures. They do not
225 * have anything to do with "connections"
226 */
227
228int adsp_open(gref)
229 gref_t *gref;
230{
231 register CCBPtr sp;
232 int s;
233
234 if (!adspInited)
235 adsp_init();
236
237 if (!adspAllocateCCB(gref))
238 return(ENOBUFS); /* can't get buffers */
239
240 sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
241 gref->readable = adsp_readable;
242 gref->writeable = adsp_writeable;
243 ATDISABLE(s, adspall_lock);
244 if ((sp->otccbLink = ccb_used_list) != 0)
245 sp->otccbLink->ccbLink = sp;
246 ccb_used_list = sp;
247 ATENABLE(s, adspall_lock);
248 return 0;
249}
250
251int adsp_close(gref)
252 gref_t *gref;
253{
254 int s, l;
255 unsigned char localSocket;
256
257 /* make sure we've not yet removed the CCB (e.g., due to TrashSession) */
258 ATDISABLE(l, adspgen_lock);
259 if (gref->info) {
260 CCBPtr sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
261 ATDISABLE(s, sp->lock);
262 ATENABLE(s, adspgen_lock);
263 localSocket = sp->localSocket;
264 ATENABLE(l, sp->lock);
265 if (localSocket)
266 adspRelease(gref);
267 else
268 {
269 adsp_dequeue_ccb(sp);
270 gbuf_freeb((gbuf_t *)gref->info);
271 }
272 } else
273 ATENABLE(l, adspgen_lock);
274 return 0;
275}
276
277
278/*
279 * Name:
280 * adsp_rput
281 *
282 * Description:
283 * ADSP streams read put and service routines.
284 */
285
286void adsp_rput(gref, mp)
287 gref_t *gref; /* READ queue */
288 gbuf_t *mp;
289{
290 switch (gbuf_type(mp)) {
291 case MSG_HANGUP:
292 case MSG_IOCACK:
293 case MSG_IOCNAK:
294 switch (adspReadHandler(gref, mp)) {
295 case STR_PUTNEXT:
296 atalk_putnext(gref, mp);
297 break;
298 case STR_IGNORE:
299 break;
300 }
301 break;
302 case MSG_ERROR:
303#ifdef APPLETALK_DEBUG
304 kprintf("adsp_rput received MSG_ERROR");
305#endif
306 /* fall through */
307 default:
308 CheckReadQueue(gbuf_rptr(((gbuf_t *)gref->info)));
309 CheckSend(gbuf_rptr(((gbuf_t *)gref->info)));
310
311 switch (gbuf_type(mp)) {
312 case MSG_IOCTL:
313 case MSG_DATA:
314 case MSG_PROTO:
315 if (adspReadHandler(gref, mp) == STR_PUTNEXT)
316 atalk_putnext(gref, mp);
317 break;
318 default:
319 atalk_putnext(gref, mp);
320 break;
321 }
322 }
323}
324
325/*
326 * Name:
327 * adsp_wput
328 *
329 * Description:
330 * ADSP streams write put and service routines.
331 *
332 */
333
334int adsp_wput(gref, mp)
335 gref_t *gref; /* WRITE queue */
336 gbuf_t *mp;
337{
338 int rc;
339 int s;
340 gbuf_t *xm;
341 ioc_t *iocbp;
fa4905b1
A
342 CCBPtr sp;
343
344 if (gref->info)
345 sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
346 else
347 sp = 0;
1c79356b
A
348
349 if (gbuf_type(mp) == MSG_IOCTL) {
350 iocbp = (ioc_t *)gbuf_rptr(mp);
351 switch (iocbp->ioc_cmd) {
352 case ADSPBINDREQ:
353 {
354 unsigned char v;
355
356 if (gbuf_cont(mp) == NULL) {
357 iocbp->ioc_rval = -1;
358 adsp_iocnak(gref, mp, EINVAL);
359 }
360 v = *(unsigned char *)gbuf_rptr(gbuf_cont(mp));
361 ATDISABLE(s, adspall_lock);
362 if ( (v != 0)
363 && ((v > DDP_SOCKET_LAST) || (v < 2)
364 || ddp_socket_inuse(v, DDP_ADSP))) {
365 ATENABLE(s, adspall_lock);
366 iocbp->ioc_rval = -1;
367 adsp_iocnak(gref, mp, EINVAL);
368 }
369 else {
370 if (v == 0) {
371 ATENABLE(s, adspall_lock);
372 if ((v = adspAssignSocket(gref, 0)) == 0) {
373 iocbp->ioc_rval = -1;
374 adsp_iocnak(gref, mp, EINVAL);
375 return 0;
376 }
377 } else {
378 adsp_inputC[v] = 1;
379 adsp_inputQ[v] = sp;
380 adsp_pidM[v] = sp->pid;
381 ATENABLE(s, adspall_lock);
382 adsp_dequeue_ccb(sp);
383 }
384 *(unsigned char *)gbuf_rptr(gbuf_cont(mp)) = v;
385 sp->localSocket = v;
386 iocbp->ioc_rval = 0;
387 adsp_iocack(gref, mp);
388 }
389 return 0;
390 }
391
392 case ADSPGETSOCK:
393 case ADSPGETPEER:
394 {
395 at_inet_t *addr;
396
397 if (((xm = gbuf_cont(mp)) == NULL)
398 && ((xm = gbuf_alloc(sizeof(at_inet_t), PRI_MED)) == NULL)) {
399 iocbp->ioc_rval = -1;
400 adsp_iocnak(gref, mp, ENOBUFS);
401 return 0;
402 }
403 gbuf_cont(mp) = xm;
404 gbuf_wset(xm,sizeof(at_inet_t));
405 addr = (at_inet_t *)gbuf_rptr(xm);
406 if (iocbp->ioc_cmd == ADSPGETSOCK) {
407 /* Obtain Network and Node Id's from DDP */
408 /* *** was ddp_get_cfg() *** */
409 addr->net = ifID_home->ifThisNode.s_net;
410 addr->node = ifID_home->ifThisNode.s_node;
411 addr->socket = (sp)? sp->localSocket: 0;
412 } else
413 if (sp)
414 *addr = sp->remoteAddress.a;
415 else {
416 addr->net = 0;
417 addr->node = 0;
418 addr->socket = 0;
419 }
420 iocbp->ioc_rval = 0;
421 adsp_iocack(gref, mp);
422 return 0;
423 }
424 case DDP_IOC_GET_CFG:
425 /* respond to an DDP_IOC_GET_CFG sent on an adsp fd */
426 if (((xm = gbuf_cont(mp)) == NULL) &&
9bccf70c 427 (xm = gbuf_alloc(sizeof(ddp_addr_t), PRI_MED)) == NULL) {
1c79356b
A
428 iocbp->ioc_rval = -1;
429 adsp_iocnak(gref, mp, ENOBUFS);
430 return 0;
431 }
432 gbuf_cont(mp) = xm;
433 gbuf_wset(xm, sizeof(ddp_addr_t));
434 /* Obtain Network and Node Id's from DDP */
435 {
436 /* *** was ddp_get_cfg() *** */
437 ddp_addr_t *cfgp =
438 (ddp_addr_t *)gbuf_rptr(gbuf_cont(mp));
439 cfgp->inet.net = ifID_home->ifThisNode.s_net;
440 cfgp->inet.node = ifID_home->ifThisNode.s_node;
441 cfgp->inet.socket = (sp)? sp->localSocket: 0;
442 cfgp->ddptype = DDP_ADSP;
443 }
444 iocbp->ioc_rval = 0;
445 adsp_iocack(gref, mp);
446 return 0;
447 } /* switch */
448 }
449
450 if (!gref->info)
451 gbuf_freem(mp);
452 else {
453 ATDISABLE(s, sp->lockClose);
454 rc = adspWriteHandler(gref, mp);
455 ATENABLE(s, sp->lockClose);
456
457 switch (rc) {
458 case STR_PUTNEXT:
459 if (gbuf_type(mp) == MSG_IOCTL) {
460 iocbp = (ioc_t *)gbuf_rptr(mp);
461 iocbp->ioc_private = (void *)gref;
462 }
463 DDP_OUTPUT(mp);
464 break;
465 case STR_IGNORE:
466 case STR_IGNORE+99:
467 break;
468 default:
469 gbuf_freem(mp);
470 break;
471 }
472 }
473
474 return 0;
475} /* adsp_wput */
476
477void adspioc_ack(errno, m, gref)
478 int errno;
479 gbuf_t *m;
480 gref_t *gref;
481{
482 ioc_t *iocbp;
483
484 if (m == NULL)
485 return;
486 iocbp = (ioc_t *) gbuf_rptr(m);
487
488 iocbp->ioc_error = errno; /* set the errno */
489 iocbp->ioc_count = gbuf_msgsize(gbuf_cont(m));
490 if (gbuf_type(m) == MSG_IOCTL) /* if an ioctl, this is an ack */
491 gbuf_set_type(m, MSG_IOCACK); /* and ALWAYS update the user */
492 /* ioctl structure */
493 trace_mbufs(D_M_ADSP,"A ", m);
494 SndMsgUp(gref, m);
495}
496
497static void adsp_iocack(gref, m)
498 gref_t *gref;
499 register gbuf_t *m;
500{
501 if (gbuf_type(m) == MSG_IOCTL)
502 gbuf_set_type(m, MSG_IOCACK);
503
504 if (gbuf_cont(m))
505 ((ioc_t *)gbuf_rptr(m))->ioc_count = gbuf_msgsize(gbuf_cont(m));
506 else
507 ((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
508
509 SndMsgUp(gref, m);
510}
511
512
513static void adsp_iocnak(gref, m, err)
514 gref_t *gref;
515 register gbuf_t *m;
516 register int err;
517{
518 if (gbuf_type(m) == MSG_IOCTL)
519 gbuf_set_type(m, MSG_IOCNAK);
520 ((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
521
522 if (err == 0)
523 err = ENXIO;
524 ((ioc_t *)gbuf_rptr(m))->ioc_error = err;
525
526 if (gbuf_cont(m)) {
527 gbuf_freem(gbuf_cont(m));
528 gbuf_cont(m) = NULL;
529 }
530 SndMsgUp(gref, m);
531}
532
533unsigned char
534adspAssignSocket(gref, flag)
535 gref_t *gref;
536 int flag;
537{
538 unsigned char sVal, sMax, sMin, sSav, inputC;
539 CCBPtr sp;
540 int s;
541
542 sMax = flag ? DDP_SOCKET_LAST-46 : DDP_SOCKET_LAST-6;
14353aa8 543 sMin = DDP_SOCKET_1st_DYNAMIC;
1c79356b
A
544
545 ATDISABLE(s, adspall_lock);
546 for (inputC=255, sVal=sMax; sVal >= sMin; sVal--) {
547 if (!ddp_socket_inuse(sVal, DDP_ADSP))
548 break;
549 else if (flag) {
550 if (adsp_inputC[sVal] &&
551 /* meaning that raw DDP doesn't have it */
552 (adsp_inputC[sVal] < inputC)
553 && (adsp_inputQ[sVal]->state == sOpen)) {
554 inputC = adsp_inputC[sVal];
555 sSav = sVal;
556 }
557 }
558 }
559 if (sVal < sMin) {
560 if (!flag || (inputC == 255)) {
561 ATENABLE(s, adspall_lock);
562 return 0;
563 }
564 sVal = sSav;
565 }
566 sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
567 ATENABLE(s, adspall_lock);
568 adsp_dequeue_ccb(sp);
569 ATDISABLE(s, adspall_lock);
570 adsp_inputC[sVal]++;
571 sp->otccbLink = adsp_inputQ[sVal];
572 adsp_inputQ[sVal] = sp;
573 if (!flag)
574 adsp_pidM[sVal] = sp->pid;
575 ATENABLE(s, adspall_lock);
576 return sVal;
577}
578
579int
580adspDeassignSocket(sp)
581 CCBPtr sp;
582{
583 unsigned char sVal;
584 CCBPtr curr_sp;
585 CCBPtr prev_sp;
586 int pid = 0;
587 int s, l;
588
589 dPrintf(D_M_ADSP, D_L_TRACE, ("adspDeassignSocket: pid=%d,s=%d\n",
590 sp->pid, sp->localSocket));
591 ATDISABLE(s, adspall_lock);
592 sVal = sp->localSocket;
593 if ((curr_sp = adsp_inputQ[sVal]) != 0) {
594 prev_sp = 0;
595 while (curr_sp != sp) {
596 prev_sp = curr_sp;
597 curr_sp = curr_sp->otccbLink;
598 }
599 if (curr_sp) {
600 ATDISABLE(l, sp->lockRemove);
601 if (prev_sp)
602 prev_sp->otccbLink = sp->otccbLink;
603 else
604 adsp_inputQ[sVal] = sp->otccbLink;
605 ATENABLE(l, sp->lockRemove);
606 if (adsp_inputQ[sVal])
607 adsp_inputC[sVal]--;
608 else {
609 pid = adsp_pidM[sVal];
610 adsp_inputC[sVal] = 0;
611 adsp_pidM[sVal] = 0;
612 }
613 sp->ccbLink = 0;
614 sp->otccbLink = 0;
615 sp->localSocket = 0;
616 ATENABLE(s, adspall_lock);
617 return pid ? 0 : 1;
618 }
619 }
620 ATENABLE(s, adspall_lock);
621
622 dPrintf(D_M_ADSP, D_L_ERROR,
623 ("adspDeassignSocket: closing, no CCB block, trouble ahead\n"));
624 return -1;
625} /* adspDeassignSocket */
626
627/*
628 * remove CCB from the use list
629 */
630void
631adsp_dequeue_ccb(sp)
632 CCB *sp;
633{
634 int s;
635
636 ATDISABLE(s, adspall_lock);
637 if (sp == ccb_used_list) {
638 if ((ccb_used_list = sp->otccbLink) != 0)
639 sp->otccbLink->ccbLink = 0;
640 } else if (sp->ccbLink) {
641 if ((sp->ccbLink->otccbLink = sp->otccbLink) != 0)
642 sp->otccbLink->ccbLink = sp->ccbLink;
643 }
644
645 sp->otccbLink = 0;
646 sp->ccbLink = 0;
647 ATENABLE(s, adspall_lock);
648}
649
650void SndMsgUp(gref, mp)
651 gref_t *gref; /* WRITE queue */
652 gbuf_t *mp;
653{
654/*
655 dPrintf(D_M_ADSP, D_L_TRACE,
656 ("SndMsgUp: gref=0x%x, mbuf=0x%x\n", (unsigned)gref, (unsigned)mp));
657 trace_mbufs(D_M_ADSP, " m", mp);
658*/
659 atalk_putnext(gref, mp);
660}