1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_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. 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
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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 adsp_rput(gref_t *, gbuf_t *);
67static void adsp_iocack(gref_t *, gbuf_t *);
68static void adsp_iocnak(gref_t *, gbuf_t *, int err);
69void adsp_dequeue_ccb(CCB *);
70int adspInited = 0;
71
72GLOBAL adspGlobal;
73
74/**********/
75
76int adsp_pidM[256];
77char adsp_inputC[256];
78CCB *adsp_inputQ[256];
79
80extern at_ifaddr_t *ifID_home;
81
82CCB *ccb_used_list;
83
84void adsp_input(mp)
85	gbuf_t *mp;
86{
87	gref_t *gref;
88	CCBPtr sp;
89	at_ddp_t *p;
90	gbuf_t *mb;
91
92	switch (gbuf_type(mp)) {
93	case MSG_DATA:
94		p = (at_ddp_t *)gbuf_rptr(mp);
95		sp = adsp_inputQ[p->dst_socket];
96		if ((sp == 0) || (sp->gref==0) || (sp->state==sClosed))
97		{
98			gbuf_freem(mp);
99			return;
100		}
101		else if (sp->otccbLink != 0) {
102			do {
103				if ((sp->remoteAddress.a.node == p->src_node)
104					&& (sp->remoteAddress.a.socket == p->src_socket)
105				&& (sp->remoteAddress.a.net == NET_VALUE(p->src_net)))
106					break;
107			} while ((sp = sp->otccbLink) != 0);
108			if (sp == 0)
109			{
110				gbuf_freem(mp);
111				return;
112			}
113		}
114		if (sp->lockFlag) {
115			gbuf_next(mp) = 0;
116			if (sp->deferred_mb) {
117				for (mb=sp->deferred_mb; gbuf_next(mb); mb=gbuf_next(mb)) ;
118				gbuf_next(mb) = mp;
119			} else
120				sp->deferred_mb = mp;
121			return;
122		}
123		sp->lockFlag = 1;
124		while (mp) {
125			adsp_rput(sp->gref, mp);
126			if ((mp = sp->deferred_mb) != 0) {
127				sp->deferred_mb = gbuf_next(mp);
128				gbuf_next(mp) = 0;
129			}
130		}
131		sp->lockFlag = 0;
132		return;
133
134	case MSG_IOCACK:
135	case MSG_IOCNAK:
136		gref = (gref_t *)((ioc_t *)gbuf_rptr(mp))->ioc_private;
137		break;
138
139	case MSG_IOCTL:
140#ifdef APPLETALK_DEBUG
141		kprintf("unexpected MSG_IOCTL in adsp_input()");
142#endif
143		/* fall through */
144
145	default:
146		gbuf_freem(mp);
147		return;
148	}
149
150	adsp_rput(gref, mp);
151}
152
153/**********/
154int adsp_readable(gref_t *);
155
156int adsp_readable(gref)
157	gref_t *gref;
158{
159	int rc;
160	CCBPtr sp;
161
162	if (gref->info == 0)
163	        /*
164		 * we don't have the structure we need to determine
165		 * if there's data available... we return readable in
166		 * this case to keep from hanging up in the select
167		 * a subsequent read will run into the same missing data
168		 * structure and return an error... the ATselect code does
169		 * this if it can't retrieve the 'gref' structure from the
170		 * file table for the fd specified
171		 */
172	        return(1);
173
174	sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
175	rc = sp->rData;
176
177	return rc;
178}
179
180int adsp_writeable(gref_t *);
181int adsp_writeable(gref)
182	gref_t *gref;
183{
184	int rc;
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));
200	rc = CalcSendQFree(sp);
201
202	return rc;
203}
204
205static void adsp_init(void);
206
207static void adsp_init(void)
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;
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;
238	if ((sp->otccbLink = ccb_used_list) != 0)
239		sp->otccbLink->ccbLink = sp;
240	ccb_used_list = sp;
241	return 0;
242}
243
244int adsp_close(gref)
245	gref_t *gref;
246{
247  unsigned char localSocket;
248
249  /* make sure we've not yet removed the CCB (e.g., due to TrashSession) */
250  if (gref->info) {
251	CCBPtr sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
252	localSocket = sp->localSocket;
253	if (localSocket)
254		adspRelease(gref);
255	else
256	{
257		adsp_dequeue_ccb(sp);
258		gbuf_freeb((gbuf_t *)gref->info);
259	}
260  }
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((CCBPtr)gbuf_rptr(((gbuf_t *)gref->info)));
296	CheckSend((CCBPtr)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;
326	gbuf_t *xm;
327	ioc_t *iocbp;
328	CCBPtr sp;
329
330	if (gref->info)
331		sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
332	else
333		sp = 0;
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));
347			if ( (v != 0)
348			     && ((v > DDP_SOCKET_LAST) || (v < 2)
349				 || ddp_socket_inuse(v, DDP_ADSP))) {
350				iocbp->ioc_rval = -1;
351				adsp_iocnak(gref, mp, EINVAL);
352			}
353			else {
354				if (v == 0) {
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;
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) &&
409			    (xm = gbuf_alloc(sizeof(ddp_addr_t), PRI_MED)) == NULL) {
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 {
435	    rc = adspWriteHandler(gref, mp);
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 = 0, inputC;
519	CCBPtr sp;
520
521	sMax = flag ? DDP_SOCKET_LAST-46 : DDP_SOCKET_LAST-6;
522	sMin = DDP_SOCKET_1st_DYNAMIC;
523
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) {
538		if (!flag || (inputC == 255))
539			return 0;
540		sVal = sSav;
541	}
542	sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
543	adsp_dequeue_ccb(sp);
544	adsp_inputC[sVal]++;
545	sp->otccbLink = adsp_inputQ[sVal];
546	adsp_inputQ[sVal] = sp;
547	if (!flag)
548		adsp_pidM[sVal] = sp->pid;
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;
560
561	dPrintf(D_M_ADSP, D_L_TRACE, ("adspDeassignSocket: pid=%d,s=%d\n",
562		sp->pid, sp->localSocket));
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) {
571			if (prev_sp)
572				prev_sp->otccbLink = sp->otccbLink;
573			else
574				adsp_inputQ[sVal] = sp->otccbLink;
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;
585		    return pid ? 0 : 1;
586		}
587	}
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{
601
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;
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}
625