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