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) 1996-1998 Apple Computer, Inc.
30 *	All Rights Reserved.
31 */
32
33/*    Modified for MP, 1996 by Tuyen Nguyen
34 *   Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
35 */
36#include <sys/errno.h>
37#include <sys/types.h>
38#include <sys/param.h>
39#include <machine/spl.h>
40#include <sys/systm.h>
41#include <sys/kernel.h>
42#include <sys/proc.h>
43#include <sys/filedesc.h>
44#include <sys/fcntl.h>
45#include <sys/mbuf.h>
46#include <sys/ioctl.h>
47#include <sys/malloc.h>
48#include <sys/socket.h>
49
50#include <net/if.h>
51
52#include <netat/sysglue.h>
53#include <netat/appletalk.h>
54#include <netat/ddp.h>
55#include <netat/at_pcb.h>
56#include <netat/at_var.h>
57#include <netat/atp.h>
58#include <netat/asp.h>
59#include <netat/debug.h>
60
61__private_extern__ int atp_resp_seqno2big = 0;
62
63static void atp_trans_complete(struct atp_trans *);
64void atp_x_done_locked(void *);
65void atp_treq_event(void *);
66
67/*
68 *	Decide what to do about received messages
69 *	Version 1.7 of atp_read.c on 89/02/09 17:53:16
70 */
71
72void atp_treq_event(void *arg)
73{
74	register gref_t *gref = (gref_t *)arg;
75	register gbuf_t *m;
76	register struct atp_state *atp;
77
78	atalk_lock();
79	atp = (struct atp_state *)gref->info;
80	if (atp->dflag)
81		atp = (struct atp_state *)atp->atp_msgq;
82
83	if (atp->dflag) {
84		if ((m = gbuf_alloc(sizeof(ioc_t), PRI_HI)) != NULL) {
85			gbuf_set_type(m, MSG_IOCTL);
86			gbuf_wset(m,sizeof(ioc_t));
87			((ioc_t *)gbuf_rptr(m))->ioc_cmd = AT_ATP_GET_POLL;
88			atp_wput(gref, m);
89		}
90	}
91	else if ((m = gbuf_alloc(1, PRI_HI)) != NULL) {
92		*gbuf_rptr(m) = 0;
93		gbuf_wset(m,1);
94		atalk_putnext(gref, m);
95	}
96
97	if (m == 0)
98		timeout(atp_treq_event, gref, 10);
99	atalk_unlock();
100}
101
102void atp_rput(gref, m)
103gref_t  *gref;
104gbuf_t   *m;
105{
106	register at_atp_t *athp;
107	register struct atp_state *atp;
108	gbuf_t *m_asp = NULL;
109	struct timeval timenow;
110	u_short		temp_net;
111
112	atp = (struct atp_state *)gref->info;
113	if (atp->dflag)
114		atp = (struct atp_state *)atp->atp_msgq;
115
116	switch(gbuf_type(m)) {
117	case MSG_DATA:
118	    /*
119	     *	Decode the message, make sure it is an atp
120	     *		message
121	     */
122	    if (((AT_DDP_HDR(m))->type != DDP_ATP) ||
123		        (atp->atp_flags & ATP_CLOSING)) {
124	        gbuf_freem(m);
125		dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
126			("atp_rput: dropping MSG, not atp\n"));
127		break;
128	    }
129
130	    athp = AT_ATP_HDR(m);
131	    dPrintf(D_M_ATP_LOW, D_L_INPUT,
132		    ("atp_rput MSG_DATA: %s (%d)\n",
133		    (athp->cmd == ATP_CMD_TRESP)? "TRESP":
134		    (athp->cmd == ATP_CMD_TREL)? "TREL":
135		    (athp->cmd == ATP_CMD_TREQ)? "TREQ": "unknown",
136		    athp->cmd));
137	    trace_mbufs(D_M_ATP_LOW, "  r", m);
138
139	    switch (athp->cmd) {
140
141	    case ATP_CMD_TRESP:
142	    {
143		register struct atp_trans *trp;
144		register unsigned int    seqno;
145		register at_ddp_t       *ddp;
146
147		/*
148		 * we just got a response, find the trans record
149		 */
150
151		for (trp = atp->atp_trans_wait.head; trp; trp = trp->tr_list.next) {
152		    if (trp->tr_tid == UAS_VALUE_NTOH(athp->tid))
153			break;
154		}
155
156		/*
157		 *	If we can't find one then ignore the message
158		 */
159		seqno = athp->bitmap;
160		if (seqno > 7) {
161			atp_resp_seqno2big++;
162			ddp = AT_DDP_HDR(m);
163			dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
164				("atp_rput: dropping TRESP seqno too big, tid=%d,loc=%d,rem=%d.%d,seqno=%u\n",
165				 UAS_VALUE_NTOH(athp->tid),
166				 ddp->dst_socket, ddp->src_node, ddp->src_socket, seqno));
167			gbuf_freem(m);
168			return;
169		}
170		if (trp == NULL) {
171	        ddp = AT_DDP_HDR(m);
172		    dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
173		("atp_rput: dropping TRESP, no trp,tid=%d,loc=%d,rem=%d.%d,seqno=%u\n",
174			    UAS_VALUE_NTOH(athp->tid),
175			    ddp->dst_socket, ddp->src_node, ddp->src_socket, seqno));
176		    gbuf_freem(m);
177		    return;
178		}
179
180		/*
181		 * If no longer valid, drop it
182		 */
183		if (trp->tr_state == TRANS_FAILED) {
184	        ddp = AT_DDP_HDR(m);
185		    dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
186		("atp_rput: dropping TRESP, failed trp,tid=%d,loc=%d,rem=%d.%d\n",
187			    UAS_VALUE_NTOH(athp->tid),
188			    ddp->dst_socket, ddp->src_node, ddp->src_socket));
189		    gbuf_freem(m);
190		    return;
191		}
192
193		/*
194		 * If we have already received it, ignore it
195		 */
196		if (!(trp->tr_bitmap&atp_mask[seqno]) || trp->tr_rcv[seqno]) {
197	        ddp = AT_DDP_HDR(m);
198		    dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
199		("atp_rput: dropping TRESP, duplicate,tid=%d,loc=%d,rem=%d.%d,seqno=%u\n",
200			    UAS_VALUE_NTOH(athp->tid),
201			    ddp->dst_socket, ddp->src_node, ddp->src_socket, seqno));
202		    gbuf_freem(m);
203		    return;
204		}
205
206		/*
207		 * Update the received packet bitmap
208		 */
209		if (athp->eom)
210		    trp->tr_bitmap &= atp_lomask[seqno];
211		else
212		    trp->tr_bitmap &= ~atp_mask[seqno];
213
214		/*
215		 *	Save the message in the trans record
216		 */
217		trp->tr_rcv[seqno] = m;
218
219		/*
220		 *	If it isn't the first message then
221		 *		can the header
222		 */
223		if (seqno)
224		    gbuf_rinc(m,DDP_X_HDR_SIZE);
225
226		/*
227		 *	If we now have all the responses then return
228		 *		the message to the user
229		 */
230		if (trp->tr_bitmap == 0) {
231
232		    /*
233		     *	Cancel the request timer and any
234		     *		pending transmits
235		     */
236		    atp_untimout(atp_req_timeout, trp);
237
238		    /*
239		     *	Send the results back to the user
240		     */
241		    atp_x_done(trp);
242		    return;
243		}
244		if (athp->sts) {
245		    /*
246		     *	If they want treq again, send them
247		     */
248		    atp_untimout(atp_req_timeout, trp);
249		    atp_send(trp);
250		    return;
251		}
252		return;
253	    }
254
255	    case ATP_CMD_TREL:
256	    {   register struct atp_rcb *rcbp;
257	        register at_ddp_t       *ddp;
258
259		/*
260		 *	Search for a matching transaction
261		 */
262	        ddp = AT_DDP_HDR(m);
263
264		for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
265		    if (rcbp->rc_tid == UAS_VALUE_NTOH(athp->tid) &&
266			rcbp->rc_socket.node == ddp->src_node &&
267			rcbp->rc_socket.net == NET_VALUE(ddp->src_net) &&
268			rcbp->rc_socket.socket == ddp->src_socket) {
269		            /*
270			     *	Mark the rcb released
271			     */
272			    rcbp->rc_not_sent_bitmap = 0;
273		            if (rcbp->rc_state == RCB_SENDING)
274			        rcbp->rc_state = RCB_RELEASED;
275			    else
276				{
277				ddp = 0;
278				atp_rcb_free(rcbp);
279				}
280			    break;
281		    }
282		}
283
284		gbuf_freem(m);
285		return;
286	   }
287
288
289	   case ATP_CMD_TREQ:
290	   {    register struct atp_rcb *rcbp;
291	        register at_ddp_t       *ddp;
292	        gbuf_t                  *m2;
293
294		/*
295		 *	If it is a request message, first
296		 *	check to see
297		 *	if matches something in our active
298		 *	request queue
299		 */
300	        ddp = AT_DDP_HDR(m);
301
302		for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
303		    if (rcbp->rc_tid == UAS_VALUE_NTOH(athp->tid) &&
304			rcbp->rc_socket.node == ddp->src_node &&
305			rcbp->rc_socket.net == NET_VALUE(ddp->src_net) &&
306			rcbp->rc_socket.socket == ddp->src_socket)
307			break;
308		}
309		/*
310		 *	If this is a new req then do
311		 *	something with it
312		 */
313		if (rcbp == NULL) {
314		    /*
315		     * see if it matches something in the
316		     * attached request queue
317		     * if it does, just release the message
318		     * and go on about our buisness
319		     */
320					/* we just did this, why do again? -jjs 4-10-95 */
321		    for (rcbp = atp->atp_attached.head; rcbp; rcbp = rcbp->rc_list.next) {
322		        if (rcbp->rc_tid == UAS_VALUE_NTOH(athp->tid) &&
323			    rcbp->rc_socket.node == ddp->src_node &&
324			    rcbp->rc_socket.net == NET_VALUE(ddp->src_net) &&
325			    rcbp->rc_socket.socket == ddp->src_socket) {
326			    gbuf_freem(m);
327			    dPrintf(D_M_ATP_LOW, D_L_INPUT,
328				    ("atp_rput: dropping TREQ, matches req queue\n"));
329			    return;
330			}
331		    }
332
333			/*
334			 * assume someone is interested in
335			 * in an asynchronous incoming request
336			 */
337			if ((rcbp = atp_rcb_alloc(atp)) == NULL) {
338			    gbuf_freem(m);
339			    return;
340			}
341			rcbp->rc_state = RCB_UNQUEUED;
342
343		    rcbp->rc_local_node = ddp->dst_node;
344		    temp_net = NET_VALUE(ddp->dst_net);
345		    NET_ASSIGN_NOSWAP(rcbp->rc_local_net, temp_net);
346		    rcbp->rc_socket.socket = ddp->src_socket;
347		    rcbp->rc_socket.node = ddp->src_node;
348		    rcbp->rc_socket.net = NET_VALUE(ddp->src_net);
349		    rcbp->rc_tid = UAS_VALUE_NTOH(athp->tid);
350		    rcbp->rc_bitmap = athp->bitmap;
351		    rcbp->rc_not_sent_bitmap = athp->bitmap;
352		    rcbp->rc_xo = athp->xo;
353		    /*
354		     *	if async then send it as
355		     *		data
356		     *	otherwise, it is a synchronous ioctl so
357		     *		complete it
358		     */
359			if (atp->dflag) { /* for ASP? */
360			  if ((m2 = gbuf_alloc(sizeof(ioc_t), PRI_HI))) {
361			    gbuf_set_type(m2, MSG_DATA);
362			    gbuf_wset(m2,sizeof(ioc_t));
363			    ((ioc_t *)gbuf_rptr(m2))->ioc_cmd = AT_ATP_GET_POLL;
364			    m_asp = m2;
365			  }
366			} else if ((m2 = gbuf_alloc(1, PRI_HI))) {
367			    *gbuf_rptr(m2) = 0;
368			    gbuf_wset(m2,1);
369			    atalk_putnext(gref, m2);
370			}
371			if (m2 == 0) {
372				dPrintf(D_M_ATP,D_L_WARNING,
373					("atp_rput: out of buffer for TREQ\n"));
374				timeout(atp_treq_event, gref, 10);
375			}
376			rcbp->rc_ioctl = m;
377
378			/*
379			 *	move it to the attached list
380			 */
381			dPrintf(D_M_ATP_LOW, D_L_INPUT,
382				("atp_rput: moving to attached list\n"));
383			rcbp->rc_state = RCB_PENDING;
384			ATP_Q_APPEND(atp->atp_attached, rcbp, rc_list);
385			if (m_asp != NULL) {
386			    atp_req_ind(atp, m_asp);
387			    return;
388			}
389		} else {
390		    dPrintf(D_M_ATP_LOW, D_L_INPUT,
391			    ("atp_rput: found match, state:%d\n",
392			    rcbp->rc_state));
393
394		    /*
395		     *	Otherwise we have found a matching request
396		     *		look for what to do
397		     */
398		    switch (rcbp->rc_state) {
399		    case RCB_RESPONDING:
400		    case RCB_RESPONSE_FULL:
401			/*
402			 *	If it is one we have in progress
403			 *		(either have all the responses
404			 *		or are waiting for them)
405			 *		update the bitmap and resend
406			 *		the replies
407			 */
408			getmicrouptime(&timenow);
409			if (rcbp->rc_timestamp) {
410			  rcbp->rc_timestamp = timenow.tv_sec;
411			  if (rcbp->rc_timestamp == 0)
412			    rcbp->rc_timestamp = 1;
413			}
414			rcbp->rc_bitmap = athp->bitmap;
415			rcbp->rc_not_sent_bitmap = athp->bitmap;
416			gbuf_freem(m);
417			atp_reply(rcbp);
418			return;
419
420		    case RCB_RELEASED:
421		    default:
422			/*
423			 *	If we have a release or
424			 *      we haven't sent any data yet
425			 *      ignore the request
426			 */
427			gbuf_freem(m);
428			return;
429		    }
430		}
431		return;
432	   }
433
434           default:
435		gbuf_freem(m);
436		break;
437	   }
438	   break;
439
440	case MSG_IOCACK:
441		if (atp->dflag)
442			asp_ack_reply(gref, m);
443		else
444			atalk_putnext(gref, m);
445		break;
446
447	case MSG_IOCNAK:
448		if (atp->dflag)
449			asp_nak_reply(gref, m);
450		else
451			atalk_putnext(gref, m);
452		break;
453
454	default:
455		gbuf_freem(m);
456	}
457} /* atp_rput */
458
459void
460atp_x_done_locked(trp)
461void *trp;
462{
463	atalk_lock();
464	atp_x_done((struct atp_trans *)trp);
465	atalk_unlock();
466
467}
468
469void
470atp_x_done(trp)
471register struct atp_trans *trp;
472{
473	struct atp_state *atp;
474        gbuf_t  *m;
475
476
477	if ( !trp->tr_xo)
478	        atp_trans_complete(trp);
479	else {
480	        /*
481		 *	If execute once send a release
482		 */
483	        if ((m = (gbuf_t *)atp_build_release(trp)) != NULL) {
484		        AT_DDP_HDR(m)->src_socket = ((struct atp_state *)
485		            trp->tr_queue)->atp_socket_no;
486		        DDP_OUTPUT(m);
487			/*
488			 *	Now send back the transaction reply to the process
489			 *		or notify the process if required
490			 */
491			atp_trans_complete(trp);
492		} else {
493
494			atp = trp->tr_queue;
495			trp->tr_state = TRANS_RELEASE;
496			timeout(atp_x_done_locked, trp, 10);
497		}
498	}
499}
500
501static void
502atp_trans_complete(trp)
503register struct atp_trans *trp;
504{	register gbuf_t *m;
505	register int    type;
506	struct atp_state *atp;
507
508	/* we could gbuf_freem(trp->tr_xmt) here if were not planning to
509	   re-use the mbuf later */
510	m = trp->tr_xmt;
511	trp->tr_xmt = NULL;
512	trp->tr_state = TRANS_DONE;
513
514	if (gbuf_cont(m) == NULL)  /* issued via the new interface */
515		type = AT_ATP_ISSUE_REQUEST_NOTE;
516	else {
517		type = ((ioc_t *)(gbuf_rptr(m)))->ioc_cmd;
518		/*
519		 * free any data following the ioctl blk
520		 */
521		gbuf_freem(gbuf_cont(m));
522		gbuf_cont(m) = NULL;
523	}
524	dPrintf(D_M_ATP_LOW, D_L_INPUT, ("atp_trans_comp: trp=0x%x type = %s\n",
525		(u_int) trp,
526		(type==AT_ATP_ISSUE_REQUEST)? "AT_ATP_ISSUE_REQUEST":
527		(type==AT_ATP_ISSUE_REQUEST_NOTE)? "AT_ATP_ISSUE_REQUEST_NOTE" :
528		"unknown"));
529
530	switch(type) {
531	case AT_ATP_ISSUE_REQUEST:
532	 atp = trp->tr_queue;
533	 if (atp->dflag) {
534		((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
535		((ioc_t *)gbuf_rptr(m))->ioc_error = 0;
536		((ioc_t *)gbuf_rptr(m))->ioc_rval = trp->tr_tid;
537		((ioc_t *)gbuf_rptr(m))->ioc_cmd = AT_ATP_REQUEST_COMPLETE;
538		gbuf_set_type(m, MSG_IOCTL);
539		atp_rsp_ind(trp, m);
540	 } else {
541	  if (trp->tr_bdsp == NULL) {
542		gbuf_freem(m);
543		if (trp->tr_rsp_wait)
544			wakeup(&trp->tr_event);
545	  } else {
546		gbuf_set_type(m, MSG_IOCACK);
547		((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
548		((ioc_t *)gbuf_rptr(m))->ioc_error = 0;
549		((ioc_t *)gbuf_rptr(m))->ioc_rval = 0;
550		atalk_putnext(trp->tr_queue->atp_gref, m);
551	  }
552	 }
553	 break;
554
555	case AT_ATP_ISSUE_REQUEST_NOTE:
556		gbuf_wset(m,1);
557		*gbuf_rptr(m) = 1;
558		gbuf_set_type(m, MSG_DATA);
559		atalk_putnext(trp->tr_queue->atp_gref, m);
560		break;
561	}
562} /* atp_trans_complete */
563