]> arthur.barton.de Git - netatalk.git/blob - libatalk/atp/atp_packet.c
Previous fix 9e4e07c1811edbaf3376ad6e238a1353b405002b resulted in the inability to...
[netatalk.git] / libatalk / atp / atp_packet.c
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
55 static 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
75 static 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
85 void 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
100 void 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
122 void 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
147 int
148 atp_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
313 int 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