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