• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.5/libatalk/atp/
1/*
2 * $Id: atp_packet.c,v 1.6 2009-10-13 22:55:37 didg Exp $
3 *
4 * Copyright (c) 1990,1991 Regents of The University of Michigan.
5 * All Rights Reserved.
6 *
7 * Permission to use, copy, modify, and distribute this software and
8 * its documentation for any purpose and without fee is hereby granted,
9 * provided that the above copyright notice appears in all copies and
10 * that both that copyright notice and this permission notice appear
11 * in supporting documentation, and that the name of The University
12 * of Michigan not be used in advertising or publicity pertaining to
13 * distribution of the software without specific, written prior
14 * permission. This software is supplied as is without expressed or
15 * implied warranties of any kind.
16 *
17 *	Research Systems Unix Group
18 *	The University of Michigan
19 *	c/o Mike Clark
20 *	535 W. William Street
21 *	Ann Arbor, Michigan
22 *	+1-313-763-0525
23 *	netatalk@itd.umich.edu
24 */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif /* HAVE_CONFIG_H */
29
30#include <string.h>
31#include <sys/types.h>
32#include <sys/time.h>
33#include <sys/uio.h>
34#include <sys/param.h>
35#include <netinet/in.h>
36
37#include <netatalk/at.h>
38#include <netatalk/endian.h>
39
40#include <atalk/netddp.h>
41#include <atalk/ddp.h>
42#include <atalk/atp.h>
43#include <atalk/util.h>
44
45#include "atp_internals.h"
46
47/* FIXME/SOCKLEN_T: socklen_t is a unix98 feature. */
48#ifndef SOCKLEN_T
49#define SOCKLEN_T unsigned int
50#endif /* ! SOCKLEN_T */
51
52#ifdef EBUG
53#include <stdio.h>
54
55static void print_func(u_int8_t ctrlinfo)
56{
57    switch ( ctrlinfo & ATP_FUNCMASK ) {
58    case ATP_TREQ:
59	printf( "TREQ" );
60	break;
61    case ATP_TRESP:
62	printf( "TRESP" );
63	break;
64    case ATP_TREL:
65	printf( "ANY/TREL" );
66	break;
67    case ATP_TIDANY:
68	printf( "*" );
69	break;
70    default:
71	printf( "%x", ctrlinfo & ATP_FUNCMASK );
72    }
73}
74
75static void dump_packet(char *buf, int len)
76{
77    int		i;
78
79    for ( i = 0; i < len; ++i ) {
80	printf( "%x-%c ", buf[i], buf[i] );
81    }
82    putchar( '\n' );
83}
84
85void atp_print_addr(char *s, struct sockaddr_at *saddr)
86{
87    printf( "%s ", s );
88    saddr->sat_family == AF_APPLETALK ? printf( "at." ) :
89      printf( "%d.", saddr->sat_family );
90    saddr->sat_addr.s_net == ATADDR_ANYNET ? printf( "*." ) :
91      printf( "%d.", ntohs( saddr->sat_addr.s_net ));
92    saddr->sat_addr.s_node == ATADDR_ANYNODE ? printf( "*." ) :
93      printf( "%d.", saddr->sat_addr.s_node );
94    saddr->sat_port == ATADDR_ANYPORT ? printf( "*" ) :
95      printf( "%d", saddr->sat_port );
96}
97#endif /* EBUG */
98
99
100void atp_build_req_packet( struct atpbuf *pktbuf,
101			   u_int16_t tid,
102			   u_int8_t ctrl,
103			   struct atp_block *atpb )
104{
105    struct atphdr	hdr;
106
107    /* fill in the packet fields
108    */
109    hdr.atphd_ctrlinfo = ctrl;
110    hdr.atphd_bitmap = atpb->atp_bitmap;
111    hdr.atphd_tid = htons( tid );
112    *(pktbuf->atpbuf_info.atpbuf_data) = DDPTYPE_ATP;
113    memcpy(pktbuf->atpbuf_info.atpbuf_data + 1, &hdr, sizeof( struct atphdr ));
114    memcpy(pktbuf->atpbuf_info.atpbuf_data + ATP_HDRSIZE,
115	   atpb->atp_sreqdata, atpb->atp_sreqdlen );
116
117    /* set length
118    */
119    pktbuf->atpbuf_dlen = ATP_HDRSIZE + (size_t) atpb->atp_sreqdlen;
120}
121
122void atp_build_resp_packet( struct atpbuf *pktbuf,
123			    u_int16_t tid,
124			    u_int8_t ctrl,
125			    struct atp_block *atpb,
126			    u_int8_t seqnum )
127{
128    struct atphdr	hdr;
129
130    /* fill in the packet fields */
131    *(pktbuf->atpbuf_info.atpbuf_data) = DDPTYPE_ATP;
132    hdr.atphd_ctrlinfo = ctrl;
133    hdr.atphd_bitmap = seqnum;
134    hdr.atphd_tid = htons( tid );
135    memcpy(pktbuf->atpbuf_info.atpbuf_data + 1, &hdr,
136	   sizeof( struct atphdr ));
137    memcpy(pktbuf->atpbuf_info.atpbuf_data + ATP_HDRSIZE,
138	  atpb->atp_sresiov[ seqnum ].iov_base,
139	  atpb->atp_sresiov[ seqnum ].iov_len );
140
141    /* set length
142    */
143    pktbuf->atpbuf_dlen = ATP_HDRSIZE + (size_t) atpb->atp_sresiov[ seqnum ].iov_len;
144}
145
146
147int
148atp_recv_atp( ATP ah,
149	      struct sockaddr_at *fromaddr,
150	      u_int8_t *func,
151	      u_int16_t tid,
152	      char *rbuf,
153	      int wait )
154{
155/*
156  Receive a packet from address fromaddr of the correct function type
157  and with the correct tid.  fromaddr = AT_ANY... and function == ATP_TYPEANY
158  and tid == ATP_TIDANY can be used to wildcard match.
159
160  recv_atp returns the length of the packet received (or -1 if error)
161  The function code for the packet received is returned in *func (ATP_TREQ or
162    ATP_TRESP).
163*/
164    struct atpbuf	*pq, *cq;
165    struct atphdr	ahdr;
166    u_int16_t		rfunc;
167    u_int16_t		rtid;
168    int			i;
169    int			dlen = -1;
170    int			recvlen;
171    struct sockaddr_at	faddr;
172    SOCKLEN_T		faddrlen;
173    struct atpbuf	*inbuf;
174
175    tid = htons( tid );
176
177    /* first check the queue
178    */
179#ifdef EBUG
180    atp_print_bufuse( ah, "recv_atp checking queue" );
181#endif /* EBUG */
182    for ( pq = NULL, cq = ah->atph_queue; cq != NULL;
183      pq = cq, cq = cq->atpbuf_next ) {
184	memcpy(&ahdr, cq->atpbuf_info.atpbuf_data + 1,
185	       sizeof( struct atphdr ));
186	rfunc = ahdr.atphd_ctrlinfo & ATP_FUNCMASK;
187#ifdef EBUG
188	printf( "<%d> checking", getpid());
189	printf( " tid=%hu func=", ntohs( ahdr.atphd_tid ));
190	print_func( rfunc );
191	atp_print_addr( " from", &cq->atpbuf_addr );
192	putchar( '\n' );
193#endif /* EBUG */
194	if ((( tid & ahdr.atphd_tid ) == ahdr.atphd_tid ) &&
195	    (( *func & rfunc ) == rfunc )
196	    && at_addr_eq( fromaddr, &cq->atpbuf_addr )) {
197	    break;
198	}
199    }
200    if ( cq != NULL ) {
201	/* we found one in the queue -- copy to rbuf
202	*/
203	dlen = (int) cq->atpbuf_dlen;
204	*func = rfunc;
205	memcpy( fromaddr, &cq->atpbuf_addr, sizeof( struct sockaddr_at ));
206	memcpy( rbuf, cq->atpbuf_info.atpbuf_data, cq->atpbuf_dlen );
207
208	/* remove packet from queue and free buffer
209	*/
210	if ( pq == NULL ) {
211	    ah->atph_queue = NULL;
212	} else {
213	    pq->atpbuf_next = cq->atpbuf_next;
214	}
215	atp_free_buf( cq );
216	return( dlen );
217    }
218
219    /* we need to get it the net -- call on ddp to receive a packet
220    */
221#ifdef EBUG
222    printf( "<%d>", getpid());
223    atp_print_addr( " waiting on address", &ah->atph_saddr );
224    printf( "\nfor tid=%hu func=", ntohs( tid ));
225    print_func( *func );
226    atp_print_addr( " from", fromaddr );
227    putchar( '\n' );
228#endif /* EBUG */
229
230    do {
231#ifdef EBUG
232    fflush( stdout );
233#endif /* EBUG */
234	faddrlen = sizeof( struct sockaddr_at );
235	memset( &faddr, 0, sizeof( struct sockaddr_at ));
236
237	if (( recvlen = netddp_recvfrom( ah->atph_socket, rbuf,
238					 ATP_BUFSIZ, 0,
239					 (struct sockaddr *) &faddr,
240					 &faddrlen )) < 0 ) {
241	    return -1;
242	}
243	memcpy( &ahdr, rbuf + 1, sizeof( struct atphdr ));
244	if ( recvlen >= ATP_HDRSIZE && *rbuf == DDPTYPE_ATP) {
245	    /* this is a valid ATP packet -- check for a match */
246	    rfunc = ahdr.atphd_ctrlinfo & ATP_FUNCMASK;
247	    rtid = ahdr.atphd_tid;
248#ifdef EBUG
249	    printf( "<%d> got tid=%hu func=", getpid(), ntohs( rtid ));
250	    print_func( rfunc );
251	    atp_print_addr( " from", &faddr );
252	    putchar( '\n' );
253	    bprint( rbuf, recvlen );
254#endif /* EBUG */
255	    if ( rfunc == ATP_TREL ) {
256		/* remove response from sent list */
257		for ( pq = NULL, cq = ah->atph_sent; cq != NULL;
258		  pq = cq, cq = cq->atpbuf_next ) {
259		    if ( at_addr_eq( &faddr, &cq->atpbuf_addr ) &&
260		      cq->atpbuf_info.atpbuf_xo.atpxo_tid == ntohs( rtid ))
261			break;
262		}
263		if ( cq != NULL ) {
264#ifdef EBUG
265	printf( "<%d> releasing transaction %hu\n", getpid(), ntohs( rtid ));
266#endif /* EBUG */
267		    if ( pq == NULL ) {
268			ah->atph_sent = cq->atpbuf_next;
269		    } else {
270			pq->atpbuf_next = cq->atpbuf_next;
271		    }
272		    for ( i = 0; i < 8; ++i ) {
273			if ( cq->atpbuf_info.atpbuf_xo.atpxo_packet[ i ]
274				    != NULL ) {
275			    atp_free_buf ( cq->atpbuf_info.atpbuf_xo.atpxo_packet[ i ] );
276			}
277		    }
278		    atp_free_buf( cq );
279		}
280
281	    } else if ((( tid & rtid ) == rtid ) &&
282		    (( *func & rfunc ) == rfunc ) &&
283		    at_addr_eq( fromaddr, &faddr )) { /* got what we wanted */
284		*func = rfunc;
285		dlen = recvlen;
286		memcpy( fromaddr, &faddr, sizeof( struct sockaddr_at ));
287
288	    } else {
289		/* add packet to incoming queue */
290#ifdef EBUG
291	printf( "<%d> queuing incoming...\n", getpid() );
292#endif /* EBUG */
293		if (( inbuf = atp_alloc_buf()) == NULL ) {
294		    return -1;
295		}
296		memcpy( &inbuf->atpbuf_addr, &faddr,
297			sizeof( struct sockaddr_at ));
298		inbuf->atpbuf_next = ah->atph_queue;
299		inbuf->atpbuf_dlen = (size_t) recvlen;
300		memcpy( inbuf->atpbuf_info.atpbuf_data, rbuf, recvlen );
301	    }
302	}
303	if ( !wait && dlen < 0 ) {
304	    return( 0 );
305	}
306
307    } while ( dlen < 0 );
308
309    return( dlen );
310}
311
312
313int at_addr_eq(
314    struct sockaddr_at	*paddr,		/* primary address */
315    struct sockaddr_at	*saddr)		/* secondary address */
316{
317/* compare two atalk addresses -- only check the non-zero fields
318    of paddr against saddr.
319   return zero if not equal, non-zero if equal
320*/
321    return (( paddr->sat_port == ATADDR_ANYPORT || paddr->sat_port == saddr->sat_port )
322	&&  ( paddr->sat_addr.s_net == ATADDR_ANYNET ||
323	      paddr->sat_addr.s_net == saddr->sat_addr.s_net )
324	&&  ( paddr->sat_addr.s_node == ATADDR_ANYNODE ||
325	      paddr->sat_addr.s_node == saddr->sat_addr.s_node ));
326}
327
328