• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.0/libatalk/atp/
1/*
2 * $Id: atp_rsel.c,v 1.6 2009-10-14 01:38:28 didg Exp $
3 *
4 * Copyright (c) 1990,1997 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
6 */
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif /* HAVE_CONFIG_H */
11
12#include <string.h>
13#include <sys/types.h>
14#include <sys/time.h>
15#include <sys/uio.h>
16#include <signal.h>
17#include <errno.h>
18
19#include <netatalk/endian.h>
20#include <netatalk/at.h>
21
22#include <atalk/netddp.h>
23#include <atalk/compat.h>
24#include <atalk/atp.h>
25#include <atalk/util.h>
26
27#include "atp_internals.h"
28
29#ifdef DROP_ATPTREL
30static int	release_count = 0;
31#endif /* DROP_ATPTREL */
32
33
34static int
35resend_request(ATP ah)
36{
37    /*
38     * update bitmap and send request packet
39     */
40    struct atphdr	req_hdr;
41
42#ifdef EBUG
43    printf( "\n<%d> resend_request: resending %ld byte request packet",
44	    getpid(), ah->atph_reqpkt->atpbuf_dlen );
45    atp_print_addr( " to", &ah->atph_reqpkt->atpbuf_addr );
46    putchar( '\n' );
47    bprint( ah->atph_reqpkt->atpbuf_info.atpbuf_data,
48	    ah->atph_reqpkt->atpbuf_dlen );
49#endif /* EBUG */
50
51    memcpy( &req_hdr, ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1,
52	sizeof( struct atphdr ));
53    req_hdr.atphd_bitmap = ah->atph_rbitmap;
54    memcpy( ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1, &req_hdr,
55	    sizeof( struct atphdr ));
56
57    gettimeofday( &ah->atph_reqtv, (struct timezone *)0 );
58    if ( netddp_sendto( ah->atph_socket,
59	    ah->atph_reqpkt->atpbuf_info.atpbuf_data,
60	    ah->atph_reqpkt->atpbuf_dlen, 0,
61	    (struct sockaddr *) &ah->atph_reqpkt->atpbuf_addr,
62	    sizeof( struct sockaddr_at )) != ah->atph_reqpkt->atpbuf_dlen ) {
63	return( -1 );
64    }
65
66    if ( ah->atph_reqtries > 0 ) {
67	--(ah->atph_reqtries);
68    }
69
70    return( 0 );
71}
72
73int
74atp_rsel(
75    ATP			ah,		/* open atp handle */
76    struct sockaddr_at	*faddr,		/* address to receive from */
77    int			func)		/* which function(s) to wait for;
78					   0 means request or response */
79{
80    struct atpbuf	*abuf, *pb, *cb;
81    struct atphdr	req_hdr, resp_hdr;
82    fd_set		fds;
83    int			i, recvlen, requesting, mask, c;
84    u_int8_t		rfunc;
85    u_int16_t		tid;
86    struct timeval	tv;
87    struct sockaddr_at	saddr;
88
89#ifdef EBUG
90    atp_print_bufuse( ah, "atp_rsel at top" );
91#endif /* EBUG */
92    if ( func == 0 ) {
93	func = ATP_FUNCANY;
94    }
95
96    requesting = ( func & ATP_TRESP ) && ah->atph_rrespcount > 0 &&
97	( ah->atph_reqtries > 0 || ah->atph_reqtries == ATP_TRIES_INFINITE );
98
99    if ( requesting && ah->atph_rbitmap == 0 ) {
100	/*
101	 * we already have a complete atp response; just return
102	 */
103	return( ATP_TRESP );
104    }
105
106    if (( abuf = atp_alloc_buf()) == NULL ) {
107	return( -1 );
108    }
109
110    if ( requesting ) {
111#ifdef EBUG
112	printf( "<%d> atp_rsel: request pending\n", getpid());
113#endif /* EBUG */
114	gettimeofday( &tv, (struct timezone *)0 );
115	if ( tv.tv_sec - ah->atph_reqtv.tv_sec > ah->atph_reqto ) {
116	    if ( resend_request( ah ) < 0 ) {
117		atp_free_buf( abuf );
118		return( -1 );
119	    }
120	}
121    }
122
123    for ( ;; ) {
124	rfunc = func;
125	if ( requesting ) {
126	    FD_ZERO( &fds );
127	    FD_SET( ah->atph_socket, &fds );
128	    tv.tv_sec = ah->atph_reqto;
129	    tv.tv_usec = 0;
130	    if (( c = select( ah->atph_socket + 1, &fds, NULL, NULL,
131		    &tv )) < 0 ) {
132		atp_free_buf( abuf );
133		return( -1 );
134	    }
135	    if ( c == 0 || FD_ISSET( ah->atph_socket, &fds ) == 0 ) {
136		recvlen = -1;
137		errno = EINTR;
138		goto timeout;
139	    }
140	}
141	memcpy( &saddr, faddr, sizeof( struct sockaddr_at ));
142#ifdef EBUG
143	printf( "<%d> atp_rsel calling recv_atp,", getpid());
144	atp_print_addr( " accepting from: ", &saddr );
145	putchar( '\n' );
146#endif /* EBUG */
147	if (( recvlen = atp_recv_atp( ah, &saddr, &rfunc, ATP_TIDANY,
148		abuf->atpbuf_info.atpbuf_data, 0 )) >= 0 ) {
149	    break;	/* we received something */
150	}
151
152timeout :
153	if ( !requesting || errno != EINTR ) {
154	    break;	/* error */
155	}
156
157	if ( ah->atph_reqtries <= 0 &&
158		ah->atph_reqtries != ATP_TRIES_INFINITE ) {
159	    errno = ETIMEDOUT;
160	    break;
161	}
162
163	if ( resend_request( ah ) < 0 ) {
164	    break;	/* error */
165	}
166    }
167
168    if ( recvlen <= 0 ) {	/* error */
169	atp_free_buf( abuf );
170	return( recvlen );
171    }
172
173#ifdef EBUG
174    printf( "<%d> atp_rsel: rcvd %d bytes", getpid(), recvlen );
175    atp_print_addr( " from: ", &saddr );
176    putchar( '\n' );
177    bprint( abuf->atpbuf_info.atpbuf_data, recvlen );
178#endif /* EBUG */
179
180    abuf->atpbuf_dlen = (size_t) recvlen;
181    memcpy( &resp_hdr, abuf->atpbuf_info.atpbuf_data + 1,
182	    sizeof( struct atphdr ));
183
184    if ( rfunc == ATP_TREQ ) {
185	/*
186	 * we got a request: check to see if it is a duplicate (XO)
187	 * while we are at it, we expire old XO responses from sent list
188	 */
189	memcpy( &req_hdr, abuf->atpbuf_info.atpbuf_data + 1,
190		sizeof( struct atphdr ));
191	tid = ntohs( req_hdr.atphd_tid );
192	gettimeofday( &tv, (struct timezone *)0 );
193	for ( pb = NULL, cb = ah->atph_sent; cb != NULL;
194		pb = cb, cb = cb->atpbuf_next ) {
195#ifdef EBUG
196	    printf( "<%d>", getpid());
197	    atp_print_addr( " examining", &cb->atpbuf_addr );
198	    printf( " %hu", cb->atpbuf_info.atpbuf_xo.atpxo_tid );
199	    atp_print_addr( " (looking for", &saddr );
200	    printf( " %hu)\n", tid );
201#endif /* EBUG */
202	    if ( tv.tv_sec - cb->atpbuf_info.atpbuf_xo.atpxo_tv.tv_sec
203		    > cb->atpbuf_info.atpbuf_xo.atpxo_reltime ) {
204		/* discard expired response */
205#ifdef EBUG
206		printf( "<%d> expiring tid %hu\n", getpid(),
207			cb->atpbuf_info.atpbuf_xo.atpxo_tid );
208#endif /* EBUG */
209		if ( pb == NULL ) {
210		    ah->atph_sent = cb->atpbuf_next;
211		} else {
212		    pb->atpbuf_next = cb->atpbuf_next;
213		}
214
215		for ( i = 0; i < 8; ++i ) {
216		    if ( cb->atpbuf_info.atpbuf_xo.atpxo_packet[ i ]
217			    != NULL ) {
218			atp_free_buf( cb->atpbuf_info.atpbuf_xo.atpxo_packet[ i ] );
219		    }
220		}
221		atp_free_buf( cb );
222
223		if (( cb = pb ) == NULL )
224		    break;
225
226	    } else if ( at_addr_eq( &saddr, &cb->atpbuf_addr )) {
227		if ( cb->atpbuf_info.atpbuf_xo.atpxo_tid == tid ) {
228		    break;
229		}
230	    }
231	}
232
233	if ( cb != NULL ) {
234#ifdef EBUG
235	    printf( "<%d> duplicate request -- re-sending XO resp\n",
236		    getpid());
237#endif /* EBUG */
238	    /* matches an old response -- just re-send and reset expire */
239	    cb->atpbuf_info.atpbuf_xo.atpxo_tv = tv;
240	    for ( i = 0; i < 8; ++i ) {
241		if ( cb->atpbuf_info.atpbuf_xo.atpxo_packet[i] != NULL &&
242			req_hdr.atphd_bitmap & ( 1 << i )) {
243		    netddp_sendto( ah->atph_socket,
244			    cb->atpbuf_info.atpbuf_xo.atpxo_packet[i]->atpbuf_info.atpbuf_data,
245			    cb->atpbuf_info.atpbuf_xo.atpxo_packet[i]->atpbuf_dlen,
246			    0, (struct sockaddr *) &saddr, sizeof( struct sockaddr_at));
247		}
248	    }
249	}
250
251	if ( cb == NULL ) {
252	    /* new request -- queue it and return */
253	    memcpy( &abuf->atpbuf_addr, &saddr, sizeof( struct sockaddr_at ));
254	    memcpy( faddr, &saddr, sizeof( struct sockaddr_at ));
255	    abuf->atpbuf_next = ah->atph_queue;
256	    ah->atph_queue = abuf;
257	    return( ATP_TREQ );
258	} else {
259	    atp_free_buf( abuf );
260	    return( 0 );
261	}
262    }
263
264    /*
265     * we got a response: update bitmap
266     */
267    memcpy( &req_hdr, ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1,
268	    sizeof( struct atphdr ));
269    if ( requesting && ah->atph_rbitmap & ( 1<<resp_hdr.atphd_bitmap )
270		&& req_hdr.atphd_tid == resp_hdr.atphd_tid ) {
271	ah->atph_rbitmap &= ~( 1<<resp_hdr.atphd_bitmap );
272
273	if ( ah->atph_resppkt[ resp_hdr.atphd_bitmap ] != NULL ) {
274	    atp_free_buf( ah->atph_resppkt[ resp_hdr.atphd_bitmap ] );
275	}
276	ah->atph_resppkt[ resp_hdr.atphd_bitmap ] = abuf;
277
278	/* if End Of Message, clear all higher bitmap bits
279	*/
280	if ( resp_hdr.atphd_ctrlinfo & ATP_EOM ) {
281#ifdef EBUG
282	    printf( "<%d> EOM -- seq num %d  current bitmap %d\n",
283		getpid(), resp_hdr.atphd_bitmap, ah->atph_rbitmap );
284#endif /* EBUG */
285	    mask = 1 << resp_hdr.atphd_bitmap;
286	    ah->atph_rbitmap &= ( mask | (mask-1) );
287	}
288
289	/* if Send Trans. Status, send updated request
290	*/
291	if ( resp_hdr.atphd_ctrlinfo & ATP_STS ) {
292#ifdef EBUG
293	    puts( "STS" );
294#endif /* EBUG */
295	    req_hdr.atphd_bitmap = ah->atph_rbitmap;
296	    memcpy(ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1,
297		   &req_hdr, sizeof( struct atphdr ));
298	    if ( netddp_sendto( ah->atph_socket,
299		    ah->atph_reqpkt->atpbuf_info.atpbuf_data,
300		    ah->atph_reqpkt->atpbuf_dlen, 0,
301		    (struct sockaddr *) &ah->atph_reqpkt->atpbuf_addr,
302		    sizeof( struct sockaddr_at )) !=
303		    ah->atph_reqpkt->atpbuf_dlen ) {
304		atp_free_buf( abuf );
305		return( -1 );
306	    }
307	}
308    } else {
309	/*
310	 * we are not expecting this response -- toss it
311	 */
312	atp_free_buf( abuf );
313#ifdef EBUG
314	printf( "atp_rsel: ignoring resp bm=%x tid=%d (expected %x/%d)\n",
315		resp_hdr.atphd_bitmap, ntohs( resp_hdr.atphd_tid ),
316		ah->atph_rbitmap, ah->atph_tid );
317#endif /* EBUG */
318    }
319
320    if ( !ah->atph_rbitmap && ( req_hdr.atphd_ctrlinfo & ATP_XO )) {
321	/*
322	 * successful completion - send release
323	 * the release consists of DDP type byte + ATP header + 4 user bytes
324	 */
325	req_hdr.atphd_ctrlinfo = ATP_TREL;
326	memcpy( ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1, &req_hdr,
327	    sizeof( struct atphdr ));
328	memset( ah->atph_reqpkt->atpbuf_info.atpbuf_data + ATP_HDRSIZE, 0, 4 );
329	ah->atph_reqpkt->atpbuf_dlen = sizeof( struct atphdr ) + ATP_HDRSIZE;
330#ifdef EBUG
331	printf( "<%d> sending TREL", getpid() );
332	bprint( ah->atph_reqpkt->atpbuf_info.atpbuf_data,
333		ah->atph_reqpkt->atpbuf_dlen );
334#endif /* EBUG */
335#ifdef DROP_ATPTREL
336	if (( ++release_count % 10 ) != 0 ) {
337#endif /* DROP_ATPTREL */
338	netddp_sendto( ah->atph_socket,
339		       ah->atph_reqpkt->atpbuf_info.atpbuf_data,
340		       ah->atph_reqpkt->atpbuf_dlen, 0,
341		       (struct sockaddr *) &ah->atph_reqpkt->atpbuf_addr,
342		       sizeof( struct sockaddr_at));
343#ifdef DROP_ATPTREL
344	}
345#endif /* DROP_ATPTREL */
346    }
347
348    if ( ah->atph_rbitmap != 0 ) {
349	if ( ah->atph_reqtries > 0
350		|| ah->atph_reqtries == ATP_TRIES_INFINITE ) {
351	    return( 0 );
352	} else {
353	    errno = ETIMEDOUT;
354	    return( -1 );
355	}
356    }
357
358    memcpy( faddr, &saddr, sizeof( struct sockaddr_at ));
359    return( ATP_TRESP );
360}
361