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 55static 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 75static 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 85void 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 100void 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 122void 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 147int 148atp_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 313int 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 328