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