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