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