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