1 /* 2 * Copyright 2008 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com 3 * 4 * All rights reserved. Distributed under the terms of the MIT License. 5 * 6 */ 7 8 9 #include "BluetoothServer.h" 10 11 #include "LocalDeviceImpl.h" 12 #include "CommandManager.h" 13 #include "Output.h" 14 15 #include <bluetooth/bdaddrUtils.h> 16 #include <bluetooth/RemoteDevice.h> 17 #include <bluetooth/bluetooth_error.h> 18 #include <bluetooth/HCI/btHCI_event.h> 19 20 #include <bluetoothserver_p.h> 21 #include <ConnectionIncoming.h> 22 #include <PincodeWindow.h> 23 24 #include <stdio.h> 25 26 27 #if 0 28 #pragma mark - Class methods - 29 #endif 30 31 32 // Factory methods 33 LocalDeviceImpl* 34 LocalDeviceImpl::CreateControllerAccessor(BPath* path) 35 { 36 HCIDelegate* hd = new HCIControllerAccessor(path); 37 38 if ( hd != NULL) 39 return new LocalDeviceImpl(hd); 40 else 41 return NULL; 42 } 43 44 45 LocalDeviceImpl* 46 LocalDeviceImpl::CreateTransportAccessor(BPath* path) 47 { 48 HCIDelegate* hd = new HCITransportAccessor(path); 49 50 if ( hd != NULL) 51 return new LocalDeviceImpl(hd); 52 else 53 return NULL; 54 } 55 56 57 LocalDeviceImpl::LocalDeviceImpl(HCIDelegate* hd) : LocalDeviceHandler(hd) 58 { 59 60 } 61 62 #if 0 63 #pragma mark - Event handling methods - 64 #endif 65 66 void 67 LocalDeviceImpl::HandleEvent(struct hci_event_header* event) 68 { 69 70 printf("### Incoming event: len = %d\n", event->elen); 71 for (int16 index = 0 ; index < event->elen + 2; index++ ) { 72 printf("%x:",((uint8*)event)[index]); 73 } 74 printf("### \n"); 75 76 // Events here might have not been initated by us 77 // TODO: ML mark as handled pass a reply by parameter and reply in common 78 switch (event->ecode) { 79 case HCI_EVENT_HARDWARE_ERROR: 80 //HardwareError(event); 81 return; 82 case HCI_EVENT_CONN_REQUEST: 83 ConnectionRequest((struct hci_ev_conn_request*)(event+1), NULL); // incoming request 84 return; 85 break; 86 87 case HCI_EVENT_CONN_COMPLETE: 88 ConnectionComplete((struct hci_ev_conn_complete*)(event+1), NULL); // should belong to a request? 89 return; // can be sporadic or initiated by us¿?... 90 break; 91 92 case HCI_EVENT_PIN_CODE_REQ: 93 PinCodeRequest((struct hci_ev_pin_code_req*)(event+1), NULL); 94 return; 95 break; 96 97 98 default: 99 // lets go on 100 break; 101 } 102 103 104 105 BMessage* request = NULL; 106 int32 eventIndexLocation; 107 108 // Check if its a requested one 109 if ( event->ecode == HCI_EVENT_CMD_COMPLETE ) { 110 111 (Output::Instance()->Post("Incoming Command Complete\n", BLACKBOARD_EVENTS)); 112 request = FindPetition(event->ecode, ((struct hci_ev_cmd_complete*)(event+1))->opcode, &eventIndexLocation ); 113 114 } else if ( event->ecode == HCI_EVENT_CMD_STATUS ) { 115 116 (Output::Instance()->Post("Incoming Command Status\n", BLACKBOARD_EVENTS)); 117 request = FindPetition(event->ecode, ((struct hci_ev_cmd_status*)(event+1))->opcode, &eventIndexLocation ); 118 119 } else 120 { 121 request = FindPetition(event->ecode); 122 } 123 124 if ( request == NULL) { 125 (Output::Instance()->Post("Event could not be understood or delivered\n", BLACKBOARD_EVENTS)); 126 return; 127 } 128 129 // we are waiting for a reply 130 switch (event->ecode) { 131 case HCI_EVENT_INQUIRY_COMPLETE: 132 InquiryComplete((uint8*)(event+1), request); 133 break; 134 135 case HCI_EVENT_INQUIRY_RESULT: 136 InquiryResult((uint8*)(event+1), request); 137 break; 138 139 case HCI_EVENT_DISCONNECTION_COMPLETE: 140 DisconnectionComplete((struct hci_ev_disconnection_complete_reply*)(event+1), request); 141 break; 142 143 case HCI_EVENT_AUTH_COMPLETE: 144 break; 145 146 case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: 147 RemoteNameRequestComplete((struct hci_ev_remote_name_request_complete_reply*)(event+1), request); 148 break; 149 150 case HCI_EVENT_ENCRYPT_CHANGE: 151 break; 152 153 case HCI_EVENT_CHANGE_CONN_LINK_KEY_COMPLETE: 154 break; 155 156 case HCI_EVENT_MASTER_LINK_KEY_COMPL: 157 break; 158 159 case HCI_EVENT_RMT_FEATURES: 160 break; 161 162 case HCI_EVENT_RMT_VERSION: 163 break; 164 165 case HCI_EVENT_QOS_SETUP_COMPLETE: 166 break; 167 168 case HCI_EVENT_CMD_COMPLETE: 169 CommandComplete((struct hci_ev_cmd_complete*)(event+1), request, eventIndexLocation); 170 break; 171 172 case HCI_EVENT_CMD_STATUS: 173 CommandStatus((struct hci_ev_cmd_status*)(event+1), request, eventIndexLocation); 174 break; 175 176 case HCI_EVENT_FLUSH_OCCUR: 177 break; 178 179 case HCI_EVENT_ROLE_CHANGE: 180 RoleChange((struct hci_ev_role_change*)(event+1), request, eventIndexLocation); 181 break; 182 183 case HCI_EVENT_NUM_COMP_PKTS: 184 break; 185 186 case HCI_EVENT_MODE_CHANGE: 187 break; 188 189 case HCI_EVENT_RETURN_LINK_KEYS: 190 break; 191 192 case HCI_EVENT_LINK_KEY_REQ: 193 break; 194 195 case HCI_EVENT_LINK_KEY_NOTIFY: 196 LinkKeyNotify((struct hci_ev_link_key_notify*)(event+1), request, eventIndexLocation); 197 break; 198 199 case HCI_EVENT_LOOPBACK_COMMAND: 200 break; 201 202 case HCI_EVENT_DATA_BUFFER_OVERFLOW: 203 break; 204 205 case HCI_EVENT_MAX_SLOT_CHANGE: 206 break; 207 208 case HCI_EVENT_READ_CLOCK_OFFSET_COMPL: 209 break; 210 211 case HCI_EVENT_CON_PKT_TYPE_CHANGED: 212 break; 213 214 case HCI_EVENT_QOS_VIOLATION: 215 break; 216 217 case HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE: 218 PageScanRepetitionModeChange((struct hci_ev_page_scan_rep_mode_change*)(event+1), request, eventIndexLocation); 219 break; 220 221 case HCI_EVENT_FLOW_SPECIFICATION: 222 break; 223 224 case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI: 225 break; 226 227 case HCI_EVENT_REMOTE_EXTENDED_FEATURES: 228 break; 229 230 case HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETED: 231 break; 232 233 case HCI_EVENT_SYNCHRONOUS_CONNECTION_CHANGED: 234 235 break; 236 } 237 238 } 239 240 241 void 242 LocalDeviceImpl::CommandComplete(struct hci_ev_cmd_complete* event, BMessage* request, int32 index) { 243 244 int16 opcodeExpected; 245 BMessage reply; 246 247 Output::Instance()->Post(__FUNCTION__, BLACKBOARD_LD(GetID())); 248 Output::Instance()->Post("\n", BLACKBOARD_LD(GetID())); 249 250 // Handle command complete information 251 request->FindInt16("opcodeExpected", index, &opcodeExpected); 252 253 254 if (request->IsSourceWaiting() == false) 255 Output::Instance()->Post("Nobody waiting for the event\n", BLACKBOARD_KIT); 256 257 switch (opcodeExpected) { 258 259 case PACK_OPCODE(OGF_INFORMATIONAL_PARAM, OCF_READ_BD_ADDR): 260 { 261 struct hci_rp_read_bd_addr* readbdaddr = (struct hci_rp_read_bd_addr*)(event+1); 262 263 if (readbdaddr->status == BT_OK) { 264 265 reply.AddData("bdaddr", B_ANY_TYPE, &readbdaddr->bdaddr, sizeof(bdaddr_t)); 266 reply.AddInt32("status", readbdaddr->status); 267 268 printf("Sending reply ... %ld\n",request->SendReply(&reply)); 269 reply.PrintToStream(); 270 271 Output::Instance()->Post("Positive reply for getAddress\n", BLACKBOARD_KIT); 272 273 } else { 274 reply.AddInt8("status", readbdaddr->status); 275 request->SendReply(&reply); 276 Output::Instance()->Post("Negative reply for getAddress\n", BLACKBOARD_KIT); 277 } 278 279 // This request is not gonna be used anymore 280 ClearWantedEvent(request); 281 } 282 break; 283 284 case PACK_OPCODE(OGF_CONTROL_BASEBAND, OCF_READ_LOCAL_NAME): 285 { 286 struct hci_rp_read_local_name* readLocalName = (struct hci_rp_read_local_name*)(event+1); 287 288 reply.AddInt8("status", readLocalName->status); 289 290 if (readLocalName->status == BT_OK) { 291 292 reply.AddString("friendlyname", (const char*)readLocalName->local_name ); 293 Output::Instance()->Post("Positive reply for friendly name\n", BLACKBOARD_KIT); 294 295 } else { 296 297 Output::Instance()->Post("Negative reply for friendly name\n", BLACKBOARD_KIT); 298 299 } 300 301 printf("Sending reply ... %ld\n",request->SendReply(&reply)); 302 reply.PrintToStream(); 303 304 // This request is not gonna be used anymore 305 ClearWantedEvent(request); 306 } 307 break; 308 309 case PACK_OPCODE(OGF_CONTROL_BASEBAND, OCF_WRITE_SCAN_ENABLE): 310 { 311 uint8* statusReply = (uint8*)(event+1); 312 313 reply.AddInt8("status", *statusReply); 314 315 if (*statusReply == BT_OK) { 316 317 Output::Instance()->Post("Positive reply for scanmode\n", BLACKBOARD_KIT); 318 319 } else { 320 321 Output::Instance()->Post("Negative reply for scanmode\n", BLACKBOARD_KIT); 322 323 } 324 325 printf("Sending reply ... %ld\n",request->SendReply(&reply)); 326 reply.PrintToStream(); 327 328 // This request is not gonna be used anymore 329 ClearWantedEvent(request); 330 } 331 break; 332 case PACK_OPCODE(OGF_LINK_CONTROL, OCF_PIN_CODE_REPLY): 333 { 334 uint8* statusReply = (uint8*)(event+1); 335 //TODO: This reply has to match the BDADDR of the outgoing message 336 reply.AddInt8("status", *statusReply); 337 338 if (*statusReply == BT_OK) { 339 340 Output::Instance()->Post("Positive reply for pincode accept\n", BLACKBOARD_KIT); 341 342 } else { 343 344 Output::Instance()->Post("Negative reply for pincode accept\n", BLACKBOARD_KIT); 345 346 } 347 348 printf("Sending reply ... %ld\n",request->SendReply(&reply)); 349 reply.PrintToStream(); 350 351 // This request is not gonna be used anymore 352 ClearWantedEvent(request); 353 } 354 break; 355 356 357 case PACK_OPCODE(OGF_LINK_CONTROL, OCF_PIN_CODE_NEG_REPLY): 358 { 359 uint8* statusReply = (uint8*)(event+1); 360 //TODO: This reply might to match the BDADDR of the outgoing message 361 // xxx:FindPetition should be expanded.... 362 reply.AddInt8("status", *statusReply); 363 364 if (*statusReply == BT_OK) { 365 366 Output::Instance()->Post("Positive reply for pincode reject\n", BLACKBOARD_KIT); 367 368 } else { 369 370 Output::Instance()->Post("Negative reply for pincode reject\n", BLACKBOARD_KIT); 371 372 } 373 374 printf("Sending reply ... %ld\n",request->SendReply(&reply)); 375 reply.PrintToStream(); 376 377 // This request is not gonna be used anymore 378 ClearWantedEvent(request); 379 } 380 break; 381 382 383 default: 384 Output::Instance()->Post("Command Complete not handled\n", BLACKBOARD_KIT); 385 break; 386 387 } 388 } 389 390 391 void 392 LocalDeviceImpl::CommandStatus(struct hci_ev_cmd_status* event, BMessage* request, int32 index) { 393 394 int16 opcodeExpected; 395 BMessage reply; 396 397 Output::Instance()->Post(__FUNCTION__, BLACKBOARD_LD(GetID())); 398 Output::Instance()->Post("\n", BLACKBOARD_LD(GetID())); 399 400 // Handle command complete information 401 request->FindInt16("opcodeExpected", index, &opcodeExpected); 402 403 404 if (request->IsSourceWaiting() == false) 405 Output::Instance()->Post("Nobody waiting for the event\n", BLACKBOARD_KIT); 406 407 switch (opcodeExpected) { 408 409 case PACK_OPCODE(OGF_LINK_CONTROL, OCF_INQUIRY): 410 { 411 reply.what = BT_MSG_INQUIRY_STARTED; 412 reply.AddInt8("status", event->status); 413 414 if (event->status == BT_OK) { 415 Output::Instance()->Post("Positive reply for inquiry status\n", BLACKBOARD_KIT); 416 } else { 417 Output::Instance()->Post("Negative reply for inquiry status\n", BLACKBOARD_KIT); 418 } 419 420 printf("Sending reply ... %ld\n", request->SendReply(&reply)); 421 reply.PrintToStream(); 422 423 ClearWantedEvent(request, HCI_EVENT_CMD_STATUS, PACK_OPCODE(OGF_LINK_CONTROL, OCF_INQUIRY)); 424 } 425 break; 426 427 case PACK_OPCODE(OGF_LINK_CONTROL, OCF_REMOTE_NAME_REQUEST): 428 { 429 if (event->status==BT_OK) { 430 ClearWantedEvent(request, HCI_EVENT_CMD_STATUS, PACK_OPCODE(OGF_LINK_CONTROL, OCF_REMOTE_NAME_REQUEST)); 431 } 432 else { 433 BMessage reply; 434 reply.AddInt8("status", event->status); 435 Output::Instance()->Post("Negative reply for remote friendly name\n", BLACKBOARD_KIT); 436 printf("Sending reply ... %ld\n", request->SendReply(&reply)); 437 ClearWantedEvent(request); 438 } 439 } 440 break; 441 /* 442 case PACK_OPCODE(OGF_LINK_CONTROL, OCF_ACCEPT_CONN_REQ): 443 { 444 ClearWantedEvent(request, HCI_EVENT_CMD_STATUS, PACK_OPCODE(OGF_LINK_CONTROL, OCF_ACCEPT_CONN_REQ)); 445 } 446 break; 447 448 case PACK_OPCODE(OGF_LINK_CONTROL, OCF_REJECT_CONN_REQ): 449 { 450 ClearWantedEvent(request, HCI_EVENT_CMD_STATUS, PACK_OPCODE(OGF_LINK_CONTROL, OCF_REJECT_CONN_REQ)); 451 } 452 break;*/ 453 454 455 default: 456 Output::Instance()->Post("Command Status not handled\n", BLACKBOARD_KIT); 457 break; 458 } 459 460 } 461 462 463 void 464 LocalDeviceImpl::InquiryResult(uint8* numberOfResponses, BMessage* request) 465 { 466 467 BMessage reply(BT_MSG_INQUIRY_DEVICE); 468 469 470 reply.AddData("info", B_ANY_TYPE, numberOfResponses+1 // skipping here the number of responses 471 , (*numberOfResponses) * sizeof(struct inquiry_info) ); 472 473 printf("%s: Sending reply ... %ld\n",__FUNCTION__, request->SendReply(&reply)); 474 475 } 476 477 478 void 479 LocalDeviceImpl::InquiryComplete(uint8* status, BMessage* request) 480 { 481 BMessage reply(BT_MSG_INQUIRY_COMPLETED); 482 483 reply.AddInt8("status", *status); 484 485 486 printf("%s: Sending reply ... %ld\n",__FUNCTION__, request->SendReply(&reply)); 487 // (request->ReturnAddress()).SendMessage(&reply); 488 489 ClearWantedEvent(request); 490 } 491 492 493 void 494 LocalDeviceImpl::RemoteNameRequestComplete(struct hci_ev_remote_name_request_complete_reply* remotename, BMessage* request) 495 { 496 BMessage reply; 497 498 reply.AddInt8("status", remotename->status); 499 500 if (remotename->status == BT_OK) { 501 502 reply.AddString("friendlyname", (const char*)remotename->remote_name ); 503 Output::Instance()->Post("Positive reply for remote friendly name\n", BLACKBOARD_KIT); 504 505 } else { 506 507 Output::Instance()->Post("Negative reply for remote friendly name\n", BLACKBOARD_KIT); 508 509 } 510 511 printf("Sending reply ... %ld\n", request->SendReply(&reply)); 512 reply.PrintToStream(); 513 514 // This request is not gonna be used anymore 515 ClearWantedEvent(request); 516 } 517 518 519 void 520 LocalDeviceImpl::ConnectionRequest(struct hci_ev_conn_request* event, BMessage* request) 521 { 522 size_t size; 523 void* command; 524 525 printf("Connection type %d from %s\n", event->link_type, bdaddrUtils::ToString(event->bdaddr)); 526 (Output::Instance()->Post("Connection Incoming ...\n", BLACKBOARD_EVENTS)); 527 528 529 /* TODO: add a possible request in the queue */ 530 if (true) { // Check Preferences if we are to accept this connection 531 command = buildAcceptConnectionRequest(event->bdaddr, 0x01 /*slave*/, &size); 532 533 534 BMessage* newrequest = new BMessage; 535 newrequest->AddInt16("eventExpected", HCI_EVENT_CMD_STATUS); 536 newrequest->AddInt16("opcodeExpected", PACK_OPCODE(OGF_LINK_CONTROL, OCF_ACCEPT_CONN_REQ)); 537 538 newrequest->AddInt16("eventExpected", HCI_EVENT_PIN_CODE_REQ); 539 newrequest->AddInt16("eventExpected", HCI_EVENT_ROLE_CHANGE); 540 newrequest->AddInt16("eventExpected", HCI_EVENT_LINK_KEY_NOTIFY); 541 newrequest->AddInt16("eventExpected", HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE); 542 543 AddWantedEvent(newrequest); 544 545 if ((fHCIDelegate)->IssueCommand(command, size) == B_ERROR) { 546 (Output::Instance()->Post("Command issue error for ConnAccpq\n", BLACKBOARD_EVENTS)); 547 // remove the request 548 549 } 550 else { 551 (Output::Instance()->Post("Command issued for ConnAccp\n", BLACKBOARD_EVENTS)); 552 553 554 } 555 } 556 557 } 558 559 560 void 561 LocalDeviceImpl::ConnectionComplete(struct hci_ev_conn_complete* event, BMessage* request) 562 { 563 564 if (event->status == BT_OK) { 565 566 ConnectionIncoming* iConnection = new ConnectionIncoming(new RemoteDevice(event->bdaddr)); 567 iConnection->Show(); 568 printf("%s: Address %s handle=%#x type=%d encrypt=%d\n", __FUNCTION__, bdaddrUtils::ToString(event->bdaddr), event->handle, 569 event->link_type, event->encrypt_mode); 570 571 } else { 572 printf("%s: failed with status %#x\n", __FUNCTION__, event->status); 573 } 574 575 576 577 } 578 579 580 void 581 LocalDeviceImpl::DisconnectionComplete(struct hci_ev_disconnection_complete_reply* event, BMessage * request) 582 { 583 Output::Instance()->Post("Disconnected\n", BLACKBOARD_KIT); 584 } 585 586 587 void 588 LocalDeviceImpl::PinCodeRequest(struct hci_ev_pin_code_req* event, BMessage* request) 589 { 590 591 PincodeWindow* iPincode = new PincodeWindow(event->bdaddr, GetID()); 592 iPincode->Show(); 593 594 } 595 596 597 void 598 LocalDeviceImpl::RoleChange(hci_ev_role_change *event, BMessage* request, int32 index) 599 { 600 printf("%s: Address %s role=%d status=%d\n", __FUNCTION__, bdaddrUtils::ToString(event->bdaddr), event->role, event->status); 601 } 602 603 void 604 LocalDeviceImpl::PageScanRepetitionModeChange(struct hci_ev_page_scan_rep_mode_change* event, BMessage* request, int32 index) 605 { 606 printf("%s: Address %s type=%d\n", __FUNCTION__, bdaddrUtils::ToString(event->bdaddr), event->page_scan_rep_mode); 607 } 608 609 610 void 611 LocalDeviceImpl::LinkKeyNotify(hci_ev_link_key_notify *event, BMessage* request, int32 index) 612 { 613 614 printf("%s: Address %s [----] type=%d\n", __FUNCTION__, bdaddrUtils::ToString(event->bdaddr), event->key_type); 615 616 } 617 618 619 #if 0 620 #pragma mark - Request Methods - 621 #endif 622 623 624 status_t 625 LocalDeviceImpl::GetAddress(bdaddr_t* bdaddr, BMessage* request) 626 { 627 ssize_t ssize; 628 629 if (fProperties->FindData("bdaddr", B_ANY_TYPE, 0, (const void **)bdaddr, &ssize) == B_OK) { 630 631 632 /* We have this info, returning back */ 633 return B_OK; 634 635 } else { 636 size_t size; 637 638 void* command = buildReadBdAddr(&size); 639 640 /* Adding a wanted event in the queue */ 641 request->AddInt16("eventExpected", HCI_EVENT_CMD_COMPLETE); 642 request->AddInt16("opcodeExpected", PACK_OPCODE(OGF_INFORMATIONAL_PARAM, OCF_READ_BD_ADDR)); 643 644 AddWantedEvent(request); 645 request->PrintToStream(); 646 647 if (((HCITransportAccessor*)fHCIDelegate)->IssueCommand(command, size) == B_ERROR) 648 (Output::Instance()->Post("Command issue error\n", BLACKBOARD_EVENTS)); 649 650 (Output::Instance()->Post("Command issued for GetAddress\n", BLACKBOARD_EVENTS)); 651 return B_WOULD_BLOCK; 652 } 653 654 } 655 656 657 status_t 658 LocalDeviceImpl::GetFriendlyName(BString str, BMessage* request) 659 { 660 661 if (fProperties->FindString("friendlyname", &str) == B_OK) { 662 663 (Output::Instance()->Post("Friendly name already present in server\n", BLACKBOARD_EVENTS)); 664 /* We have this info, returning back */ 665 return B_OK; 666 667 } else { 668 size_t size; 669 670 void* command = buildReadLocalName(&size); 671 672 /* Adding a wanted event in the queue */ 673 request->AddInt16("eventExpected", HCI_EVENT_CMD_COMPLETE); 674 request->AddInt16("opcodeExpected", PACK_OPCODE(OGF_CONTROL_BASEBAND, OCF_READ_LOCAL_NAME)); 675 676 AddWantedEvent(request); 677 request->PrintToStream(); 678 679 if (((HCITransportAccessor*)fHCIDelegate)->IssueCommand(command, size) == B_ERROR) 680 (Output::Instance()->Post("Command issue error\n", BLACKBOARD_EVENTS)); 681 682 (Output::Instance()->Post("Command issued for GetFriendlyname\n", BLACKBOARD_EVENTS)); 683 684 return B_WOULD_BLOCK; 685 } 686 687 } 688 689 690 status_t 691 LocalDeviceImpl::ProcessSimpleRequest(BMessage* request) 692 { 693 ssize_t size; 694 void* command = NULL; 695 696 if (request->FindData("raw command", B_ANY_TYPE, 0, (const void **)&command, &size) == B_OK) { 697 698 AddWantedEvent(request); 699 700 if (((HCITransportAccessor*)fHCIDelegate)->IssueCommand(command, size) == B_ERROR) { 701 // TODO: - Reply the request with error! 702 // - Remove the just added request 703 (Output::Instance()->Post("Command issue error\n", BLACKBOARD_EVENTS)); 704 } 705 else { 706 707 return B_OK; 708 } 709 } 710 else { 711 (Output::Instance()->Post("No command specified for simple request\n", BLACKBOARD_KIT)); 712 } 713 714 return B_ERROR; 715 } 716