示例#1
0
KNIEXPORT KNI_RETURNTYPE_INT
Java_com_sun_cldc_io_j2me_socket_Protocol_writeBuf() {
  int result;
  int fd = KNI_GetParameterAsInt(1);
  int offset = KNI_GetParameterAsInt(3);
  int length = KNI_GetParameterAsInt(4);

  KNI_StartHandles(1);
  KNI_DeclareHandle(buffer_object);
  KNI_GetParameterAsObject(2, buffer_object);
  char *buffer = (char *) SNI_GetRawArrayPointer(buffer_object) + offset;

  result = jvm_send(fd, buffer, length, 0); // We rely on open0() for setting the socket to non-blocking
  KNI_EndHandles();

  if (result < 0) {
    int err_code = GET_LAST_ERROR();
    if (err_code == EWOULDBLOCK) {
      if (SNI_GetReentryData(NULL) == NULL) {
        BlockingSocket *socket =
            (BlockingSocket *) SNI_AllocateReentryData(sizeof(*socket));
        socket->fd = fd;
        socket->check_flags = CHECK_WRITE;
      }
      SNI_BlockThread();
    }
  }

  KNI_ReturnInt(result);
}
示例#2
0
KNIEXPORT KNI_RETURNTYPE_INT
Java_com_sun_cldc_io_j2me_socket_Protocol_open0() {
  static int inited = 0;
  if (!inited) {
    pcsl_network_init();
    inited = 1;
  }

  int fd = -1;

  // (1) Get the hostname, and convert it to IP address
  KNI_StartHandles(1);
  {
    KNI_DeclareHandle(hostname_object);
    KNI_GetParameterAsObject(1, hostname_object);
    // hostname is always NUL terminated. See socket/Protocol.java for detail.
    char *hostname = (char*) SNI_GetRawArrayPointer(hostname_object);
    int port = KNI_GetParameterAsInt(2);

    unsigned char addr[4];
    int len;
    int status;
    void *context;
    void *handle;

    status = pcsl_network_gethostbyname_start(
          hostname, addr, sizeof(addr), &len, &handle, &context);
    if (status == PCSL_NET_WOULDBLOCK) {
      do {
        status =  pcsl_network_gethostbyname_finish(addr,
                                                    sizeof(addr), &len, 
                                                    &handle, &context);
      } while (status == PCSL_NET_WOULDBLOCK);
    }

    if (status != PCSL_NET_SUCCESS) {
      goto done;
    }

    // (2) Make the connection
    status = pcsl_socket_open_start(
          addr, port, &handle, &context);
    if (status == PCSL_NET_WOULDBLOCK) {
      do {
        status = pcsl_socket_open_finish(handle, context);
      } while (status == PCSL_NET_WOULDBLOCK);
    }

    if (status != PCSL_NET_SUCCESS) {
      goto done;
    }

    fd = (int)handle;
  }
done:
  KNI_EndHandles();

  KNI_ReturnInt(fd);
}
示例#3
0
KNIEXPORT KNI_RETURNTYPE_INT
Java_com_sun_cldc_io_j2me_socket_Protocol_open0() {
  SocketOpenParameter *p;
  struct hostent *phostent;
  char *hostname;
  int port;
  int result;

  init_sockets();

  if (!ANI_Start()) {
    ANI_Wait();
    KNI_ReturnInt(-1);
  }

  p = (SocketOpenParameter *)(ANI_GetParameterBlock(NULL));
  if (p == NULL) {
    p = (SocketOpenParameter *)
        (ANI_AllocateParameterBlock(sizeof(SocketOpenParameter)));
    p->fd = -1;

    KNI_StartHandles(1);
    KNI_DeclareHandle(hostname_object);
    KNI_GetParameterAsObject(1, hostname_object);

    // hostname is always NUL terminated. See socket/Protocol.java for detail.
    hostname = (char *)(SNI_GetRawArrayPointer(hostname_object));
    // 'gethostbyname()' is NON-REENTRANT and its result is in global memory!
    // => its call must not be moved to 'asynchronous_connect_socket()'!
    phostent = gethostbyname(hostname);
    KNI_EndHandles();

    if (phostent != NULL) {
      p->destination_sin.sin_family = AF_INET;
      port = KNI_GetParameterAsInt(2);
      p->destination_sin.sin_port = htons((short)port);
      memcpy((char *) &p->destination_sin.sin_addr,
             phostent->h_addr, phostent->h_length);
      p->fd = socket(AF_INET, SOCK_STREAM, 0);
      if (p->fd >= 0 && set_blocking_flags(&p->fd, /*is_blocking*/ KNI_TRUE) &&
          !ANI_UseFunction(asynchronous_connect_socket,
                           /*try_non_blocking*/ KNI_FALSE)) {
        ANI_BlockThread();
      }
    }
  }

  result = p->fd;
  ANI_End();
  KNI_ReturnInt(result);
}
示例#4
0
KNIEXPORT KNI_RETURNTYPE_INT
Java_com_sun_cldc_io_j2me_socket_Protocol_writeBuf() {
  void *handle = (void*)KNI_GetParameterAsInt(1);
  int offset = KNI_GetParameterAsInt(3);
  int length = KNI_GetParameterAsInt(4);
  int result;

  KNI_StartHandles(1);
  {
    KNI_DeclareHandle(buffer_object);
    KNI_GetParameterAsObject(2, buffer_object);
    char *buffer = (char *) SNI_GetRawArrayPointer(buffer_object) + offset;

    result = do_pcsl_write(handle, buffer, length);
  }
  KNI_EndHandles();
  KNI_ReturnInt(result);
}
示例#5
0
/**
 * Performs reset of the device.
 * <p>Java declaration:
 * <pre>
 * private native int reset0(byte[] atr);
 * </pre>
 * @param atr ATR bytes
 * @return Length of ATR in case of success, else -1 
 */
KNIEXPORT KNI_RETURNTYPE_INT 
KNIDECL(com_sun_cardreader_PlatformCardDevice_reset0) {
    jint retcode;
    javacall_int32 atr_length;
    char *atr_buffer;
    MidpReentryData* info;
    void *context = NULL;
    javacall_result status_code;
    
    KNI_StartHandles(1);
    KNI_DeclareHandle(atr_handle);

    info = (MidpReentryData*)SNI_GetReentryData(NULL);
    KNI_GetParameterAsObject(1, atr_handle);
    if (KNI_IsNullHandle(atr_handle)) {
        atr_buffer = NULL;
        atr_length = 0;
    } else {
        atr_length = KNI_GetArrayLength(atr_handle);
        atr_buffer = SNI_GetRawArrayPointer(atr_handle);
    }

    if (info == NULL) {
        status_code = javacall_carddevice_reset_start(atr_buffer, &atr_length, &context);
    } else {
        context = info->pResult;
        status_code = javacall_carddevice_reset_finish(atr_buffer, &atr_length, context);
    }

    if (status_code == JAVACALL_WOULD_BLOCK) {
        midp_thread_wait(CARD_READER_DATA_SIGNAL, SIGNAL_RESET, context);
        goto end;
    }

    if (status_code != JAVACALL_OK) {
        retcode = -1;
    } else {
        retcode = atr_length;
    }
end:
    KNI_EndHandles();
    KNI_ReturnInt(retcode);
}
示例#6
0
KNIEXPORT KNI_RETURNTYPE_INT
Java_com_sun_cldc_io_j2me_socket_Protocol_readBuf() {
  int result;
  int fd = KNI_GetParameterAsInt(1);
  int offset = KNI_GetParameterAsInt(3);
  int length = KNI_GetParameterAsInt(4);

  KNI_StartHandles(1);
  KNI_DeclareHandle(buffer_object);
  KNI_GetParameterAsObject(2, buffer_object);
  char *buffer = (char *) SNI_GetRawArrayPointer(buffer_object) + offset;

  result = jvm_recv(fd, buffer, length, 0); // We rely on open0() for setting the socket to non-blocking
  KNI_EndHandles();

  if (result == 0) {
    // If remote side has shut down the connection gracefully, and all
    // data has been received, recv() will complete immediately with
    // zero bytes received.
    //
    // This is true for Win32/CE and Linux
    result = -1;
  }
  else if (result < 0) {
    int err_code = GET_LAST_ERROR();
    if (err_code == EWOULDBLOCK) {
      if (SNI_GetReentryData(NULL) == NULL) {
        BlockingSocket *socket =
            (BlockingSocket *)SNI_AllocateReentryData(sizeof(*socket));
        socket->fd = fd;
        socket->check_flags = CHECK_READ;
      }
      SNI_BlockThread();
    }
  }

  KNI_ReturnInt(result);
}
示例#7
0
KNIEXPORT KNI_RETURNTYPE_INT
Java_com_sun_cldc_io_j2me_socket_Protocol_open0() {
  init_sockets();

  SocketOpenParameter *p = (SocketOpenParameter*) SNI_GetReentryData(NULL);
  if (p == NULL) {
    p = (SocketOpenParameter*) SNI_AllocateReentryData(sizeof(*p));
    p->fd = -1;

    struct hostent *phostent;
    KNI_StartHandles(1);
    KNI_DeclareHandle(hostname_object);
    KNI_GetParameterAsObject(1, hostname_object);

    // hostname is always NUL terminated. See socket/Protocol.java for detail.
    char *hostname = (char*) SNI_GetRawArrayPointer(hostname_object);
    phostent = (struct hostent*)jvm_gethostbyname(hostname);
    KNI_EndHandles();

    if (phostent == NULL) {
      KNI_ReturnInt(-1);
    }
    struct sockaddr_in destination_sin;
    destination_sin.sin_family = AF_INET;
    int port = KNI_GetParameterAsInt(2);
    destination_sin.sin_port = jvm_htons(port);
    jvm_memcpy((char *) &destination_sin.sin_addr, phostent->h_addr,
                phostent->h_length);

    p->fd = jvm_socket(AF_INET, SOCK_STREAM, 0);
    if (p->fd < 0) {
       KNI_ReturnInt(-1);
    }
    if (!set_blocking_flags(&p->fd, /*is_blocking*/ KNI_FALSE)) {
      KNI_ReturnInt(-1);
    }

    if (jvm_connect(p->fd, (struct sockaddr *) &destination_sin,
                    sizeof(destination_sin)) < 0) {
      int err_code = GET_LAST_ERROR();
      if (err_code == EINPROGRESS) {
        // When the socket is ready for connect, it becomes *writable*
        // (according to BSD socket spec of select())
        p->check_flags = CHECK_WRITE | CHECK_EXCEPTION;
        SNI_BlockThread();
      } else {
        jvm_shutdown(p->fd, 2);
        closesocket(p->fd);
        p->fd = -1;
      }
    }
    KNI_ReturnInt(p->fd);
  } else {
    // When we come to here, a CheckEvent() call has reported one of the
    // following:
    // [1] connect() has succeeded. In this case we return the socket fd.
    // [2] connect() has failed. In this case CheckEvent has already closed
    //     the socket and set p->fd to -1. So we'd be returning -1.
    KNI_ReturnInt(p->fd);
  }
}
示例#8
0
/**
 * Copies the contents of fromMsg to the contents of toMsg. Both must be
 * instances of LinkMessage. The toLink object must be an instance of Link.
 * It's filled in if the contents of fromMsg are a Link.  Returns KNI_TRUE if
 * successful, otherwise KNI_FALSE.
 */
static jboolean
copy(jobject fromMsg, jobject toMsg, jobject toLink) {
    jboolean retval;

    KNI_StartHandles(6);
    KNI_DeclareHandle(byteArrayClass);
    KNI_DeclareHandle(stringClass);
    KNI_DeclareHandle(linkClass);
    KNI_DeclareHandle(fromContents);
    KNI_DeclareHandle(newString);
    KNI_DeclareHandle(newByteArray);

    KNI_FindClass("[B", byteArrayClass);
    KNI_FindClass("java/lang/String", stringClass);
    KNI_FindClass("com/sun/midp/links/Link", linkClass);
    getContents(fromMsg, fromContents);
    
    if (KNI_IsInstanceOf(fromContents, byteArrayClass)) {
        /* do a byte array copy */
        jint fromOffset;
        jint fromLength;

        getRange(fromMsg, &fromOffset, &fromLength);

        SNI_NewArray(SNI_BYTE_ARRAY, fromLength, newByteArray);
        if (KNI_IsNullHandle(newByteArray)) {
            retval = KNI_FALSE;
        } else {
            KNI_GetRawArrayRegion(fromContents, fromOffset, fromLength,
                SNI_GetRawArrayPointer(newByteArray));
            setContents(toMsg, newByteArray);
            setRange(toMsg, 0, fromLength);
            retval = KNI_TRUE;
        }
    } else if (KNI_IsInstanceOf(fromContents, stringClass)) {
        /* do a string copy */
        jchar *buf;
        jsize slen = KNI_GetStringLength(fromContents);

        SNI_NewArray(SNI_BYTE_ARRAY, slen*sizeof(jchar), newByteArray);

        if (KNI_IsNullHandle(newByteArray)) {
            retval = KNI_FALSE;
        } else {
            buf = SNI_GetRawArrayPointer(newByteArray);
            KNI_GetStringRegion(fromContents, 0, slen, buf);
            KNI_NewString(buf, slen, newString);
            setContents(toMsg, newString);
            retval = KNI_TRUE;
        }
    } else if (KNI_IsInstanceOf(fromContents, linkClass)) {
        /* copy the link */
        rendezvous *rp = getNativePointer(fromContents);
        setNativePointer(toLink, rp);
        rp_incref(rp);
        setContents(toMsg, toLink);
        retval = KNI_TRUE;
    } else {
        retval = KNI_FALSE;
    }

    KNI_EndHandles();
    return retval;
}
示例#9
0
/**
 * Performs data transfer to the device.
 * <p>Java declaration:
 * <pre>
 * private native int cmdXfer0(byte[] request, byte[] response);
 * </pre>
 * @param request Buffer with request data
 * @param response Buffer for response data
 * @return Length of response in case of success, else -1
 */
KNIEXPORT KNI_RETURNTYPE_INT 
KNIDECL(com_sun_cardreader_PlatformCardDevice_cmdXfer0) {
    jint retcode;
    javacall_int32 tx_length, rx_length;
    char *tx_buffer, *rx_buffer;
    MidpReentryData* info;
    void *context = NULL;
    javacall_result status_code;
    
    KNI_StartHandles(2);
    KNI_DeclareHandle(request_handle);
    KNI_DeclareHandle(response_handle);
    
    info = (MidpReentryData*)SNI_GetReentryData(NULL);

    KNI_GetParameterAsObject(1, request_handle);
    if (KNI_IsNullHandle(request_handle)) {
        tx_buffer = NULL;
        tx_length = 0;
        retcode = -1;
        goto end;
    } else {
        tx_length = KNI_GetArrayLength(request_handle);
        tx_buffer = SNI_GetRawArrayPointer(request_handle);
    }
    
    KNI_GetParameterAsObject(2, response_handle);
    if (KNI_IsNullHandle(response_handle)) {
        rx_buffer = NULL;
        rx_length = 0;
        retcode = -1;
        goto end;
    } else {
        rx_length = KNI_GetArrayLength(response_handle);
        rx_buffer = SNI_GetRawArrayPointer(response_handle);
    }
    
    if (tx_length > 5) {
        jsize apdu_len = 5 + (tx_buffer[4]&0xFF) + 1;
        if (tx_length > apdu_len) {
            tx_length = apdu_len;
        }
    }

    if (info == NULL) {
        status_code = javacall_carddevice_xfer_data_start(tx_buffer, 
                                                          tx_length, 
                                                          rx_buffer, 
                                                          &rx_length, &context);
    } else {
        context = info->pResult;
        status_code = javacall_carddevice_xfer_data_finish(tx_buffer, 
                                                           tx_length, 
                                                           rx_buffer, 
                                                           &rx_length, context);
    }

    if (status_code == JAVACALL_WOULD_BLOCK) {
        midp_thread_wait(CARD_READER_DATA_SIGNAL, SIGNAL_XFER, context);
        goto end;
    }

    if (status_code != JAVACALL_OK) {
        retcode = -1;
    } else {
        retcode = rx_length;
    }

end:
    KNI_EndHandles();
    KNI_ReturnInt(retcode);
}
示例#10
0
/**
 * Performs data transfer to the device. This method must be called within
 * <tt>synchronize</tt> block with the Slot object.
 * <p>Java declaration:
 * <pre>
 * public native static int exchangeAPDU0(Handle h, Slot slot,
                                          byte[] request, byte[] response) 
                            throws IOException;
 * </pre>
 * @param h Connection handle. Can be null for internal purposes
 * @param slot Slot object. Unused when <tt>h</tt> is not null. 
 * Must be provided if <tt>h</tt> is null.
 * @param request Buffer with request data
 * @param response Buffer for response data
 * @return Length of response data
 * @exception NullPointerException if any parameter is null
 * @exception IllegalArgumentException if request does not contain proper APDU
 * @exception InterruptedIOException if the connection handle is suddenly closed
 * in the middle of exchange or the card was removed and inserted again
 * @exception IOException if any I/O troubles occured
 */
KNIEXPORT KNI_RETURNTYPE_INT 
Java_com_sun_midp_io_j2me_apdu_APDUManager_exchangeAPDU0() {
    jint retcode = -1;
    MidpReentryData* info;
    void *context = NULL;
    JSR177_STATUSCODE status_code;
    JSR177_CARD_MOVEMENT movements;
    jsize tx_length, rx_length, rx_length_max;
    jbyte *tx_buffer, *rx_buffer;
    jbyte *cur;
    jbyte case_2[5];
    int Lc, Le;
    int cla, channel;
    ConnectionHandle *h;
    CardSlot *card_slot;
    char *err_msg;
    jbyte getResponseAPDU[5];
    
    KNI_StartHandles(4);
    KNI_DeclareHandle(connection_handle);
    KNI_DeclareHandle(slot_handle);
    KNI_DeclareHandle(request_handle);
    KNI_DeclareHandle(response_handle);
    
    info = (MidpReentryData*)SNI_GetReentryData(NULL);

    // If the Handle object is provided we get a Slot object from it
    KNI_GetParameterAsObject(1, connection_handle);
    if (!KNI_IsNullHandle(connection_handle)) {
        h = unhand(ConnectionHandle,(connection_handle));
        card_slot = h->cardSlot;
        if (card_slot == NULL) {
            KNI_ThrowNew(midpNullPointerException, "Slot object is null");
            goto end;
        }
    } else {
        h = NULL;
        KNI_GetParameterAsObject(2, slot_handle);
        if (KNI_IsNullHandle(slot_handle)) {
            KNI_ThrowNew(midpNullPointerException, "Handle and slot are null");
            goto end;
        }
        card_slot = unhand(CardSlot,(slot_handle));
    }
    
    KNI_GetParameterAsObject(3, request_handle);
    if (KNI_IsNullHandle(request_handle)) {
        KNI_ThrowNew(midpNullPointerException, "Request APDU is null");
        goto end;
    }
    tx_length = KNI_GetArrayLength(request_handle);
    tx_buffer = SNI_GetRawArrayPointer(request_handle);
    
    KNI_GetParameterAsObject(4, response_handle);
    if (KNI_IsNullHandle(response_handle)) {
        KNI_ThrowNew(midpNullPointerException, "Response buffer is null");
        goto end;
    }
    rx_length_max = KNI_GetArrayLength(response_handle);
    rx_buffer = SNI_GetRawArrayPointer(response_handle);
    
    if (h != NULL && 
            (!h->opened || h->cardSessionId != card_slot->cardSessionId)) {
        char *msg = "Connection closed";
        if (!card_slot->locked) {
            KNI_ThrowNew(midpIOException, msg);
            goto end;
        } else {
            KNI_ThrowNew(midpInterruptedIOException, msg);
            goto unlock_end;
        }
    }

    if (!card_slot->powered) {
        char *msg = "Card not powered up";
        if (!card_slot->locked) {
            KNI_ThrowNew(midpIOException, msg);
            goto end;
        } else {
            KNI_ThrowNew(midpInterruptedIOException, msg);
            goto unlock_end;
        }
    }
    
    if (tx_length < 4) { // invalid APDU: too short
    invalid_apdu:
        KNI_ThrowNew(midpIllegalArgumentException, "Invalid APDU");
        goto end;
    }
    
    // trying to guess the case
    if (tx_length == 4) { // case 1
        Lc = Le = 0;
    } else {
        Lc = (tx_buffer[4]&0xFF);
        if (tx_length == 5) { // case 2
            Le = Lc;
            Lc = 0;
            if (Le == 0) {
                Le = 256;
            }
        } else if (tx_length == 5 + Lc) { // case 3
            Le = 0;
        } else { // case 4
            if (5 + Lc >= tx_length) { // invalid APDU: bad Lc field
                goto invalid_apdu;
            }
            Le = tx_buffer[5 + Lc] & 0xFF;
            if (Le == 0) {
                Le = 256;
            }
        }
    }
    
    // if APDU of case 4 has Lc=0 then we transform it to case 2
    if (tx_length > 5 && Lc == 0) {
        memcpy(case_2, tx_buffer, 4);
        case_2[4] = tx_buffer[5];
        tx_buffer = case_2;
        tx_length = 5;
    } 
    
    // trimming APDU
    if (tx_length > 5 + Lc + 1) {
        tx_length = 5 + Lc + 1;
    }

    cla = tx_buffer[0] & 0xf8; // mask channel and secure bit
    channel = cla != 0 && (cla < 0x80 || cla > 0xA0) ? 0 : tx_buffer[0] & 3;
    
    // locked slot means that we are in the middle of an exchange, 
    // otherwise we should start a data transfer
    if (!card_slot->locked) {
        card_slot->received = 0;
        cur = rx_buffer;
    } else {
        cur = rx_buffer + card_slot->received;
    }
    
    do { // infinite loop
        int sw1, sw2;

        rx_length = rx_length_max - (jint)(cur - rx_buffer);
        if (rx_length < Le + 2) { 
            err_msg = "Too long response";
            goto err_mess;
        }
        if (info == NULL || info->status == SIGNAL_LOCK) {
            if (!card_slot->locked) {
                status_code = jsr177_lock();
                if (status_code == JSR177_STATUSCODE_WOULD_BLOCK) {
                    midp_thread_wait(CARD_READER_DATA_SIGNAL, SIGNAL_LOCK, NULL);
                    goto end;
                }
                if (status_code != JSR177_STATUSCODE_OK) {
                    goto err;
                }
                card_slot->locked = KNI_TRUE;

// Since this line slot is locked
                status_code = jsr177_select_slot(card_slot->slot);
                if (status_code != JSR177_STATUSCODE_OK) {
                    goto err;
                }
            }
            status_code = 
                jsr177_xfer_data_start(tx_buffer, tx_length, 
                    cur, &rx_length, &context);
        } else {
            context = info->pResult;
            status_code = 
                jsr177_xfer_data_finish(tx_buffer, tx_length, 
                    cur, &rx_length, context);
        }
        if (jsr177_card_movement_events(&movements) == JSR177_STATUSCODE_OK) {
            if ((movements & JSR177_CARD_MOVEMENT_MASK) != 0) {
                err_msg = "Card changed";
                jsr177_set_error(err_msg);
                if (jsr177_get_error((jbyte*)gKNIBuffer, KNI_BUFFER_SIZE)) {
                    err_msg = gKNIBuffer;
                }
                card_slot->powered = KNI_FALSE;
                goto interrupted;
            }
        }
        if (status_code == JSR177_STATUSCODE_WOULD_BLOCK) {
            midp_thread_wait(CARD_READER_DATA_SIGNAL, SIGNAL_XFER, context);
            card_slot->received = (jint)(cur - rx_buffer);
            goto end;
        }
        
        if (status_code != JSR177_STATUSCODE_OK) {
        err:
            if (jsr177_get_error((jbyte*)gKNIBuffer, KNI_BUFFER_SIZE)) {
                err_msg = gKNIBuffer;
            } else {
                err_msg = "exchangeAPDU0()";
            }
        err_mess:
            KNI_ThrowNew(midpIOException, err_msg);
            if (card_slot->locked) {
                status_code = jsr177_unlock(); // ignore status_code
                card_slot->locked = KNI_FALSE;
                midp_thread_signal(CARD_READER_DATA_SIGNAL, 
                                               SIGNAL_LOCK, SIGNAL_LOCK);
            }
            goto end;
        }
        if (rx_length < 2) {
            err_msg = "Response error";
            goto err_mess;
        }
        
        if (h != NULL && 
                (!h->opened || h->cardSessionId != card_slot->cardSessionId)) {
            err_msg = "Handle invalid or closed";
        interrupted:
            KNI_ThrowNew(midpInterruptedIOException, err_msg);
            goto unlock_end;
        }
        sw1 = cur[rx_length - 2] & 0xFF;
        sw2 = cur[rx_length - 1] & 0xFF;
        
        if (sw1 == 0x6C && sw2 != 0x00 && Le != 0) {
            tx_buffer[tx_length - 1] = sw2;
            Le = sw2;
            info = NULL;
            continue;
        }
        
        cur += rx_length;
        if (Le == 0 || (sw1 != 0x61 &&
            (channel != 0 || !card_slot->SIMPresent ||
             (sw1 != 0x62 && sw1 != 0x63 &&
              sw1 != 0x9E && sw1 != 0x9F)))) {
            break;
        }
        cur -= 2; // delete last SW1/SW2 from buffer
        Le = sw1 == 0x62 || sw1 == 0x63 ? 0 : sw2;
        
        memset(getResponseAPDU, 0, sizeof getResponseAPDU);
        tx_buffer = getResponseAPDU;
        tx_buffer[0] = channel;
        tx_buffer[1] = 0xC0;
        tx_buffer[4] = Le;
        if (Le == 0) {
            Le = 256;
        }
        tx_length = 5;
        info = NULL;
    } while(1);
    retcode = (jint)(cur - rx_buffer);

unlock_end:
    card_slot->locked = KNI_FALSE;
    midp_thread_signal(CARD_READER_DATA_SIGNAL, SIGNAL_LOCK, SIGNAL_LOCK);
    status_code = jsr177_unlock(); 
    if (status_code != JSR177_STATUSCODE_OK) {
        goto err;
    }

end:
    KNI_EndHandles();
    KNI_ReturnInt(retcode);
}