]> arthur.barton.de Git - netatalk.git/blob - libatalk/atp/atp_packet.c
9659e008f1c2f5ec5bb908d30190c41c7c83142b
[netatalk.git] / libatalk / atp / atp_packet.c
1 /*
2  * $Id: atp_packet.c,v 1.5 2002-01-17 06:08:55 srittau 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
55 static void print_func( ctrlinfo )
56     u_int8_t    ctrlinfo;
57 {
58     switch ( ctrlinfo & ATP_FUNCMASK ) {
59     case ATP_TREQ:
60         printf( "TREQ" );
61         break;
62     case ATP_TRESP:
63         printf( "TRESP" );
64         break;
65     case ATP_TREL:
66         printf( "ANY/TREL" );
67         break;
68     case ATP_TIDANY:
69         printf( "*" );
70         break;
71     default:
72         printf( "%x", ctrlinfo & ATP_FUNCMASK );
73     }
74 }
75
76 static void dump_packet( buf, len )
77     char        *buf;
78     int         len;
79 {
80     int         i;
81
82     for ( i = 0; i < len; ++i ) {
83         printf( "%x-%c ", buf[i], buf[i] );
84     }
85     putchar( '\n' );
86 }
87
88 void atp_print_addr( s, saddr )
89     char                *s;
90     struct sockaddr_at  *saddr;
91 {
92     printf( "%s ", s );
93     saddr->sat_family == AF_APPLETALK ? printf( "at." ) :
94       printf( "%d.", saddr->sat_family );
95     saddr->sat_addr.s_net == ATADDR_ANYNET ? printf( "*." ) :
96       printf( "%d.", ntohs( saddr->sat_addr.s_net ));
97     saddr->sat_addr.s_node == ATADDR_ANYNODE ? printf( "*." ) :
98       printf( "%d.", saddr->sat_addr.s_node );
99     saddr->sat_port == ATADDR_ANYPORT ? printf( "*" ) :
100       printf( "%d", saddr->sat_port );
101 }
102 #endif /* EBUG */
103
104
105 void atp_build_req_packet( struct atpbuf *pktbuf,
106                            u_int16_t tid,
107                            u_int8_t ctrl,
108                            struct atp_block *atpb )
109 {
110     struct atphdr       hdr;
111
112     /* fill in the packet fields
113     */
114     hdr.atphd_ctrlinfo = ctrl;
115     hdr.atphd_bitmap = atpb->atp_bitmap;
116     hdr.atphd_tid = htons( tid );
117     *(pktbuf->atpbuf_info.atpbuf_data) = DDPTYPE_ATP;
118     memcpy(pktbuf->atpbuf_info.atpbuf_data + 1, &hdr, sizeof( struct atphdr ));
119     memcpy(pktbuf->atpbuf_info.atpbuf_data + ATP_HDRSIZE, 
120            atpb->atp_sreqdata, atpb->atp_sreqdlen ); 
121
122     /* set length
123     */
124     pktbuf->atpbuf_dlen = ATP_HDRSIZE + (size_t) atpb->atp_sreqdlen;
125 }
126
127 void atp_build_resp_packet( struct atpbuf *pktbuf,
128                             u_int16_t tid,
129                             u_int8_t ctrl,
130                             struct atp_block *atpb,
131                             u_int8_t seqnum )
132 {
133     struct atphdr       hdr;
134
135     /* fill in the packet fields */
136     *(pktbuf->atpbuf_info.atpbuf_data) = DDPTYPE_ATP;
137     hdr.atphd_ctrlinfo = ctrl;
138     hdr.atphd_bitmap = seqnum;
139     hdr.atphd_tid = htons( tid );
140     memcpy(pktbuf->atpbuf_info.atpbuf_data + 1, &hdr, 
141            sizeof( struct atphdr ));
142     memcpy(pktbuf->atpbuf_info.atpbuf_data + ATP_HDRSIZE,
143           atpb->atp_sresiov[ seqnum ].iov_base,
144           atpb->atp_sresiov[ seqnum ].iov_len ); 
145
146     /* set length
147     */
148     pktbuf->atpbuf_dlen = ATP_HDRSIZE + (size_t) atpb->atp_sresiov[ seqnum ].iov_len;
149 }
150
151
152 int
153 atp_recv_atp( ATP ah,
154               struct sockaddr_at *fromaddr,
155               u_int8_t *func,
156               u_int16_t tid,
157               char *rbuf,
158               int wait )
159 {
160 /* 
161   Receive a packet from address fromaddr of the correct function type
162   and with the correct tid.  fromaddr = AT_ANY... and function == ATP_TYPEANY
163   and tid == ATP_TIDANY can be used to wildcard match.
164   
165   recv_atp returns the length of the packet received (or -1 if error)
166   The function code for the packet received is returned in *func (ATP_TREQ or
167     ATP_TRESP).
168 */
169     struct atpbuf       *pq, *cq;
170     struct atphdr       ahdr;
171     u_int16_t           rfunc;
172     u_int16_t           rtid;
173     int                 i;
174     int                 dlen = -1;
175     int                 recvlen;
176     struct sockaddr_at  faddr;
177     SOCKLEN_T           faddrlen;
178     struct atpbuf       *inbuf;
179
180     tid = htons( tid );
181
182     /* first check the queue
183     */
184 #ifdef EBUG
185     atp_print_bufuse( ah, "recv_atp checking queue" );
186 #endif /* EBUG */
187     for ( pq = NULL, cq = ah->atph_queue; cq != NULL;
188       pq = cq, cq = cq->atpbuf_next ) {
189         memcpy(&ahdr, cq->atpbuf_info.atpbuf_data + 1, 
190                sizeof( struct atphdr ));
191         rfunc = ahdr.atphd_ctrlinfo & ATP_FUNCMASK;
192 #ifdef EBUG
193         printf( "<%d> checking", getpid());
194         printf( " tid=%hu func=", ntohs( ahdr.atphd_tid ));
195         print_func( rfunc );
196         atp_print_addr( " from", &cq->atpbuf_addr );
197         putchar( '\n' );
198 #endif /* EBUG */
199         if ((( tid & ahdr.atphd_tid ) == ahdr.atphd_tid ) &&
200             (( *func & rfunc ) == rfunc )
201             && at_addr_eq( fromaddr, &cq->atpbuf_addr )) {
202             break;
203         }
204     }
205     if ( cq != NULL ) {
206         /* we found one in the queue -- copy to rbuf
207         */
208         dlen = (int) cq->atpbuf_dlen;
209         *func = rfunc;
210         memcpy( fromaddr, &cq->atpbuf_addr, sizeof( struct sockaddr_at ));
211         memcpy( rbuf, cq->atpbuf_info.atpbuf_data, cq->atpbuf_dlen );
212
213         /* remove packet from queue and free buffer
214         */
215         if ( pq == NULL ) {
216             ah->atph_queue = NULL;
217         } else {
218             pq->atpbuf_next = cq->atpbuf_next;
219         }
220         atp_free_buf( cq );
221         return( dlen );
222     }
223
224     /* we need to get it the net -- call on ddp to receive a packet
225     */
226 #ifdef EBUG
227     printf( "<%d>", getpid());
228     atp_print_addr( " waiting on address", &ah->atph_saddr );
229     printf( "\nfor tid=%hu func=", ntohs( tid ));
230     print_func( *func );
231     atp_print_addr( " from", fromaddr );
232     putchar( '\n' );
233 #endif /* EBUG */
234
235     do {
236 #ifdef EBUG
237     fflush( stdout );
238 #endif /* EBUG */
239         faddrlen = sizeof( struct sockaddr_at );
240         memset( &faddr, 0, sizeof( struct sockaddr_at ));
241
242         if (( recvlen = netddp_recvfrom( ah->atph_socket, rbuf, 
243                                          ATP_BUFSIZ, 0,
244                                          (struct sockaddr *) &faddr,
245                                          &faddrlen )) < 0 ) {
246             return -1;
247         }
248         memcpy( &ahdr, rbuf + 1, sizeof( struct atphdr ));
249         if ( recvlen >= ATP_HDRSIZE && *rbuf == DDPTYPE_ATP) {
250             /* this is a valid ATP packet -- check for a match */
251             rfunc = ahdr.atphd_ctrlinfo & ATP_FUNCMASK;
252             rtid = ahdr.atphd_tid;
253 #ifdef EBUG
254             printf( "<%d> got tid=%hu func=", getpid(), ntohs( rtid ));
255             print_func( rfunc );
256             atp_print_addr( " from", &faddr );
257             putchar( '\n' );
258             bprint( rbuf, recvlen );
259 #endif /* EBUG */
260             if ( rfunc == ATP_TREL ) {
261                 /* remove response from sent list */
262                 for ( pq = NULL, cq = ah->atph_sent; cq != NULL;
263                   pq = cq, cq = cq->atpbuf_next ) {
264                     if ( at_addr_eq( &faddr, &cq->atpbuf_addr ) &&
265                       cq->atpbuf_info.atpbuf_xo.atpxo_tid == ntohs( rtid )) 
266                         break;
267                 }
268                 if ( cq != NULL ) {
269 #ifdef EBUG
270         printf( "<%d> releasing transaction %hu\n", getpid(), ntohs( rtid ));
271 #endif /* EBUG */
272                     if ( pq == NULL ) {
273                         ah->atph_sent = cq->atpbuf_next;
274                     } else {
275                         pq->atpbuf_next = cq->atpbuf_next;
276                     }
277                     for ( i = 0; i < 8; ++i ) {
278                         if ( cq->atpbuf_info.atpbuf_xo.atpxo_packet[ i ]
279                                     != NULL ) {
280                             atp_free_buf ( cq->atpbuf_info.atpbuf_xo.atpxo_packet[ i ] );
281                         }
282                     }
283                     atp_free_buf( cq );
284                 }
285
286             } else if ((( tid & rtid ) == rtid ) &&
287                     (( *func & rfunc ) == rfunc ) &&
288                     at_addr_eq( fromaddr, &faddr )) { /* got what we wanted */
289                 *func = rfunc;
290                 dlen = recvlen;
291                 memcpy( fromaddr, &faddr, sizeof( struct sockaddr_at ));
292
293             } else {
294                 /* add packet to incoming queue */
295 #ifdef EBUG
296         printf( "<%d> queuing incoming...\n", getpid() );
297 #endif /* EBUG */
298                 if (( inbuf = atp_alloc_buf()) == NULL ) {
299                     return -1;
300                 }
301                 memcpy( &inbuf->atpbuf_addr, &faddr, 
302                         sizeof( struct sockaddr_at ));
303                 inbuf->atpbuf_next = ah->atph_queue;
304                 inbuf->atpbuf_dlen = (size_t) recvlen;
305                 memcpy( inbuf->atpbuf_info.atpbuf_data, rbuf, recvlen );
306             }
307         }
308         if ( !wait && dlen < 0 ) {
309             return( 0 );
310         }
311
312     } while ( dlen < 0 );
313
314     return( dlen );
315 }
316
317
318 int at_addr_eq( paddr, saddr )
319     struct sockaddr_at  *paddr;         /* primary address */
320     struct sockaddr_at  *saddr;         /* secondary address */
321 {
322 /* compare two atalk addresses -- only check the non-zero fields
323     of paddr against saddr.
324    return zero if not equal, non-zero if equal
325 */
326     return (( paddr->sat_port == ATADDR_ANYPORT || paddr->sat_port == saddr->sat_port )
327         &&  ( paddr->sat_addr.s_net == ATADDR_ANYNET ||
328               paddr->sat_addr.s_net == saddr->sat_addr.s_net )
329         &&  ( paddr->sat_addr.s_node == ATADDR_ANYNODE ||
330               paddr->sat_addr.s_node == saddr->sat_addr.s_node ));
331 }
332