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 * Change log:
30 *   06/29/95 - Modified to handle flow control for writing (Tuyen Nguyen)
31 *    Modified for MP, 1996 by Tuyen Nguyen
32 *   Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
33 */
34#define RESOLVE_DBG
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
47#include <netat/sysglue.h>
48#include <netat/appletalk.h>
49#include <netat/at_pcb.h>
50#include <netat/ddp.h>
51#include <netat/adsp.h>
52#include <netat/adsp_internal.h>
53
54#ifdef notdefn
55struct adsp_debug adsp_dtable[1025];
56int ad_entry = 0;
57#endif
58
59int
60adspAllocateCCB(gref)
61    register gref_t *gref;	/* READ queue */
62{
63    gbuf_t *ccb_mp;
64    register CCBPtr sp;
65
66    if (!(ccb_mp = gbuf_alloc(sizeof(CCB), PRI_LO))) {
67        return (0);
68    }
69    bzero((caddr_t) gbuf_rptr(ccb_mp), sizeof(CCB));
70    gbuf_wset(ccb_mp,sizeof(CCB));
71    gref->info = (caddr_t) ccb_mp;
72    sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
73
74    sp->pid = gref->pid; /* save the caller process pointer */
75    sp->gref = gref;		/* save a back pointer to the WRITE queue */
76    sp->sp_mp = ccb_mp;		/* and its message block */
77    return 1;
78}
79
80int
81adspRelease(gref)
82    register gref_t *gref;	/* READ queue */
83{
84    register CCBPtr sp;
85
86    if (gref->info) {
87	sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
88				/* Tells completion routine of close */
89				/* packet to remove us. */
90
91	if (sp->state == sPassive || sp->state == sClosed ||
92	    sp->state == sOpening || sp->state == sListening) {
93	    if (sp->state == sListening)
94		CompleteQueue(&sp->opb, errAborted);
95	    sp->removing = 1;	/* Prevent allowing another dspClose. */
96	    DoClose(sp, errAborted, 0); /* will remove CCB */
97	    return 0;
98	} else {			/* sClosing & sOpen */
99	    sp->state = sClosing;
100	}
101
102	if (CheckOkToClose(sp)) { /* going to close */
103	    sp->sendCtl = B_CTL_CLOSE; /* Send close advice */
104	} else {
105		CheckSend(sp);	/* try one more time to send out data */
106		if (sp->state != sClosed)
107		    sp->sendCtl = B_CTL_CLOSE; /* Setup to send close advice */
108	}
109	CheckSend(sp);		/* and force out the close */
110	    sp->removing = 1;	/* Prevent allowing another dspClose. */
111	    sp->state = sClosed;
112	    DoClose(sp, errAborted, 0);  /* to closed and remove CCB */
113    }
114	return 0;
115}
116
117
118
119int
120adspWriteHandler(gref, mp)
121    gref_t *gref;			/* WRITE queue */
122    gbuf_t *mp;
123{
124
125    register ioc_t *iocbp;
126    register struct adspcmd *ap;
127    int error, flag;
128	void *sp;
129
130    switch(gbuf_type(mp)) {
131		case MSG_DATA:
132		if (gref->info == 0) {
133			gbuf_freem(mp);
134			return(STR_IGNORE);
135			}
136		/*
137		 * Fill in the global stuff
138		 */
139		ap = (struct adspcmd *)gbuf_rptr(mp);
140		ap->gref = gref;
141		ap->ioc = 0;
142		ap->mp = mp;
143		sp = (void *)gbuf_rptr(((gbuf_t *)gref->info));
144		switch(ap->csCode) {
145			case dspWrite:
146				if ((error = adspWrite(sp, ap)))
147				gbuf_freem(mp);
148				return(STR_IGNORE);
149			case dspAttention:
150				if ((error = adspAttention(sp, (CCBPtr)ap)))
151				gbuf_freem(mp);
152				return(STR_IGNORE);
153		}
154		case MSG_IOCTL:
155		if (gref->info == 0) {
156			adspioc_ack(EPROTOTYPE, mp, gref);
157			return(STR_IGNORE);
158			}
159		iocbp = (ioc_t *) gbuf_rptr(mp);
160		if (ADSP_IOCTL(iocbp->ioc_cmd)) {
161			iocbp->ioc_count = sizeof(*ap) - 1;
162			if (gbuf_cont(mp) == 0) {
163			adspioc_ack(EINVAL, mp, gref);
164			return(STR_IGNORE);
165			}
166			ap = (struct adspcmd *) gbuf_rptr(gbuf_cont(mp));
167			ap->gref = gref;
168			ap->ioc = (caddr_t) mp;
169			ap->mp = gbuf_cont(mp); /* request head */
170			ap->ioResult = 0;
171
172			if ((gref->info == 0) && ((iocbp->ioc_cmd != ADSPOPEN) &&
173							(iocbp->ioc_cmd != ADSPCLLISTEN))) {
174				ap->ioResult = errState;
175
176			adspioc_ack(EINVAL, mp, gref);
177			return(STR_IGNORE);
178			}
179		} else
180			return(STR_PUTNEXT);	/* pass it on down */
181		sp = (void *)gbuf_rptr(((gbuf_t *)gref->info));
182		switch(iocbp->ioc_cmd) {
183			case ADSPOPEN:
184			case ADSPCLLISTEN:
185				ap->socket = ((CCBPtr)sp)->localSocket;
186				flag = (adspMode(ap) == ocAccept) ? 1 : 0;
187				if (flag && ap->socket) {
188					if (adspDeassignSocket((CCBPtr)sp) >= 0)
189						ap->socket = 0;
190				}
191				if ((ap->socket == 0) &&
192					((ap->socket =
193					  (at_socket)adspAssignSocket(gref, flag)) == 0)) {
194					adspioc_ack(EADDRNOTAVAIL, mp, gref);
195					return(STR_IGNORE);
196				}
197				ap->csCode = iocbp->ioc_cmd == ADSPOPEN ? dspInit : dspCLInit;
198				if ((error = adspInit(sp, ap)) == 0) {
199				switch(ap->csCode) {
200				case dspInit:
201					/* and open the connection */
202					ap->csCode = dspOpen;
203					error = adspOpen(sp, ap);
204					break;
205				case dspCLInit:
206					/* ADSPCLLISTEN */
207					ap->csCode = dspCLListen;
208					error = adspCLListen(sp, ap);
209					break;
210				}
211				}
212				if (error)
213				adspioc_ack(error, mp, gref); /* if this failed req complete */
214				return(STR_IGNORE);
215			case ADSPCLOSE:
216				ap->csCode = dspClose;
217				if ((error = adspClose(sp, ap))) {
218				adspioc_ack(error, mp, gref);
219				break;
220				}
221				break;
222			case ADSPCLREMOVE:
223				ap->csCode = dspCLRemove;
224				error = adspClose(sp, ap);
225				adspioc_ack(error, mp, gref);
226				return(STR_IGNORE);
227			case ADSPCLDENY:
228				ap->csCode = dspCLDeny;
229				if ((error = adspCLDeny(sp, (CCBPtr)ap))) {
230				adspioc_ack(error, mp, gref);
231				}
232				return(STR_IGNORE);
233			case ADSPSTATUS:
234				ap->csCode = dspStatus;
235				if ((error = adspStatus(sp, ap))) {
236				adspioc_ack(error, mp, gref);
237				}
238				return(STR_IGNORE);
239			case ADSPREAD:
240				ap->csCode = dspRead;
241				if ((error = adspRead(sp, ap))) {
242				adspioc_ack(error, mp, gref);
243				}
244				return(STR_IGNORE);
245			case ADSPATTENTION:
246				ap->csCode = dspAttention;
247				if ((error = adspReadAttention((CCBPtr)sp, ap))) {
248				adspioc_ack(error, mp, gref);
249				}
250				return(STR_IGNORE);
251			case ADSPOPTIONS:
252				ap->csCode = dspOptions;
253				if ((error = adspOptions(sp, ap))) {
254				adspioc_ack(error, mp, gref);
255				}
256				return(STR_IGNORE);
257			case ADSPRESET:
258				ap->csCode = dspReset;
259				if ((error = adspReset(sp, ap))) {
260				adspioc_ack(error, mp, gref);
261				}
262				return(STR_IGNORE);
263			case ADSPNEWCID:
264				ap->csCode = dspNewCID;
265				if ((error = adspNewCID(sp, ap))) {
266				adspioc_ack(error, mp, gref);
267				}
268				return(STR_IGNORE);
269			default:
270				return(STR_PUTNEXT);	/* pass it on down */
271		}
272		return(STR_IGNORE);
273		case MSG_PROTO:
274		default:
275		gbuf_freem(mp);
276    }
277	return(STR_IGNORE);
278}
279
280int
281adspReadHandler(gref, mp)
282    gref_t *gref;
283    gbuf_t *mp;
284{
285    int error;
286
287    switch(gbuf_type(mp)) {
288    case MSG_DATA:
289	if ((error = adspPacket(gref, mp))) {
290	    gbuf_freem(mp);
291	}
292	break;
293
294    case MSG_IOCTL:
295    default:
296	return(STR_PUTNEXT);
297	break;
298    }
299    return(STR_IGNORE);
300}
301
302/*
303 * adsp_sendddp()
304 *
305 * Description:
306 *      This procedure a formats a DDP datagram header and calls the
307 *      DDP module to queue it for routing and transmission according to
308 *      the DDP parameters.  We always take control of the datagram;
309 *      if there is an error we free it, otherwise we pass it to the next
310 *      layer.  We don't need to set the src address fileds because the
311 *      DDP layer fills these in for us.
312 *
313 * Calling Sequence:
314 *      ret_status = adsp_sendddp(q, sp, mp, length, dstnetaddr, ddptype);
315 *
316 * Formal Parameters:
317 *	sp		Caller stream pointer
318 *      mp              gbuf_t chain containing the datagram to transmit
319 *			The first mblk contains the ADSP header and space
320 *			for the DDP header.
321 *      length          size of data portion of datagram
322 *      dstnetaddr      address of 4-byte destination internet address
323 *      ddptype         DDP protocol to assign to the datagram
324 *
325 * Completion Status:
326 *      0               Procedure successful completed.
327 *      EMSGSIZE        Specified datagram length is too big.
328 *
329 * Side Effects:
330 *      NONE
331 */
332int
333adsp_sendddp(sp, mp, length, dstnetaddr, ddptype)
334   CCBPtr sp;
335   gbuf_t *mp;
336   int length;
337   AddrUnion *dstnetaddr;
338   int ddptype;
339{
340   DDPX_FRAME   *ddp;
341   gbuf_t *mlist = mp;
342
343   if (mp == 0)
344       return EINVAL;
345
346   if (length > DDP_DATA_SIZE) {
347       gbuf_freel(mlist);
348       return EMSGSIZE;
349   }
350
351  while (mp) {
352
353   if (length == 0)
354       length = gbuf_msgsize(mp) - DDPL_FRAME_LEN;
355   /* Set up the DDP header */
356
357   ddp = (DDPX_FRAME *) gbuf_rptr(mp);
358   UAS_ASSIGN_HTON(ddp->ddpx_length, (length + DDPL_FRAME_LEN));
359   UAS_ASSIGN(ddp->ddpx_cksm, 0);
360   if (sp) {
361	if (sp->useCheckSum)
362	   UAS_ASSIGN_HTON(ddp->ddpx_cksm, 1);
363   }
364
365   NET_ASSIGN(ddp->ddpx_dnet, dstnetaddr->a.net);
366   ddp->ddpx_dnode = dstnetaddr->a.node;
367   ddp->ddpx_source = sp ? sp->localSocket : ddp->ddpx_dest;
368   ddp->ddpx_dest = dstnetaddr->a.socket;
369
370   ddp->ddpx_type = ddptype;
371   length = 0;
372   mp = gbuf_next(mp);
373
374  }
375
376   DDP_OUTPUT(mlist);
377   return 0;
378}
379
380void NotifyUser(
381	__unused CCBPtr sp)
382
383{
384/*
385    pidsig(sp->pid, SIGIO);
386*/
387}
388
389void UrgentUser(
390    __unused CCBPtr sp)
391{
392/*
393    pidsig(sp->pid, SIGURG);
394*/
395}
396