Beispiel #1
0
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 *) &noticep->IssuerGID.Raw[0], (void *) &mi->gidPrefix, 8);
		(void) memcpy((void *) &noticep->IssuerGID.Raw[8], (void *) &mi->guid, 8);
		*(uint64_t *) &noticep->IssuerGID.Raw[0] = ntoh64(*(uint64_t *) &noticep->IssuerGID.Raw[0]);
		*(uint64_t *) &noticep->IssuerGID.Raw[8] = ntoh64(*(uint64_t *) &noticep->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);
}