I'm trying to use libusb on Android 2.3 to read a stream of data from a USB device connected to an Android development device using libusb and the Android NDK. The development device supports USB host mode even though my version of Android does not. Through the serial terminal connection I have given 777 permissions to the entire tree under /dev/bus/usb.
When I try to run the following code I get an I/O error (-1 returned) from the line that calls libusb_bulk_transfer.
struct usb_bus *p;
struct usb_device *q;
struct libusb_device *current_device;
libusb_device_handle *current_handle;
libusb_device **deviceList;
libusb_device *dev;
libusb_context *ctx = NULL;
int result;
unsigned char firmware[31]= {...}
unsigned char reset[2]={1,0};
unsigned char buffer[2*BUFF_SIZE];
int er[10];
unsigned char endpoint=0x08;
unsigned int i,j,k,tlen,startTime,endTime;
unsigned int val1,val2,offset;
unsigned int packetCnt;
libusb_init(&ctx);
libusb_set_debug(ctx,3);
cnt = libusb_get_device_list(NULL, &deviceList);
if (cnt < 0)
printf("ERROR: %i", (int) cnt);
while ((dev = deviceList[i++]) != NULL) {
char outputString[255];
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "failed to get device descriptor");
return (*env)->NewStringUTF(env, str);
}
if (desc.idVendor == 0x4b4 && desc.idProduct == 0x8613) {
current_device = dev;
sprintf(outputString, "%04x:%04x (bus %d, device %d)\n",
desc.idVendor, desc.idProduct,
libusb_get_bus_number(dev), libusb_get_device_address(dev));
__android_log_write(ANDROID_LOG_INFO, "usb_device", outputString);
}
}
if (current_device == NULL) {
__android_log_write(ANDROID_LOG_INFO, "usb_device", "Could not find a CY7C68013\n\n");
return (*env)->NewStringUTF(env, str);
}
result = libusb_open(current_device, ¤t_handle);
result = libusb_open(current_device, ¤t_handle);
if (result != 0) {
__android_log_write(ANDROID_LOG_INFO, "usb_device", "Unable to open device\n\n");
return (*env)->NewStringUTF(env, str);
}
char outputString[255];
libusb_free_device_list(deviceList, 1);
libusb_control_transfer(current_handle, 0x40, 0xa0, 0xE600, 0, reset, 1, 1000);
int actual;
for(i=0;i<31;i+=16) //LOAD FIRMWARE
{
tlen = 60-i;
if(tlen > 16)
tlen = 16;
result = libusb_control_transfer(current_handle, 0x40, 0xa0, i, 0, firmware+i, tlen, 1000);
log_result(result);
}
result = libusb_control_transfer(current_handle, 0x40, 0xa0, 0xE600, 0, reset+1, 1, 1000);
log_result(result);
result = libusb_claim_interface(current_handle, 0);
if (result < 0) {
__android_log_write(ANDROID_LOG_INFO, "usb_device", "Cannot Claim Interface\n\n");
return (*env)->NewStringUTF(env, str);
}
result = libusb_bulk_transfer(current_handle, endpoint, buffer, BUFF_SIZE, &actual, 11000);
log_result(result);
libusb_release_interface(current_handle, 0);
libusb_close(current_handle);
libusb_exit(ctx);
Everything succeeds up until this point, including performing the 32 byte control transfer of the device firmware.
I've given myself full permission to the USB /dev files and I've checked using libusb to ensure that there isn't any kernel driver attached to this interface.
What am I doing wrong?
Related
What would be analog to hid_get_feature_report in Android USB Library?
I need to get relays state from usb relays device on Android.
I found example on C (for Linux/Windows): https://github.com/darrylb123/usbrelay/blob/master/libusbrelay.c
static int get_board_features(relay_board *board, hid_device *handle)
{
unsigned char buf[9];
//Get the features of the device
buf[0] = 0x01;
int ret = hid_get_feature_report(handle, buf, sizeof(buf));
if (ret == -1)
{
perror("hid_get_feature_report\n");
}
//Set the serial number (0x0 for termination)
memset(board->serial, 0x0, sizeof(board->serial));
memcpy(board->serial, buf, Serial_Length);
//Byte 7 in the response contains the target_state of the relays
board->state = buf[7];
return ret;
}
On Android it returns only one end point Log.i(TAG, "endpointCount ${usbInterface.endpointCount}
I am working on making a customized bsp based on AOSP Nougat latest source.
Android service process ask service manager to find or add the service.
And service manager try to check mac permissions by calling svc_can_register() or svc_can_find() which calls check_mac_perms() which calls getpidcon().
Let's see svc_can_find()
static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
{
const char *perm = "find";
return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
}
check_mac_perms_from_lookup() is like this:
static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name)
{
bool allowed;
char *tctx = NULL;
if (selinux_enabled <= 0) {
return true;
}
if (!sehandle) {
ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n");
abort();
}
if (selabel_lookup(sehandle, &tctx, name, 0) != 0) {
ALOGE("SELinux: No match for %s in service_contexts.\n", name);
return false;
}
allowed = check_mac_perms(spid, uid, tctx, perm, name);
freecon(tctx);
return allowed;
}
It calls check_mac_perms(). check_mac_perms() like this:
static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name)
{
char *sctx = NULL;
const char *class = "service_manager";
bool allowed;
struct audit_data ad;
if (getpidcon(spid, &sctx) < 0) {
ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);
return false;
}
ad.pid = spid;
ad.uid = uid;
ad.name = name;
int result = selinux_check_access(sctx, tctx, class, perm, (void *) &ad);
allowed = (result == 0);
freecon(sctx);
return allowed;
}
It calls getpidcon(). getpidcon() is defined in
external/selinux/libselinux/src/procattr.c
getpidcon() is defined like this:
#define getpidattr_def(fn, attr) \
int get##fn(pid_t pid, char **c) \
{ \
if (pid <= 0) { \
errno = EINVAL; \
return -1; \
} else { \
return getprocattrcon(c, pid, #attr); \
} \
}
...
...
getpidattr_def(pidcon, current)
"getpidattr_def(pidcon, current)" is expanded to getpidcon() function
definition and it calls getprocatrcon()
getprocattrcon() is like this:
static int getprocattrcon(char ** context,
pid_t pid, const char *attr)
{
char *buf;
size_t size;
int fd;
ssize_t ret;
int errno_hold;
fd = openattr(pid, attr, O_RDONLY);
if (fd < 0)
return -1;
size = selinux_page_size;
buf = malloc(size);
if (!buf) {
ret = -1;
goto out;
}
memset(buf, 0, size);
do {
ret = read(fd, buf, size - 1);
} while (ret < 0 && errno == EINTR);
if (ret < 0)
goto out2;
if (ret == 0) {
*context = NULL;
goto out2;
}
*context = strdup(buf);
if (!(*context)) {
ret = -1;
goto out2;
}
ret = 0;
out2:
free(buf);
out:
errno_hold = errno;
close(fd);
errno = errno_hold;
return ret;
}
Pretty simple huh? Just opening some files and reading the contents
and return it by function argument.
It fails at openattr(). I've confirmed this by inserting some log function in
openattr(). openattr() is also simple function.
static int openattr(pid_t pid, const char *attr, int flags)
{
int fd, rc;
char *path;
pid_t tid;
if (pid > 0) {
rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
} else if (pid == 0) {
rc = asprintf(&path, "/proc/thread-self/attr/%s", attr);
if (rc < 0)
return -1;
fd = open(path, flags | O_CLOEXEC);
if (fd >= 0 || errno != ENOENT)
goto out;
free(path);
tid = gettid();
rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
} else {
errno = EINVAL;
return -1;
}
if (rc < 0)
return -1;
fd = open(path, flags | O_CLOEXEC);
out:
free(path);
return fd;
}
The fail point is "fd = open(path, flags | O_CLOEXEC);"
Even if the file exists, almost always opening fails. I don't understand ths and want to know what caused the problem. I've confirmed the failure
by inserting some log printing codes, checking android log(adb logcat) and reading the file from android shell(adb shell), e.g. 'cat /proc/412/attr/current'. Reading by 'cat ...' succeeded but log shows the opening the
file fails. The odd thing is if 'pid' is 0, it succeeds.
If opening fails, services can't be launched so the system don't
boot properly. If I ignore the fails and return success from getpidcon()
the system boots properly but this is not the right thing to do obviously.
I'm testing the bsp as selinux permissive mode.
Can anyone have a experience like me? If anyone, please share the
experience and the solution of the problem.
Thank you.
Sangyong Lee.
I'm making an executable in Android. This will be used for sending ARP packets, but the sendto command is failing with EINVAL.
The same piece of code is working on ARM, but failing on Cortex A9.
Here is the code snippet:
int sendArp( const char *iface, const char *src_ip, const char * trgt_ip)
{
int status, frame_length, bytes;
arp_hdr arphdr;
uint8_t src_mac[6] ={0};
uint8_t dst_mac[6] ={0};
uint8_t ether_frame[ARP_LEN] = {0};
struct addrinfo hints, *res;
struct sockaddr_in *ipv4;
struct sockaddr_ll send_struct;
struct ifreq ifr;
int sd =-1;
int recValue = -1;
pthread_t thread;
if(iface == NULL || src_ip == NULL || trgt_ip == NULL)
return -1;
if ((sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {
ALOG ("socket() failed ");
goto out;
}
memset (&ifr, 0, sizeof (ifr));
snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", iface);
if (ioctl (sd, SIOCGIFHWADDR, &ifr) < 0) {
ALOG ("ioctl() failed to get source MAC address ");
goto out;
}
// Copy source MAC address.
memcpy (src_mac, ifr.ifr_hwaddr.sa_data, 6 * sizeof (uint8_t));
memset (&send_struct, 0, sizeof (send_struct));
if ((send_struct.sll_ifindex = if_nametoindex (iface)) == 0) {
ALOG ("if_nametoindex() failed to obtain iface index ");
goto out;
}
memset (dst_mac, 0xff, 6 * sizeof (uint8_t));
ALOG ("Iface '%s' index='%i', src=%s : dest=%s\n", iface, send_struct.sll_ifindex, src_ip, trgt_ip);
memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = hints.ai_flags | AI_CANONNAME;
if ((status = inet_pton (AF_INET, src_ip, &arphdr.sender_ip)) != 1) {
fprintf (stderr, "inet_pton() failed for source IP address.\nError message: %s", strerror (status));
goto out;
}
if ((status = getaddrinfo (trgt_ip, NULL, &hints, &res)) != 0) {
fprintf (stderr, "getaddrinfo() failed - %s\n", strerror (status));
goto out;
}
ipv4 = (struct sockaddr_in *) res->ai_addr;
memcpy (&arphdr.target_ip, &ipv4->sin_addr, 4 * sizeof (uint8_t));
freeaddrinfo (res);
send_struct.sll_family = AF_PACKET;
send_struct.sll_protocol = htons(ETH_P_ARP);
send_struct.sll_hatype = htons(ARPHRD_ETHER);
send_struct.sll_pkttype = (PACKET_BROADCAST);
memcpy (send_struct.sll_addr, src_mac, 6 * sizeof (uint8_t));
send_struct.sll_halen = 6;
send_struct.sll_addr[6] = 0x00;
send_struct.sll_addr[7] = 0x00;
arphdr.htype = htons (1);
arphdr.ptype = htons (ETH_P_IP);
arphdr.hlen = 6;
arphdr.plen = 4;
arphdr.opcode = htons (ARPOP_REQUEST);
memcpy (&arphdr.sender_mac, src_mac, 6 * sizeof (uint8_t));
memset (&arphdr.target_mac, 0, 6 * sizeof (uint8_t));
frame_length = 6 + 6 + 2 + ARP_HDRLEN;
memcpy (ether_frame, dst_mac, 6 * sizeof (uint8_t));
memcpy (ether_frame + 6, src_mac, 6 * sizeof (uint8_t));
ether_frame[12] = ETH_P_ARP / 256;
ether_frame[13] = ETH_P_ARP % 256;
memcpy (ether_frame + ETH_HDRLEN, &arphdr, ARP_HDRLEN * sizeof (uint8_t));
// Send ethernet frame to socket.
if ((bytes = sendto (sd, ether_frame, frame_length, 0, (struct sockaddr *) &send_struct, sizeof (send_struct))) <= 0) {
ALOG ("sendto() failed: error=%s", strerror(errno));
goto out;
}
ALOG("ARP sent, bytes[%d]", bytes);
recValue = arpRecv(sd, (uint8_t*)arphdr.target_ip);
ALOG("main::thread_ret=%d", recValue);
out:
if(sd){
shutdown(sd,2);
close(sd);
}
return recValue;
}
int main(int argc, const char **argv) {
return sendArp("wlan0", "10.10.10.10", "20.20.20.20");
}
From the code snippet, I'm getting the error:
sendto() failed
The Kernel error I'm seeing is:
packet size is too short (42 <= 62)
I have tried modifying socket flags and played around the code a lot, but couldn't figure out the root cause. Any help is greatly appreciated.
Thanks in advance.
I am trying to read all the .so files from the android process memory and store it in a map for later usage. Though, the below code snippet works for all non rooted android devices, it is not working for rooted android 7 device, Nexus 6.
The "m_modules" map is always empty. But, when I run "cat /proc/self/maps" in the adb shell, it is showing the memory mapping with the .so files.
Can someone kindly help me out.
Native code snippet used in Android :
bool elf_hooker::phrase_proc_maps()
{
m_modules.clear();
FILE* fd = fopen("/proc/self/maps", "r");
if (fd != NULL) {
char buff[2048+1];
while(fgets(buff, 2048, fd) != NULL) {
const char *sep = "\t \r\n";
char *line = NULL;
char* addr = strtok_r(buff, sep, &line);
if (!addr) {
continue;
}
char *flags = strtok_r(NULL, sep, &line);
if (!flags || flags[0] != 'r' || flags[3] == 's') {
//log_info("######## FIRST CRASHING IF ********************");
//
/*
1. mem section cound NOT be read, without 'r' flag.
2. read from base addr of /dev/mail module would crash.
i dont know how to handle it, just skip it.
1f5573000-1f58f7000 rw-s 1f5573000 00:0c 6287 /dev/mali0
*/
continue;
}
strtok_r(NULL, sep, &line); // offsets
char *dev = strtok_r(NULL, sep, &line); // dev number.
int major = 0, minor = 0;
if (!phrase_dev_num(dev, &major, &minor) || major == 0) {
//log_info("######## SECOND CRASHING IF ********************");
/*
if dev major number equal to 0, mean the module must NOT be
a shared or executable object loaded from disk.
e.g:
lookup symbol from [vdso] would crash.
7f7b48a000-7f7b48c000 r-xp 00000000 00:00 0 [vdso]
*/
continue;
}
strtok_r(NULL, sep, &line); // node
char* filename = strtok_r(NULL, sep, &line); //module name
if (!filename) {
continue;
}
std::string module_name = filename;
std::map<std::string, elf_module>::iterator itor = m_modules.find(module_name);
if (itor == m_modules.end() &&
!(in_exception_list(module_name.substr(module_name.find_last_of("/\\") + 1)))) {
void* base_addr = NULL;
void* end_addr = NULL;
if (phrase_proc_base_addr(addr, &base_addr, &end_addr) && elf_module::is_elf_module(base_addr)) {
elf_module module(reinterpret_cast<ElfW(Addr)>
(base_addr), module_name.c_str());
m_modules.insert(std::pair<std::string, elf_module>(module_name, module));
}
}
}
fclose(fd);
return 0;
}
return -1;
}
Helper functions :
bool elf_hooker::phrase_proc_base_addr(char* addr, void** pbase_addr, void**
pend_addr)
{
char* split = strchr(addr, '-');
if (split != NULL) {
if (pbase_addr != NULL) {
*pbase_addr = (void *) strtoul(addr, NULL, 16);
}
if (pend_addr != NULL) {
*pend_addr = (void *) strtoul(split + 1, NULL, 16);
}
return true;
}
return false;
}
bool elf_hooker::phrase_dev_num(char* devno, int *pmajor, int *pminor)
{
*pmajor = 0;
*pminor = 0;
if (devno != NULL && strlen(devno) == 5 && devno[2] == ':') {
*pmajor = strtoul(devno + 0, NULL, 16);
*pminor = strtoul(devno + 3, NULL, 16);
return true;
}
return false;
}
adb shell showing "cat /proc/self/maps/" :
I am trying to develop a simple program to communicate with the Nexus-4 bootloader in firmware update mode.
Nexus -4 has three usb interfaces. Interface-1 has two 2 endpoints - 2 and 131.
I wrote a program to write the command, get-device-info, through endpoint 2 and listen at endpoint 131 for the reply.
(I tried all permutations of interfaces and endpoints!).
The program successfully writes the command to the device but nothing is read from the device.
Command format: Flag(0x7e): CMD: Data (variable length): CRC-16: Flag(0x7e)
Get-device-info-command: 0x7e 0x00 0x78 0xf0 0x7e
The following is the program.
#include <stdio.h>
#include <stdlib.h>
#include <libusb-1.0/libusb.h>
#define INTERFACE 1
#define EP_OUT 2
#define EP_IN 131
int main() {
libusb_device **devs; // retrieve a list of devices
libusb_device_handle *dev_handle; // device handler
libusb_context *ctx = NULL; //a libusb session
int r, r2, i;
ssize_t cnt; //holding number of devices in list
unsigned char data[30],read_data[512]; //data to write
data[0]=0x7e;data[1]=0x00;data[2]=0x78;data[3]=0xf0;data[4]=0x7e; // get-device-info command in HLDC format
int actual,read_actual;
r = libusb_init(&ctx);
if(r < 0) {
printf("Init Error\n");
return 1;
}
libusb_set_debug(ctx, 3);
cnt = libusb_get_device_list(ctx, &devs); //get the list of devices
if(cnt < 0) {
printf("Get Device Error\n");
return 1;
}
printf("%d Devices in list\n",(int)cnt);
dev_handle = libusb_open_device_with_vid_pid(ctx, 4100, 25371); //these are vendorID and productID I found for Nexus-4 firmware update
if(dev_handle == NULL)
printf("Cannot open device\n");
else
printf("Device opened\n");
libusb_free_device_list(devs, 0); //free the device list
if(libusb_kernel_driver_active(dev_handle, INTERFACE) == 1) { //find out if kernel driver is attached
printf("Kernel Driver Active\n");
if(libusb_detach_kernel_driver(dev_handle, INTERFACE) == 0) //detach it
printf("Kernel Driver Detached!\n");
}
r = libusb_claim_interface(dev_handle, INTERFACE); //claim interface 1 Nexus-5/4 FUM
if(r < 0) {
printf("Cannot Claim Interface\n");
printf("%s\n",libusb_error_name(r));
return 1;
}
printf("Claimed Interface\n");
printf("Data to be send -> %s\n",data); //just to see the data that we are writing
printf("Writing Data...\n");
r = libusb_bulk_transfer(dev_handle, (EP_OUT | LIBUSB_ENDPOINT_OUT), data, 5, &actual, 0);
if(r == 0 && actual == 5){ //we wrote successfully 5 bytes to the device
printf("Writing Successful!\n");
printf("Waiting to read from device!\n");
r2 = libusb_bulk_transfer(dev_handle, (EP_IN | LIBUSB_ENDPOINT_IN), read_data, 512, &read_actual, 5000);
if (r2 >=0){
if (read_actual > 0){
printf("Data received by bulk transfer\n");
printf("Data is ");
for (i=0; i<read_actual; i++)
printf("%x ",read_data[i]);
printf("\n");
}
else{
printf(stderr, "No data received in bulk transfer (%d)\n", r2);
return -1;
}
}
else{
fprintf(stderr, "Error receiving data via bulk transfer %d\n", r2);
return r2;
}
}
else
printf("Write Error\n");
r = libusb_release_interface(dev_handle, INTERFACE); //release the claimed interface
if(r!=0) {
printf("Cannot Release Interface\n");
return 1;
}
printf("Released Interface\n");
libusb_close(dev_handle);
libusb_exit(ctx);
return 0;
}
The program is able to send the command successfully to the phone but it is not able to receive any response from the phone. When I run the program, I get the following output:
10 Devices in list
Device opened
Kernel Driver Active
Kernel Driver Detached!
Claimed Interface
Data to be send -> ~
Writing Data...
Writing Successful!
Waiting to read from device!
Error receiving data via bulk transfer -7
I am not sure the reason for not getting a response is because of the wrong command structure or because of the implementation of the program?