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