~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to libatalk/atp/atp_packet.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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