1/* 2 * LICENSE NOTICE. 3 * 4 * Use of the Microsoft Windows Rally Development Kit is covered under 5 * the Microsoft Windows Rally Development Kit License Agreement, 6 * which is provided within the Microsoft Windows Rally Development 7 * Kit or at http://www.microsoft.com/whdc/rally/rallykit.mspx. If you 8 * want a license from Microsoft to use the software in the Microsoft 9 * Windows Rally Development Kit, you must (1) complete the designated 10 * "licensee" information in the Windows Rally Development Kit License 11 * Agreement, and (2) sign and return the Agreement AS IS to Microsoft 12 * at the address provided in the Agreement. 13 */ 14 15/* 16 * Copyright (c) Microsoft Corporation 2005. All rights reserved. 17 * This software is provided with NO WARRANTY. 18 */ 19 20#include <stdio.h> 21#include <string.h> 22#include <assert.h> 23#include <limits.h> 24 25#include "globals.h" 26 27#include "statemachines.h" 28#include "bandfuncs.h" 29#include "packetio.h" 30 31/**************************** 32 * Timeout handlers - 33 * these are the time-based entry points, which also clock the state machine. 34 */ 35 36void 37state_block_timeout(void *cookie) 38{ 39 g_block_timer = NULL; 40 g_this_event.evtType = evtBlockTimeout; 41 state_process_timeout(); 42} 43 44void 45state_charge_timeout(void *cookie) 46{ 47 g_charge_timer = NULL; 48 g_ctc_packets = 0; 49 g_ctc_bytes = 0; 50 g_this_event.evtType = evtChargeTimeout; 51 g_this_event.ssn = (session_t*) cookie; 52 state_process_timeout(); 53} 54 55void 56state_emit_timeout(void *cookie) 57{ 58 g_emit_timer = NULL; 59 g_this_event.evtType = evtEmitTimeout; 60 61 /* Probes are forced to associate with the mapping session, if there is one. */ 62 if (g_topo_session != NULL && g_topo_session->ssn_is_valid) 63 { 64 g_this_event.ssn = g_topo_session; 65 } 66 67 state_process_timeout(); 68} 69 70void 71state_hello_delay_timeout(void *cookie) 72{ 73 g_hello_timer = NULL; 74 g_this_event.evtType = evtHelloDelayTimeout; 75 g_this_event.ssn = (session_t*) cookie; 76 state_process_timeout(); 77} 78 79void 80state_inactivity_timeout(void *cookie) 81{ 82 g_this_event.evtType = evtInactivityTimeout; 83 g_this_event.ssn = (session_t*) cookie; 84 g_this_event.ssn->ssn_InactivityTimer = NULL; 85 state_process_timeout(); 86} 87 88 89/* This function locates an existing session that is associated with the passed-in address */ 90static session_t * 91find_session(etheraddr_t *this_addr) 92{ 93 session_t *ssn = &g_sessions[0]; 94 int i; 95 96 for (i=0; i < MAX_NUM_SESSIONS; ssn++, i++) 97 { 98 if ( (ssn->ssn_is_valid) && (ETHERADDR_EQUALS(&ssn->ssn_mapper_real, this_addr)) ) 99 { 100//*/ DEBUG({printf("find_session returning session %d @ %X\n",i,(uint)ssn);}) 101 return ssn; 102 } 103 } 104//*/DEBUG({puts("find_session returning NULL");}) 105 return NULL; 106} 107 108 109static session_t * 110new_session() 111{ 112 session_t *ssn = &g_sessions[0]; 113 int i; 114 115 for (i=0; i < MAX_NUM_SESSIONS; ssn++, i++) 116 { 117 if ( !(ssn->ssn_is_valid) ) 118 { 119 ssn->ssn_is_valid = TRUE; 120 ssn->ssn_count = BAND_TXC; 121 ssn->ssn_XID = 0; 122 memset(&ssn->ssn_mapper_real,0,sizeof(etheraddr_t)); 123 memset(&ssn->ssn_mapper_current,0,sizeof(etheraddr_t)); 124 ssn->ssn_use_broadcast = TRUE; 125 ssn->ssn_TypeOfSvc = ToS_Unknown; 126 ssn->ssn_InactivityTimer = NULL; 127 return ssn; 128 } 129 } 130 return NULL; 131} 132 133 134/***************************************************************************** 135 * 136 * This code processes the current packet-event (in g_this_event) by locating 137 * (and possibly creating) the session with which it must be associated, 138 * then passing it to the 3 state machines, smS, smE, and smT, in that order. 139 * 140 *****************************************************************************/ 141 142uint 143state_process_packet() 144{ 145 session_t *this_session; 146 enum sm_Status smStatus; 147 148 IF_TRACED((TRC_STATE|TRC_PACKET)) 149 printf("state_process_packet: Entered with event %s",smEvent_names[g_this_event.evtType]); 150 if (g_this_event.evtType==evtPacketRcvd) 151 { 152 printf(" (%s)\n",Topo_opcode_names[g_opcode]); 153 } else { 154 puts(""); 155 } 156 END_TRACE 157 158 g_this_event.isInternalEvt = FALSE; // It's a real event, not internally generated 159 160 /* First, look this RealSrc up in the session table, to 161 * locate any association with an established session. 162 * 163 * If there is no matching session, create a new one, iff the 164 * packet is a valid Discover of either topo- or quick- TOS ... */ 165 166 g_this_event.isNewSession = FALSE; 167 168 if ((this_session = find_session(&g_base_hdr->tbh_realsrc)) == NULL) 169 { 170 /* Not found: Check for a Discovery packet (validated in packetio.c) */ 171 if (g_opcode == Opcode_Discover) 172 { 173 /* Create a new session for this association */ 174 if ((this_session = new_session()) == NULL) 175 { 176 /* No room in the table: drop the packet and whine. */ 177 warn("state_process_packet: no room to create new session. Packet dropped.\n"); 178 return UINT_MAX; 179 } 180 g_this_event.isNewSession = TRUE; 181 182 /* Fill in the newly valid session table entry with info from the packet */ 183 this_session->ssn_XID = g_sequencenum; 184 this_session->ssn_mapper_real = g_base_hdr->tbh_realsrc; 185 this_session->ssn_mapper_current = g_ethernet_hdr->eh_src; 186 this_session->ssn_TypeOfSvc = g_base_hdr->tbh_tos; 187 IF_TRACED(TRC_STATE) 188 printf("New Session:\n\tXID = %X\n\treal address: " ETHERADDR_FMT \ 189 "\n",this_session->ssn_XID, \ 190 ETHERADDR_PRINT(&this_session->ssn_mapper_real) ); 191 192 printf("\tcurrent address: " ETHERADDR_FMT "\n\tToS: %s\n", 193 ETHERADDR_PRINT(&this_session->ssn_mapper_current), 194 Lld2_tos_names[this_session->ssn_TypeOfSvc] ); 195 END_TRACE 196 g_this_event.ssn = this_session; 197 198 } /*** end of if (g_opcode == Opcode_Discover) ***/ 199 200 /* Probes are forced to associate with the mapping session, if there is one. */ 201 if (g_opcode == Opcode_Probe) 202 { 203 if (g_topo_session != NULL && g_topo_session->ssn_is_valid) 204 { 205 this_session = g_topo_session; 206 } 207 } 208 209 } /*** endo of if (find_session()==NULL) ***/ 210 211 /* We have associated whatever session that we can with this packet - pass to state machines */ 212 g_this_event.ssn = this_session; 213 214 smStatus = smS_process_event( &g_this_event ); 215 216 if (smStatus != PROCESSING_ABORTED) 217 { 218 smStatus = smE_process_event( &g_this_event ); 219 } 220 221 if (smStatus != PROCESSING_ABORTED) 222 { 223 smStatus = smT_process_event( &g_this_event ); 224 } 225 226 /* Remove any "new-session" marking */ 227 g_this_event.isNewSession = FALSE; 228 229 IF_TRACED(TRC_PACKET) 230 printf("state_process_packet: Leaving - done with event %s\n",smEvent_names[g_this_event.evtType]); 231 END_TRACE 232 return 0; /* Success! */ 233} 234 235 236/****************************************************************************** 237 * 238 * This code processes the current timeout-event (in g_this_event). Any session 239 * associated with this event (only happens with activity-timeouts) is already 240 * noted in the GLOBAL g_this_event (g_this_event). 241 * 242 ******************************************************************************/ 243 244uint 245state_process_timeout() 246{ 247 enum sm_Status smStatus; 248 249 IF_TRACED(TRC_STATE) 250 if (g_this_event.evtType!=evtBlockTimeout) 251 printf("state_process_timeout: Entered with event %s\n",smEvent_names[g_this_event.evtType]); 252 END_TRACE 253 254 g_rcvd_pkt_len = 0; 255 256 /* Finish initializing the protocol-event */ 257 258 /* g_this_event.evtType = <set in individual timeout handler> */ 259 /* g_this_event.ssn = <set in individual timeout handler> */ 260 g_this_event.isNewSession = FALSE; 261 g_this_event.isAckingMe = FALSE; 262 g_this_event.isInternalEvt = FALSE; // It's a real event, not internally generated 263 g_this_event.numDescrs = 0; 264 265 /* pass Hello-Delay timer events to each existing session's smS state-machine */ 266 if (g_this_event.evtType == evtHelloDelayTimeout) 267 { 268 session_t *ssn = &g_sessions[0]; 269 int i; 270 271 for (i=0; i < MAX_NUM_SESSIONS; ssn++, i++) 272 { 273 if (ssn->ssn_is_valid) 274 { 275 g_this_event.ssn = ssn; 276 smS_process_event( &g_this_event ); 277 } 278 } 279 g_this_event.ssn = NULL; 280 } 281 282 /* Pass per-session activity timeouts to the associated session. The remaining 283 * timeouts, for charge and emit, need only be processed by smE & smT... */ 284 if (g_this_event.evtType == evtInactivityTimeout) 285 { 286 smS_process_event( &g_this_event ); 287 } 288 289 /* send all the timeouts to smE and then smT */ 290 291 smStatus = smE_process_event( &g_this_event ); 292 293 if (smStatus != PROCESSING_ABORTED) 294 { 295 smT_process_event( &g_this_event ); 296 } 297 298 return 0; /* Success! */ 299} 300 301 302/**************************** 303 * Helper functions - 304 * actions performed as part of state processing. 305 */ 306 307/* Restart the inactivity timer for the session associated with the current event */ 308void 309restart_inactivity_timer(uint32_t timeout) 310{ 311 struct timeval now; 312 313 if (g_this_event.ssn == NULL || g_this_event.ssn->ssn_is_valid != TRUE) return; 314 315 gettimeofday(&now, NULL); 316 timeval_add_ms(&now, timeout); 317 CANCEL(g_this_event.ssn->ssn_InactivityTimer); 318 g_this_event.ssn->ssn_InactivityTimer = event_add(&now, state_inactivity_timeout, g_this_event.ssn); 319} 320 321 322/* Searches session table - returns TRUE if all valid sessions are in smS_Complete state */ 323 324bool_t 325OnlyCompleteSessions(void) 326{ 327 session_t *ssn = &g_sessions[0]; 328 int i; 329 330 for (i=0; i < MAX_NUM_SESSIONS; ssn++, i++) 331 { 332 if (ssn->ssn_is_valid && ssn->ssn_state != smS_Complete) 333 { 334 return FALSE; 335 } 336 } 337 return TRUE; 338} 339 340 341/* Searches session table - returns TRUE if all sessions are invalid */ 342 343bool_t 344SessionTableIsEmpty(void) 345{ 346 session_t *ssn = &g_sessions[0]; 347 int i; 348 349 for (i=0; i < MAX_NUM_SESSIONS; ssn++, i++) 350 { 351 if (ssn->ssn_is_valid) 352 { 353 return FALSE; 354 } 355 } 356 return TRUE; 357} 358 359bool_t 360set_emit_timer(void) 361{ 362 topo_emitee_desc_t *ed; 363 364 assert(g_emit_remaining > 0); 365 assert(g_emit_timer == NULL); 366 367 /* get the next emitee_desc and schedule a callback when it is due 368 * to be transmitted */ 369 ed = g_emitdesc; 370 if (ed->ed_pause != 0) 371 { 372 struct timeval now; 373 gettimeofday(&now, NULL); 374 timeval_add_ms(&now, ed->ed_pause); 375 g_emit_timer = event_add(&now, state_emit_timeout, NULL); 376 return TRUE; 377 } else { 378 /* no pause; return PAUSE=FALSE */ 379 return FALSE; 380 } 381} 382