1/** 2 * \file 3 * \brief Forwards bulk_transfer traffic 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <stdlib.h> 16 17#include <barrelfish/barrelfish.h> 18#include <barrelfish/nameservice_client.h> 19 20#include <bulk_transfer/bulk_transfer.h> 21#include <bulk_transfer/bulk_sm.h> 22 23// ------------------------------------------------------------------------ 24// Global State 25// ------------------------------------------------------------------------ 26 27enum forward_state { 28 STARTUP, 29 BIND_BOUND, 30 EXPORT_BOUND, 31 RUNNING, 32 UNREACHABLE, 33 ERROR, 34}; 35volatile enum forward_state state; 36 37enum bulk_trust_level fw_trust; 38 39const uint8_t bind = 0; 40char *bind_name; 41struct waitset bind_waitset; 42struct bulk_channel bind_channel; 43 44const uint8_t export = 1; 45char *export_name; 46struct waitset export_waitset; 47struct bulk_channel export_channel; 48 49/** 50 * Wait for given state and dispatch waitsets on the go. 51 */ 52static void wait_state_or_error(enum forward_state cond) 53{ 54 struct bulk_sm_ws_item ws_list[3]; 55 56 ws_list[0].ws = get_default_waitset(); 57 ws_list[1].ws = &bind_waitset; 58 ws_list[2].ws = &export_waitset; 59 ws_list[0].next = &ws_list[1]; 60 ws_list[1].next = &ws_list[2]; 61 ws_list[2].next = NULL; 62 63 while (state != cond && state != ERROR) { 64 errval_t err = bulk_sm_multiple_event_dispatch(ws_list); 65 if (err_is_fail(err)) { 66 USER_PANIC_ERR(err, "wait_state: event_dispach"); 67 } 68 } 69} 70 71/** 72 * Wait for boolean to become true. 73 */ 74static void wait_cond(volatile bool *cond) 75{ 76 struct bulk_sm_ws_item ws_list[3]; 77 78 ws_list[0].ws = get_default_waitset(); 79 ws_list[1].ws = &bind_waitset; 80 ws_list[2].ws = &export_waitset; 81 ws_list[0].next = &ws_list[1]; 82 ws_list[1].next = &ws_list[2]; 83 ws_list[2].next = NULL; 84 85 while (!*cond) { 86 errval_t err = bulk_sm_multiple_event_dispatch(ws_list); 87 if (err_is_fail(err)) { 88 USER_PANIC_ERR(err, "wait_cond: event_dispach"); 89 } 90 } 91} 92 93// ------------------------------------------------------------------------ 94// Traffic Passthrough Helper Functions 95// ------------------------------------------------------------------------ 96 97static inline void wait_enabled(void) 98{ 99 if (state != RUNNING) { 100 wait_state_or_error(RUNNING); 101 } 102} 103 104static inline struct bulk_channel *other_channel(struct bulk_channel *channel) 105{ 106 if (channel == &bind_channel) { 107 return &export_channel; 108 } else { 109 return &bind_channel; 110 } 111} 112 113/** 114 * Holds reply for future response. 115 */ 116struct future_reply { 117 volatile bool valid; 118 errval_t err; 119}; 120 121#define REPLY_INIT ((struct future_reply) { false, SYS_ERR_OK }) 122 123/** 124 * Fill struct future_reply with result. 125 */ 126static void fill_reply_cont(void *arg, errval_t err, 127 struct bulk_channel *channel) 128{ 129 struct future_reply *r = arg; 130 r->err = err; 131 r->valid = true; 132} 133 134/** 135 * Wait for a reply to be filled and return error code. 136 */ 137static errval_t wait_reply(struct future_reply *r) 138{ 139 wait_cond(&r->valid); 140 return r->err; 141} 142 143// ------------------------------------------------------------------------ 144// Traffic Passthrough Callbacks 145// ------------------------------------------------------------------------ 146 147/** 148 * The other endpoint requests to assign a new pool to this channel. 149 * @return If an error value is returned, the pool is not assigned and the 150 * error code is sent to the other side (veto). 151 */ 152static errval_t pool_assigned_fw(struct bulk_channel *channel, 153 struct bulk_pool *pool) 154{ 155 wait_enabled(); 156 157 struct bulk_channel *other = other_channel(channel); 158 159 struct future_reply r = REPLY_INIT; 160 errval_t err = bulk_channel_assign_pool(other, pool, 161 MK_BULK_CONT(fill_reply_cont, &r)); 162 163 if (err_is_fail(err)) { 164 return err; 165 } else { 166 return wait_reply(&r); 167 } 168} 169 170/** 171 * The other endpoint wants to remove a pool from this channel 172 */ 173static errval_t pool_removed_fw(struct bulk_channel *channel, 174 struct bulk_pool *pool) 175{ 176 wait_enabled(); 177 178 struct bulk_channel *other = other_channel(channel); 179 180 struct future_reply r = REPLY_INIT; 181 errval_t err = bulk_channel_remove_pool(other, pool, 182 MK_BULK_CONT(fill_reply_cont, &r)); 183 184 if (err_is_fail(err)) { 185 return err; 186 } else { 187 return wait_reply(&r); 188 } 189} 190 191/** Incoming moved buffer (sink) */ 192static void move_received_fw(struct bulk_channel *channel, 193 struct bulk_buffer *buffer, 194 void *meta) 195{ 196 wait_enabled(); 197 198 struct bulk_channel *other = other_channel(channel); 199 200 struct future_reply r = REPLY_INIT; 201 errval_t err = bulk_channel_move(other, buffer, meta, 202 MK_BULK_CONT(fill_reply_cont, &r)); 203 204 if (err_is_ok(err)) { 205 wait_reply(&r); 206 } 207} 208 209/** Incoming passed buffer (source) */ 210static void buffer_received_fw(struct bulk_channel *channel, 211 struct bulk_buffer *buffer, 212 void *meta) 213{ 214 wait_enabled(); 215 216 struct bulk_channel *other = other_channel(channel); 217 218 struct future_reply r = REPLY_INIT; 219 errval_t err = bulk_channel_pass(other, buffer, meta, 220 MK_BULK_CONT(fill_reply_cont, &r)); 221 222 if (err_is_ok(err)) { 223 wait_reply(&r); 224 } 225} 226 227/** Incoming copied buffer (sink) */ 228static void copy_received_fw(struct bulk_channel *channel, 229 struct bulk_buffer *buffer, 230 void *meta) 231{ 232 wait_enabled(); 233 234 struct bulk_channel *other = other_channel(channel); 235 236 struct future_reply r = REPLY_INIT; 237 errval_t err = bulk_channel_copy(other, buffer, meta, 238 MK_BULK_CONT(fill_reply_cont, &r)); 239 240 if (err_is_ok(err)) { 241 wait_reply(&r); 242 } 243} 244 245/** Released copied buffer (source) */ 246static void copy_released_fw(struct bulk_channel *channel, 247 struct bulk_buffer *buffer) 248{ 249 wait_enabled(); 250 251 struct bulk_channel *other = other_channel(channel); 252 253 struct future_reply r = REPLY_INIT; 254 errval_t err = bulk_channel_release(other, buffer, 255 MK_BULK_CONT(fill_reply_cont, &r)); 256 257 if (err_is_ok(err)) { 258 wait_reply(&r); 259 } 260} 261 262// ------------------------------------------------------------------------ 263// Communication Setup 264// ------------------------------------------------------------------------ 265 266static errval_t export_bound(struct bulk_channel *channel) 267{ 268 assert(state == BIND_BOUND); 269 state = EXPORT_BOUND; 270 return SYS_ERR_OK; 271} 272 273static void bind_bound_cont(void *arg, errval_t err, 274 struct bulk_channel *channel) 275{ 276 assert(state == STARTUP); 277 278 if (err_is_ok(err)) { 279 state = BIND_BOUND; 280 } else { 281 DEBUG_ERR(err, "bind continuation"); 282 state = ERROR; 283 } 284} 285 286struct bulk_channel_callbacks bind_callbacks = { 287 .bind_received = NULL, 288 .teardown_received = NULL, 289 .pool_assigned = pool_assigned_fw, 290 .pool_removed = pool_removed_fw, 291 .move_received = move_received_fw, 292 .buffer_received = buffer_received_fw, 293 .copy_received = copy_received_fw, 294 .copy_released = copy_released_fw, 295}; 296 297struct bulk_channel_callbacks export_callbacks = { 298 .bind_received = export_bound, 299 .teardown_received = NULL, 300 .pool_assigned = pool_assigned_fw, 301 .pool_removed = pool_removed_fw, 302 .move_received = move_received_fw, 303 .buffer_received = buffer_received_fw, 304 .copy_received = copy_received_fw, 305 .copy_released = copy_released_fw, 306}; 307 308/** 309 * This application takes two commandline arguments. It binds to the bulk 310 * transfer interface given as first argument. It exports a bulk transfer 311 * interface as given in the second argument. Traffic is mediated between 312 * the two ports. 313 */ 314int main(int argc, char *argv[]) 315{ 316 if (argc != 4) { 317 debug_printf("bulk_transfer passthrough\n"); 318 debug_printf(" Usage: %s bind export trust\n", argv[0]); 319 return EXIT_FAILURE; 320 } 321 322 bind_name = argv[1]; 323 export_name = argv[2]; 324 fw_trust = ((argv[3][0] == '0') ? BULK_TRUST_NONE : BULK_TRUST_FULL); 325 326 debug_printf("bulk_transfer passthrough: bind=%s, export=%s trust=%s\n", 327 bind_name, export_name, 328 (fw_trust==BULK_TRUST_NONE ? "NONE" : "FULL")); 329 330 errval_t err; 331 332 // Data Initializtaion ------------------------------------------------ 333 state = STARTUP; 334 memset(&bind_channel, 0, sizeof(bind_channel)); 335 memset(&export_channel, 0, sizeof(bind_channel)); 336 waitset_init(&bind_waitset); 337 waitset_init(&export_waitset); 338 339 // Bind --------------------------------------------------------------- 340 debug_printf("Connecting to %s...\n", bind_name); 341 342 iref_t bind_iref; 343 err = nameservice_blocking_lookup(bind_name, &bind_iref); 344 if (err_is_fail(err)) { 345 USER_PANIC_ERR(err, "bind: nameservice_blocking_lookup"); 346 } 347 348 struct bulk_sm_endpoint_descriptor bind_ep; 349 err = bulk_sm_ep_create_remote(&bind_ep, bind_iref); 350 if (err_is_fail(err)) { 351 USER_PANIC_ERR(err, "bind: bulk_sm_ep_create_remote"); 352 } 353 354 struct bulk_channel_bind_params bind_params = { 355 .role = BULK_ROLE_GENERIC, 356 .trust = fw_trust, 357 .waitset = &bind_waitset 358 }; 359 err = bulk_channel_bind(&bind_channel, 360 (struct bulk_endpoint_descriptor*)&bind_ep, 361 &bind_callbacks, &bind_params, 362 MK_BULK_CONT(bind_bound_cont, NULL)); 363 if (err_is_fail(err)) { 364 USER_PANIC_ERR(err, "bind: bulk_channel_bind"); 365 } 366 367 wait_state_or_error(BIND_BOUND); 368 if (state == ERROR) { 369 debug_printf("Error during bind. Exiting.\n"); 370 return EXIT_FAILURE; 371 } 372 373 debug_printf("Bound to %s.\n", bind_name); 374 375 // Export ------------------------------------------------------------- 376 debug_printf("Exporting port to %s...\n", export_name); 377 378 struct bulk_sm_endpoint_descriptor export_ep; 379 err = bulk_sm_ep_create(&export_ep); 380 if (err_is_fail(err)) { 381 USER_PANIC_ERR(err, "export: bulk_sm_ep_create"); 382 } 383 384 enum bulk_channel_direction export_direction = BULK_DIRECTION_TX; 385 if (bind_channel.direction == BULK_DIRECTION_TX) { 386 export_direction = BULK_DIRECTION_RX; 387 } 388 389 enum bulk_channel_role export_role = BULK_ROLE_MASTER; 390 if (bind_channel.role == BULK_ROLE_MASTER) { 391 export_role = BULK_ROLE_SLAVE; 392 } 393 394 struct bulk_channel_setup export_setup = { 395 .direction = export_direction, 396 .role = export_role, 397 .trust = fw_trust, 398 .constraints = bind_channel.constraints, 399 .meta_size = bind_channel.meta_size, 400 .waitset = &export_waitset, 401 .user_state = NULL 402 }; 403 404 err = bulk_channel_create(&export_channel, 405 (struct bulk_endpoint_descriptor*)&export_ep, 406 &export_callbacks, &export_setup); 407 if (err_is_fail(err)) { 408 USER_PANIC_ERR(err, "export: bulk_sm_ep_create"); 409 } 410 411 err = nameservice_register(export_name, export_ep.iref); 412 if (err_is_fail(err)) { 413 USER_PANIC_ERR(err, "export: nameservice_register"); 414 } 415 416 debug_printf("Exported %s.\n", export_name); 417 418 // Wait for domain to connect on exported port ------------------------ 419 debug_printf("Waiting for connection on %s...\n", export_name); 420 421 wait_state_or_error(EXPORT_BOUND); 422 if (state == ERROR) { 423 debug_printf("Error during export. Exiting.\n"); 424 return EXIT_FAILURE; 425 } 426 427 debug_printf("Connected on %s.\n", export_name); 428 429 // Forward messages --------------------------------------------------- 430 debug_printf("Connection %s <-> %s established. Enabeling passthrough.\n", 431 bind_name, export_name); 432 433 assert(state == EXPORT_BOUND); 434 state = RUNNING; 435 436 wait_state_or_error(UNREACHABLE); 437 438 return EXIT_SUCCESS; 439} 440