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