uint32_t fe_unsolicited(FE_ConnList *clist, uint32_t *conn_state) { uint32_t i, rc = FE_SUCCESS; uint32_t found = 0, count = 0; int32_t len = 0; STL_NOTICE connStateTrap; STL_NOTICE *noticep; FE_ConnList *tlist; FE_Trap_t traps, *curr; #ifndef IB_STACK_OPENIB FE_Trap_t *temp; #endif uint64_t tid; ManagerInfo_t *mi; SA_MAD *noticeMad; OOBPacket *packet; IB_ENTER(__func__, conn_state, 0, 0, 0); tlist = clist; #ifdef IB_STACK_OPENIB // early sanity check on OFED to avoid locking the trap thread if (!fe_trap_thread_get_trapcount() && *conn_state != CONN_LOST && *conn_state != CONN_ESTABLISH) { IB_EXIT(__func__, rc); return (rc); } // stop the trap thread and grab the traps. due to the non-OFED semantics // of this function, we store the first trap on the stack { FE_Trap_t *ptraps; fe_trap_thread_pause(); fe_trap_thread_get_traplist(&ptraps, &found); if (found) { memcpy(&traps, ptraps, sizeof(FE_Trap_t)); } } #else (void)fe_if3_get_traps(&traps, &found); #endif if (*conn_state == CONN_LOST) { count++; } if (*conn_state == CONN_ESTABLISH) { count++; } if (rc == FE_SUCCESS) { count = count + found; } if (count == 0) { /* no Notices to send */ #ifdef IB_STACK_OPENIB fe_trap_thread_resume(); #endif IB_EXIT(__func__, rc); return (rc); } // find the handle stuff if ((rc = if3_mngr_locate_minfo(fdsa, &mi))) { IB_EXIT(__func__, rc); return rc; } // allocate a tid ; if ((rc = mai_alloc_tid(mi->fds, mi->mclass, &tid))) { IB_LOG_ERRORRC("unable to allocate tid rc:", rc); IB_EXIT(__func__, rc); return rc; } // // process the traps if (found) { curr = &traps; for (i = 0; i < found; i++, tid = mai_increment_tid(tid)) { #ifndef IB_STACK_OPENIB temp = curr; #endif // build the out of band packet and copy the response into it. // there's no need to bswap the data, as that will be done by // the FEC on the other side packet = (OOBPacket *)g_fe_oob_send_buf; memset(packet, 0, sizeof(OOBPacket)); noticeMad = (SA_MAD *)&(packet->MadData); // initialize SA MAD header fields SA_MAD_SET_HEADER(noticeMad, SM_KEY, 0); // initialize the commom mad header fields packet->Header.HeaderVersion = STL_BASE_VERSION; MAD_SET_VERSION_INFO(noticeMad, STL_BASE_VERSION, MCLASS_SUBN_ADM, STL_SA_CLASS_VERSION); MAD_SET_METHOD_TYPE(noticeMad, MAD_CM_REPORT); MAD_SET_ATTRIB_ID(noticeMad, SA_NOTICE); MAD_SET_TRANSACTION_ID(noticeMad, tid); // initialize RMPP fields noticeMad->RmppHdr.RmppVersion = 1; // copy the notice data into our packet and convert to network byte order. // Byte swapping to network byte order for the rest of the packet, will // be done by the fe_send_packet() routine. (void)BSWAPCOPY_STL_NOTICE(&curr->notice, (STL_NOTICE *)noticeMad->Data); len = sizeof(OOBHeader) + IBA_SUBN_ADM_HDRSIZE + sizeof(STL_NOTICE); // send the notice to all FECs while (tlist) { if ((rc = fe_send_packet(tlist->conn, g_fe_oob_send_buf, len))) { IB_LOG_ERROR("fe_send_packet fail in fe_unsolicited rc:", rc); } // the fe_send_packet() routine byte swaps the headers of the // OOB packet, so convert them back to host byte order before // sending packet again. BSWAP_OOB_PACKET(packet); tlist = tlist->next; } curr = curr->next; // relegate memory management to trap thread functions on OFED #ifndef IB_STACK_OPENIB if (i > 0) { vs_pool_free(&fe_pool, (void *)temp); } #endif } } switch (*conn_state) { case CONN_LOST: case CONN_ESTABLISH: tlist = clist; // use 64/65 trap to notify the FEC that the connection to the SM/SA // has gone down/reestablished tid = mai_increment_tid(tid); // build the out of band packet and copy the response into it. // there's no need to bswap the data, as that will be done by // the FEC on the other side memset(&connStateTrap, 0, sizeof(connStateTrap)); packet = (OOBPacket *)g_fe_oob_send_buf; memset(packet, 0, sizeof(OOBPacket)); noticeMad = (SA_MAD *)&(packet->MadData); // initialize SA MAD header fields SA_MAD_SET_HEADER(noticeMad, SM_KEY, 0); // initialize the commom mad header fields packet->Header.HeaderVersion = STL_BASE_VERSION; MAD_SET_VERSION_INFO(noticeMad, STL_BASE_VERSION, MCLASS_SUBN_ADM, STL_SA_CLASS_VERSION); MAD_SET_METHOD_TYPE(noticeMad, MAD_CM_REPORT); MAD_SET_ATTRIB_ID(noticeMad, SA_NOTICE); MAD_SET_TRANSACTION_ID(noticeMad, tid); // initialize RMPP fields noticeMad->RmppHdr.RmppVersion = 1; // initialize the notice fields connStateTrap.Attributes.Generic.u.s.IsGeneric = 1; connStateTrap.Attributes.Generic.u.s.Type = NOTICE_TYPE_INFO; connStateTrap.Attributes.Generic.u.s.ProducerType = NOTICE_PRODUCERTYPE_CLASSMANAGER; connStateTrap.Attributes.Generic.TrapNumber = (*conn_state == CONN_LOST) ? MAD_SMT_PORT_DOWN: MAD_SMT_PORT_UP; connStateTrap.IssuerLID = mi->saLid; connStateTrap.Stats.s.Toggle = 0; connStateTrap.Stats.s.Count = 0; // copy the notice data into our packet and convert to network byte order. // Byte swapping to network byte order for the rest of the packet, will // be done by the fe_send_packet() routine. (void)BSWAPCOPY_STL_NOTICE(&connStateTrap, (STL_NOTICE *)noticeMad->Data); // Now construct IssurerGID // // Note, we don't copy the GIDs till after we bswap the rest of the notice. // This is done in order to remain consistant with the unique handling of // GIDs throughout the FM (GIDs are stored in network byte order). noticep = (STL_NOTICE *)noticeMad->Data; (void) memcpy((void *) ¬icep->IssuerGID.Raw[0], (void *) &mi->gidPrefix, 8); (void) memcpy((void *) ¬icep->IssuerGID.Raw[8], (void *) &mi->guid, 8); *(uint64_t *) ¬icep->IssuerGID.Raw[0] = ntoh64(*(uint64_t *) ¬icep->IssuerGID.Raw[0]); *(uint64_t *) ¬icep->IssuerGID.Raw[8] = ntoh64(*(uint64_t *) ¬icep->IssuerGID.Raw[8]); len = sizeof(OOBHeader) + IBA_SUBN_ADM_HDRSIZE + sizeof(STL_NOTICE); // send the notice to all FECs while (tlist) { if ((rc = fe_send_packet(tlist->conn, g_fe_oob_send_buf, len))) { IB_LOG_ERROR("fe_send_packet fail in fe_unsolicited rc:", rc); } // the fe_send_packet() routine byte swaps the headers of the // OOB packet, so convert them back to host byte order before // sending packet again. BSWAP_OOB_PACKET(packet); tlist = tlist->next; } break; default: break; } PCHK(rc, FAILED, "fe_unsolicited"); *conn_state = CONN_UNCHANGED; #ifdef IB_STACK_OPENIB fe_trap_thread_free_traps(); fe_trap_thread_resume(); #endif IB_EXIT(__func__, rc); return (rc); }
int main (int argc, char **argv) { bool daemonize = false; while (true) { int c; static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'v'}, {"daemon", no_argument, NULL, 'd'}, {"fork", no_argument, NULL, 'f'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "hvd", long_options, NULL); if (c == -1) break; switch (c) { case 'h': print_usage(argv[0]); exit(EXIT_SUCCESS); case 'v': msg("HAMA MCE remote event client v%s for XBMC\n", VERSION); exit(EXIT_SUCCESS); case 'd': daemonize = true; break; default: print_usage(argv[0]); exit(EXIT_FAILURE); } } if (optind < (argc - 1)) { err("%s: too many arguments\n", argv[0]); exit(EXIT_FAILURE); } struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_handler = handle_exit; PCHK(sigaction(SIGINT, &sa, NULL)); PCHK(sigaction(SIGTERM, &sa, NULL)); libusb_context *ctx; libusb_device_handle *dev; struct libusb_transfer *transfer0x81 = libusb_alloc_transfer(0); struct libusb_transfer *transfer0x82 = libusb_alloc_transfer(0); unsigned char buf0x81 [8]; unsigned char buf0x82 [5]; UCHK(libusb_init(&ctx)); if (!(dev = libusb_open_device_with_vid_pid(ctx, 0x05a4, 0x9881))) { err("%s: No HAMA MCE remote control found.\n", argv[0]); exit(EXIT_FAILURE); } int exit_code = EXIT_SUCCESS; if (libusb_kernel_driver_active(dev, 0)) UCHK(libusb_detach_kernel_driver(dev, 0)); if (libusb_kernel_driver_active(dev, 1)) UCHK(libusb_detach_kernel_driver(dev, 1)); UCHK(libusb_claim_interface(dev, 0)); UCHK(libusb_claim_interface(dev, 1)); libusb_fill_interrupt_transfer(transfer0x81, dev, 0x81, buf0x81, sizeof(buf0x81), transfer0x81_cb, NULL, 215); UCHK(libusb_submit_transfer(transfer0x81)); libusb_fill_interrupt_transfer(transfer0x82, dev, 0x82, buf0x82, sizeof(buf0x82), transfer0x82_cb, NULL, 200); UCHK(libusb_submit_transfer(transfer0x82)); msg("Connected HAMA MCE Remote\n"); xbmc.SendHELO("HAMA MCE Remote", ICON_NONE); if (daemonize) { if (daemon(0,0) == -1) { err("Failed to fork\n"); perror(argv[0]); exit_code = EXIT_FAILURE; goto exit; } } while (!(disconnected || quit)) { UCHK(libusb_handle_events(ctx)); } exit: if (disconnected) { msg("Disconnected HAMA MCE Remote\n"); xbmc.SendNOTIFICATION("Disconnected", "HAMA MCE Remote", ICON_NONE); } else { msg("Closing HAMA MCE Remote\n"); xbmc.SendNOTIFICATION("Closing", "HAMA MCE Remote", ICON_NONE); } libusb_free_transfer(transfer0x81); libusb_free_transfer(transfer0x82); if (!disconnected) { // Release the remote back to the system UCHK(libusb_release_interface(dev, 0)); UCHK(libusb_release_interface(dev, 1)); UCHK(libusb_attach_kernel_driver(dev, 0)); UCHK(libusb_attach_kernel_driver(dev, 1)); } libusb_close(dev); libusb_exit(ctx); exit(exit_code); }