1/* 2 * $Id: atp_rsel.c,v 1.6 2009-10-14 01:38:28 didg Exp $ 3 * 4 * Copyright (c) 1990,1997 Regents of The University of Michigan. 5 * All Rights Reserved. See COPYRIGHT. 6 */ 7 8#ifdef HAVE_CONFIG_H 9#include "config.h" 10#endif /* HAVE_CONFIG_H */ 11 12#include <string.h> 13#include <sys/types.h> 14#include <sys/time.h> 15#include <sys/uio.h> 16#include <signal.h> 17#include <errno.h> 18 19#include <netatalk/endian.h> 20#include <netatalk/at.h> 21 22#include <atalk/netddp.h> 23#include <atalk/compat.h> 24#include <atalk/atp.h> 25#include <atalk/util.h> 26 27#include "atp_internals.h" 28 29#ifdef DROP_ATPTREL 30static int release_count = 0; 31#endif /* DROP_ATPTREL */ 32 33 34static int 35resend_request(ATP ah) 36{ 37 /* 38 * update bitmap and send request packet 39 */ 40 struct atphdr req_hdr; 41 42#ifdef EBUG 43 printf( "\n<%d> resend_request: resending %ld byte request packet", 44 getpid(), ah->atph_reqpkt->atpbuf_dlen ); 45 atp_print_addr( " to", &ah->atph_reqpkt->atpbuf_addr ); 46 putchar( '\n' ); 47 bprint( ah->atph_reqpkt->atpbuf_info.atpbuf_data, 48 ah->atph_reqpkt->atpbuf_dlen ); 49#endif /* EBUG */ 50 51 memcpy( &req_hdr, ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1, 52 sizeof( struct atphdr )); 53 req_hdr.atphd_bitmap = ah->atph_rbitmap; 54 memcpy( ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1, &req_hdr, 55 sizeof( struct atphdr )); 56 57 gettimeofday( &ah->atph_reqtv, (struct timezone *)0 ); 58 if ( netddp_sendto( ah->atph_socket, 59 ah->atph_reqpkt->atpbuf_info.atpbuf_data, 60 ah->atph_reqpkt->atpbuf_dlen, 0, 61 (struct sockaddr *) &ah->atph_reqpkt->atpbuf_addr, 62 sizeof( struct sockaddr_at )) != ah->atph_reqpkt->atpbuf_dlen ) { 63 return( -1 ); 64 } 65 66 if ( ah->atph_reqtries > 0 ) { 67 --(ah->atph_reqtries); 68 } 69 70 return( 0 ); 71} 72 73int 74atp_rsel( 75 ATP ah, /* open atp handle */ 76 struct sockaddr_at *faddr, /* address to receive from */ 77 int func) /* which function(s) to wait for; 78 0 means request or response */ 79{ 80 struct atpbuf *abuf, *pb, *cb; 81 struct atphdr req_hdr, resp_hdr; 82 fd_set fds; 83 int i, recvlen, requesting, mask, c; 84 u_int8_t rfunc; 85 u_int16_t tid; 86 struct timeval tv; 87 struct sockaddr_at saddr; 88 89#ifdef EBUG 90 atp_print_bufuse( ah, "atp_rsel at top" ); 91#endif /* EBUG */ 92 if ( func == 0 ) { 93 func = ATP_FUNCANY; 94 } 95 96 requesting = ( func & ATP_TRESP ) && ah->atph_rrespcount > 0 && 97 ( ah->atph_reqtries > 0 || ah->atph_reqtries == ATP_TRIES_INFINITE ); 98 99 if ( requesting && ah->atph_rbitmap == 0 ) { 100 /* 101 * we already have a complete atp response; just return 102 */ 103 return( ATP_TRESP ); 104 } 105 106 if (( abuf = atp_alloc_buf()) == NULL ) { 107 return( -1 ); 108 } 109 110 if ( requesting ) { 111#ifdef EBUG 112 printf( "<%d> atp_rsel: request pending\n", getpid()); 113#endif /* EBUG */ 114 gettimeofday( &tv, (struct timezone *)0 ); 115 if ( tv.tv_sec - ah->atph_reqtv.tv_sec > ah->atph_reqto ) { 116 if ( resend_request( ah ) < 0 ) { 117 atp_free_buf( abuf ); 118 return( -1 ); 119 } 120 } 121 } 122 123 for ( ;; ) { 124 rfunc = func; 125 if ( requesting ) { 126 FD_ZERO( &fds ); 127 FD_SET( ah->atph_socket, &fds ); 128 tv.tv_sec = ah->atph_reqto; 129 tv.tv_usec = 0; 130 if (( c = select( ah->atph_socket + 1, &fds, NULL, NULL, 131 &tv )) < 0 ) { 132 atp_free_buf( abuf ); 133 return( -1 ); 134 } 135 if ( c == 0 || FD_ISSET( ah->atph_socket, &fds ) == 0 ) { 136 recvlen = -1; 137 errno = EINTR; 138 goto timeout; 139 } 140 } 141 memcpy( &saddr, faddr, sizeof( struct sockaddr_at )); 142#ifdef EBUG 143 printf( "<%d> atp_rsel calling recv_atp,", getpid()); 144 atp_print_addr( " accepting from: ", &saddr ); 145 putchar( '\n' ); 146#endif /* EBUG */ 147 if (( recvlen = atp_recv_atp( ah, &saddr, &rfunc, ATP_TIDANY, 148 abuf->atpbuf_info.atpbuf_data, 0 )) >= 0 ) { 149 break; /* we received something */ 150 } 151 152timeout : 153 if ( !requesting || errno != EINTR ) { 154 break; /* error */ 155 } 156 157 if ( ah->atph_reqtries <= 0 && 158 ah->atph_reqtries != ATP_TRIES_INFINITE ) { 159 errno = ETIMEDOUT; 160 break; 161 } 162 163 if ( resend_request( ah ) < 0 ) { 164 break; /* error */ 165 } 166 } 167 168 if ( recvlen <= 0 ) { /* error */ 169 atp_free_buf( abuf ); 170 return( recvlen ); 171 } 172 173#ifdef EBUG 174 printf( "<%d> atp_rsel: rcvd %d bytes", getpid(), recvlen ); 175 atp_print_addr( " from: ", &saddr ); 176 putchar( '\n' ); 177 bprint( abuf->atpbuf_info.atpbuf_data, recvlen ); 178#endif /* EBUG */ 179 180 abuf->atpbuf_dlen = (size_t) recvlen; 181 memcpy( &resp_hdr, abuf->atpbuf_info.atpbuf_data + 1, 182 sizeof( struct atphdr )); 183 184 if ( rfunc == ATP_TREQ ) { 185 /* 186 * we got a request: check to see if it is a duplicate (XO) 187 * while we are at it, we expire old XO responses from sent list 188 */ 189 memcpy( &req_hdr, abuf->atpbuf_info.atpbuf_data + 1, 190 sizeof( struct atphdr )); 191 tid = ntohs( req_hdr.atphd_tid ); 192 gettimeofday( &tv, (struct timezone *)0 ); 193 for ( pb = NULL, cb = ah->atph_sent; cb != NULL; 194 pb = cb, cb = cb->atpbuf_next ) { 195#ifdef EBUG 196 printf( "<%d>", getpid()); 197 atp_print_addr( " examining", &cb->atpbuf_addr ); 198 printf( " %hu", cb->atpbuf_info.atpbuf_xo.atpxo_tid ); 199 atp_print_addr( " (looking for", &saddr ); 200 printf( " %hu)\n", tid ); 201#endif /* EBUG */ 202 if ( tv.tv_sec - cb->atpbuf_info.atpbuf_xo.atpxo_tv.tv_sec 203 > cb->atpbuf_info.atpbuf_xo.atpxo_reltime ) { 204 /* discard expired response */ 205#ifdef EBUG 206 printf( "<%d> expiring tid %hu\n", getpid(), 207 cb->atpbuf_info.atpbuf_xo.atpxo_tid ); 208#endif /* EBUG */ 209 if ( pb == NULL ) { 210 ah->atph_sent = cb->atpbuf_next; 211 } else { 212 pb->atpbuf_next = cb->atpbuf_next; 213 } 214 215 for ( i = 0; i < 8; ++i ) { 216 if ( cb->atpbuf_info.atpbuf_xo.atpxo_packet[ i ] 217 != NULL ) { 218 atp_free_buf( cb->atpbuf_info.atpbuf_xo.atpxo_packet[ i ] ); 219 } 220 } 221 atp_free_buf( cb ); 222 223 if (( cb = pb ) == NULL ) 224 break; 225 226 } else if ( at_addr_eq( &saddr, &cb->atpbuf_addr )) { 227 if ( cb->atpbuf_info.atpbuf_xo.atpxo_tid == tid ) { 228 break; 229 } 230 } 231 } 232 233 if ( cb != NULL ) { 234#ifdef EBUG 235 printf( "<%d> duplicate request -- re-sending XO resp\n", 236 getpid()); 237#endif /* EBUG */ 238 /* matches an old response -- just re-send and reset expire */ 239 cb->atpbuf_info.atpbuf_xo.atpxo_tv = tv; 240 for ( i = 0; i < 8; ++i ) { 241 if ( cb->atpbuf_info.atpbuf_xo.atpxo_packet[i] != NULL && 242 req_hdr.atphd_bitmap & ( 1 << i )) { 243 netddp_sendto( ah->atph_socket, 244 cb->atpbuf_info.atpbuf_xo.atpxo_packet[i]->atpbuf_info.atpbuf_data, 245 cb->atpbuf_info.atpbuf_xo.atpxo_packet[i]->atpbuf_dlen, 246 0, (struct sockaddr *) &saddr, sizeof( struct sockaddr_at)); 247 } 248 } 249 } 250 251 if ( cb == NULL ) { 252 /* new request -- queue it and return */ 253 memcpy( &abuf->atpbuf_addr, &saddr, sizeof( struct sockaddr_at )); 254 memcpy( faddr, &saddr, sizeof( struct sockaddr_at )); 255 abuf->atpbuf_next = ah->atph_queue; 256 ah->atph_queue = abuf; 257 return( ATP_TREQ ); 258 } else { 259 atp_free_buf( abuf ); 260 return( 0 ); 261 } 262 } 263 264 /* 265 * we got a response: update bitmap 266 */ 267 memcpy( &req_hdr, ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1, 268 sizeof( struct atphdr )); 269 if ( requesting && ah->atph_rbitmap & ( 1<<resp_hdr.atphd_bitmap ) 270 && req_hdr.atphd_tid == resp_hdr.atphd_tid ) { 271 ah->atph_rbitmap &= ~( 1<<resp_hdr.atphd_bitmap ); 272 273 if ( ah->atph_resppkt[ resp_hdr.atphd_bitmap ] != NULL ) { 274 atp_free_buf( ah->atph_resppkt[ resp_hdr.atphd_bitmap ] ); 275 } 276 ah->atph_resppkt[ resp_hdr.atphd_bitmap ] = abuf; 277 278 /* if End Of Message, clear all higher bitmap bits 279 */ 280 if ( resp_hdr.atphd_ctrlinfo & ATP_EOM ) { 281#ifdef EBUG 282 printf( "<%d> EOM -- seq num %d current bitmap %d\n", 283 getpid(), resp_hdr.atphd_bitmap, ah->atph_rbitmap ); 284#endif /* EBUG */ 285 mask = 1 << resp_hdr.atphd_bitmap; 286 ah->atph_rbitmap &= ( mask | (mask-1) ); 287 } 288 289 /* if Send Trans. Status, send updated request 290 */ 291 if ( resp_hdr.atphd_ctrlinfo & ATP_STS ) { 292#ifdef EBUG 293 puts( "STS" ); 294#endif /* EBUG */ 295 req_hdr.atphd_bitmap = ah->atph_rbitmap; 296 memcpy(ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1, 297 &req_hdr, sizeof( struct atphdr )); 298 if ( netddp_sendto( ah->atph_socket, 299 ah->atph_reqpkt->atpbuf_info.atpbuf_data, 300 ah->atph_reqpkt->atpbuf_dlen, 0, 301 (struct sockaddr *) &ah->atph_reqpkt->atpbuf_addr, 302 sizeof( struct sockaddr_at )) != 303 ah->atph_reqpkt->atpbuf_dlen ) { 304 atp_free_buf( abuf ); 305 return( -1 ); 306 } 307 } 308 } else { 309 /* 310 * we are not expecting this response -- toss it 311 */ 312 atp_free_buf( abuf ); 313#ifdef EBUG 314 printf( "atp_rsel: ignoring resp bm=%x tid=%d (expected %x/%d)\n", 315 resp_hdr.atphd_bitmap, ntohs( resp_hdr.atphd_tid ), 316 ah->atph_rbitmap, ah->atph_tid ); 317#endif /* EBUG */ 318 } 319 320 if ( !ah->atph_rbitmap && ( req_hdr.atphd_ctrlinfo & ATP_XO )) { 321 /* 322 * successful completion - send release 323 * the release consists of DDP type byte + ATP header + 4 user bytes 324 */ 325 req_hdr.atphd_ctrlinfo = ATP_TREL; 326 memcpy( ah->atph_reqpkt->atpbuf_info.atpbuf_data + 1, &req_hdr, 327 sizeof( struct atphdr )); 328 memset( ah->atph_reqpkt->atpbuf_info.atpbuf_data + ATP_HDRSIZE, 0, 4 ); 329 ah->atph_reqpkt->atpbuf_dlen = sizeof( struct atphdr ) + ATP_HDRSIZE; 330#ifdef EBUG 331 printf( "<%d> sending TREL", getpid() ); 332 bprint( ah->atph_reqpkt->atpbuf_info.atpbuf_data, 333 ah->atph_reqpkt->atpbuf_dlen ); 334#endif /* EBUG */ 335#ifdef DROP_ATPTREL 336 if (( ++release_count % 10 ) != 0 ) { 337#endif /* DROP_ATPTREL */ 338 netddp_sendto( ah->atph_socket, 339 ah->atph_reqpkt->atpbuf_info.atpbuf_data, 340 ah->atph_reqpkt->atpbuf_dlen, 0, 341 (struct sockaddr *) &ah->atph_reqpkt->atpbuf_addr, 342 sizeof( struct sockaddr_at)); 343#ifdef DROP_ATPTREL 344 } 345#endif /* DROP_ATPTREL */ 346 } 347 348 if ( ah->atph_rbitmap != 0 ) { 349 if ( ah->atph_reqtries > 0 350 || ah->atph_reqtries == ATP_TRIES_INFINITE ) { 351 return( 0 ); 352 } else { 353 errno = ETIMEDOUT; 354 return( -1 ); 355 } 356 } 357 358 memcpy( faddr, &saddr, sizeof( struct sockaddr_at )); 359 return( ATP_TRESP ); 360} 361