Android - IOCTL usage returns ENOTTY - android

I am trying to run a simple IOCTL example on Android. I am using kernel 2.6 and ICS. The module is properly registered/unregistered (insmod/rmmod). However, every time a try to execute ./user_app on the emulator, I always get
error: first ioctl: Not a typewriter
error: second ioctl: Not a typewriter
message: `�
This is clearly a ENOTTY. I debugged the application, and no fops procedure (device_ioctl, read_ioctl and write_ioctl) is being executed.
I would like to know if there is any restriction with the usage/implementation of IOCTL on Android. Thank you very much in advance.
--Raul
Here is the code:
module.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#define MY_MACIG 'G'
#define READ_IOCTL _IOR(MY_MACIG, 0, int)
#define WRITE_IOCTL _IOW(MY_MACIG, 1, int)
int main(){
char buf[200];
int fd = -1;
if ((fd = open("/data/local/afile.txt", O_RDWR)) < 0) {
perror("open");
return -1;
}
if(ioctl(fd, WRITE_IOCTL, "hello world") < 0)
perror("first ioctl");
if(ioctl(fd, READ_IOCTL, buf) < 0)
perror("second ioctl");
printf("message: %s\n", buf);
return 0;
}
user_app.c
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#define MY_MACIG 'G'
#define READ_IOCTL _IOR(MY_MACIG, 0, int)
#define WRITE_IOCTL _IOW(MY_MACIG, 1, int)
static char msg[200];
static ssize_t device_read(struct file *filp, char __user *buffer, size_t length, loff_t *offset)
{
...
}
static ssize_t device_write(struct file *filp, const char __user *buff, size_t len, loff_t *off)
{
...
}
char buf[200];
int device_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) {
int len = 200;
switch(cmd) {
case READ_IOCTL:
...
break;
case WRITE_IOCTL:
...
break;
default:
return -ENOTTY;
}
return len;
}
static struct file_operations fops = {
.read = device_read,
.write = device_write,
.unlocked_ioctl = device_ioctl,
};
static int __init example_module_init(void)
{
printk("registering module");
return 0;
}
static void __exit example_module_exit(void)
{
printk("unregistering module");
}
module_init(example_module_init);
module_exit(example_module_exit);
MODULE_LICENSE("GPL");

It this the whole code that you've posted? You don't register a char device when initializing a module, so this can't work.
Also, be carefull when assigning IOCTLS numbers. When using reserved IOCTL on a wrong file, you will get ENOTTY. Consult this to make sure you don't have conflicts.
Read more about char drivers here.

Related

Android kernel module

The problem is "insmod success", but seems the entry function "demo_init()" is not been executed. lsmod shows the module loaded successfully and no errors or warnings. However, I can't see "Hello, World!" after dmesg, and there is no device node "/dev/demo_device" and there is no class "/sys/class/demo_class". I'm not able to figure it out.
Someone could help me, thanks.
The kernel version is 3.10.86.
The system Android.
This is my code:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
int major;
static struct class *demo_class;
static struct device *demo_device;
static int demo_open(struct inode * inode, struct file * filp)
{
printk(KERN_ALERT "demo_open\n");
return 0;
}
static int demo_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)
{
printk(KERN_ALERT "demo_write\n");
return 0;
}
static const struct file_operations demo_fops = {
.owner = THIS_MODULE,
.open = demo_open,
.write = demo_write,
};
static int __init demo_init(void) {
printk(KERN_ALERT "Hello, World!\n");
major = register_chrdev(0, "demo_drv", &demo_fops);
demo_class = class_create(THIS_MODULE, "demo_class");
demo_device = device_create(demo_class, NULL, MKDEV(major, 0), NULL, "demo_device");
return 0;
}
static void __exit demo_exit(void) {
printk(KERN_ALERT "Goodbye, World!\n");
unregister_chrdev(major, "demo_drv");
device_unregister(demo_device);
class_destroy(demo_class);
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_VERSION("0.01");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("A simple example Linux module.");

How to get mac address in Android native code

I can get mac address with this C code:
struct ifreq s;
char buffer[12 + 1];
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
int i, j;
memset(buffer, 0 , sizeof(buffer));
strcpy(s.ifr_name, "wlan0");
if (0 == ioctl(fd, SIOCGIFHWADDR, &s)) {
memcpy(mac, s.ifr_addr.sa_data, 6);
return 1;
}
I want to get mac address in Android. but this code does not give MAC address. if (0 == ioctl(fd, SIOCGIFHWADDR, &s) is always false.
I found a code in https://groups.google.com/d/msg/android-ndk/6Y-0Eid3mGw/6bFvtap8xJIJ
But this code gives error:
ioctl(SIOCGIFHWADDR) error
and it gives wrong mac address like 00:00:00:7C::00:01
How can I get mac address in Android native code ?
This code works good on Nexus 5:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include <linux/if.h>
#include <linux/in.h>
int get_mac_addr(char *mac_addr)
{
int sockfd;
struct ifreq ifr;
if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) >= 0) {
//strncpy(ifr.ifr_name, "eth0", IFNAMESIZE);
strncpy(ifr.ifr_name, "wlan0", IFNAMSIZ);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(sockfd, SIOCGIFHWADDR, (char*) &ifr) == 0) {
sprintf(mac_addr, "%02X:%02X:%02X:%02X:%02X:%02X",
(unsigned char) ifr.ifr_ifru.ifru_hwaddr.sa_data[0], (unsigned char) ifr.ifr_ifru.ifru_hwaddr.sa_data[1],
(unsigned char) ifr.ifr_ifru.ifru_hwaddr.sa_data[2], (unsigned char) ifr.ifr_ifru.ifru_hwaddr.sa_data[3],
(unsigned char) ifr.ifr_ifru.ifru_hwaddr.sa_data[4], (unsigned char) ifr.ifr_ifru.ifru_hwaddr.sa_data[5]);
return 0;
}
}
/* error */
return -1;
}
int main(int argc, char *argv[], char *envp[])
{
char mac_addr[80] = {0};
printf( "MAC = %d, %s\n", get_mac_addr(mac_addr), mac_addr );
return 0;
}
You must connect to a WiFi network, then try to get mac address.

android linux kernel communicate with user space about NETLINK_USER

I want to implements kernel communicate with user space,Here is my code:
#include <sys/socket.h>
#include <linux/netlink.h>
#include <stddef.h>
#define NETLINK_USER 16
#define MAX_PAYLOAD 1024 /* maximum payload size*/
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd;
struct msghdr msg;
void main()
{
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
printf("%d\n",sock_fd);
if (sock_fd < 0)
return -1;
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid(); /* self pid */
printf("%d\n",getpid());
.....
When I set NETLINK_USER = 17,18 or something else, then I exec this code :
sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
it show sock_fd return -1, so it must set NETLINK_USER = 16, I want know why?
And I have another question: Here is my kernel code:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <linux/semaphore.h>
#include <asm/cacheflush.h>
#include <linux/string.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <stddef.h>
#define NETLINK_USER 16
struct sock *nl_sk = NULL;
void **sys_call_table;
asmlinkage int (*original_call_open) (const char*, int, int);
asmlinkage int (*original_call_read) (unsigned int, char*, int);
asmlinkage long (*sys_openat) (int, const char*, int, int);
asmlinkage long our_openat(int dfd, const char *filename, int flags, int mode){
printk("%s\n",filename);
return sys_openat(dfd,filename,flags,mode);
}
void hello_nl_recv_msg(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
int pid;
struct sk_buff *skb_out;
int msg_size;
char *msg = "Hello from kernel";
int res;
printk(KERN_INFO "Entering: %s\n", __FUNCTION__);
msg_size = strlen(msg);
nlh = (struct nlmsghdr *)skb->data;
printk(KERN_INFO "Netlink received msg payload:%s\n", (char *)nlmsg_data(nlh));
pid = nlh->nlmsg_pid; //pid of sending process
skb_out = nlmsg_new(msg_size, 0);
if (!skb_out)
{
printk(KERN_ERR "Failed to allocate new skb\n");
return;
}
nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0);
NETLINK_CB(skb_out).dst_group = 0; //not in mcast group
strncpy(nlmsg_data(nlh), msg, msg_size);
res = nlmsg_unicast(nl_sk, skb_out, pid);
if (res < 0)
printk(KERN_INFO "Error while sending bak to user\n");
}
int init_module()
{
printk("Entering: %s\n", __FUNCTION__);
nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, 0, hello_nl_recv_msg, NULL, THIS_MODULE);
// printk("%s",nl_sk);
// nl_sk = netlink_kernel_create(NETLINK_USER, input);
if (!nl_sk)
{
printk(KERN_ALERT "Error creating socket.\n");
return -10;
}
return 0;
}
void cleanup_module()
{
// Restore the original call
sys_call_table[__NR_open] = original_call_open;
sys_call_table[__NR_read] = original_call_read;
sys_call_table[__NR_openat] = sys_openat;
printk(KERN_INFO "exiting hello module\n");
netlink_kernel_release(nl_sk);
}
//MODULE_LICENSE("GPL");
//module_init(init_module);
//module_exit(cleanup_module);
I found if I set NETLINK_USER = 16, when I insert kernel, the avd will stop running, but if I set NETLINK_USER = 31,28 or something else the avd will run normally,I want to know why it will like this?
At last, I think the function hello_nl_recv_msg haven't exec, I don't know why.

Bad type conversion in android ndk

I want my Android application to create a fake virtual device, to achieve this the device needs to be rooted and uinput module is needed.
I am using the following code to create the device, calling
static{ System.loadLibrary("myModule"); }
CreateVirtualDevice("Devname",0x123,0x123);
inside my java code.
Here the native code:
#include <string.h>
#include <jni.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/uinput.h>
static int fd;
static struct uinput_user_dev dev;
short int analog_axis_list[] = { ABS_X,ABS_Y,ABS_RX,ABS_RY, -1};
jint Java_com_example_app_MyClass_CreateVirtualDevice(
JNIEnv* env, jobject thiz, jstring param, jint param2, jint param3) {
int i;
memset(&dev, 0, sizeof(dev));
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (fd < 0)
return -1;
if(ioctl(fd, UI_SET_EVBIT, EV_ABS)<0) return -4;
for(i=0;analog_axis_list[i]>=0;i++){
if(ioctl(fd,UI_SET_ABSBIT,analog_axis_list[i])<0) return -5;
dev.absmax[analog_axis_list[i]]=32767;
dev.absmin[analog_axis_list[i]]=-32768;
}
const char *cparam = (*env)->GetStringUTFChars(env, param, 0);
snprintf(dev.name, UINPUT_MAX_NAME_SIZE, cparam);
(*env)->ReleaseStringUTFChars(env, param, cparam);
dev.id.bustype = BUS_VIRTUAL;
dev.id.vendor = param2;
dev.id.product = param3;
dev.id.version = 1;
if (write(fd, &dev, sizeof(dev)) < 0)
return -7;
if (ioctl(fd, UI_DEV_CREATE) < 0)
return -8;
return 0;
}
The device is successfully created, and the return value is 0.
Inside input.h the ABS values are so defined:
#define ABS_X 0x00
#define ABS_Y 0x01
#define ABS_RX 0x03
#define ABS_RY 0x04
But when checking the axis on android, I get proper values for AXIS_X and AXIS_Y, but ABS_RX and ABS_RY have wrong values. I used this code to check the axis values:
InputDevice device = InputDevice.getDevice(ids[position]);
List<InputDevice.MotionRange> ranges = device.getMotionRanges();
StringBuilder sb = new StringBuilder("");
if(ranges.size()==0){
sb.append("NO_MOTION_RANGES");
}
else{
int i = 0;
for(InputDevice.MotionRange range:ranges) {
if(i>0) {
sb.append(",");
}
sb.append(MotionEvent.axisToString(range.getAxis()));
sb.append("(").append(range.getAxis()).append(")");
i++;
}
}
return sb.toString();
And the result is:
AXIS_X(0),AXIS_Y(1),AXIS_Z(11),AXIS_RZ(14)
I am using the latest NDK release (r10d) without any particular settings enabled. What can cause these errors?
I want to point out that it's my code to have something wrong, because with an actual controller the axis numbers are correct.
Edit 1:
I tried to return analog_axis_list[2], which is ABS_RX, at the end of my function instead of 0 and it returns 3, so I think I'm passing a wrong type to the ioctl call.
Which type should I choose?
Android uses AXIS_Z and AXIS_RZ for the right stick; this is consistent with USB HID.

Linux Kernel Module unix domain sockets

I'm trying to share data between kernel and user space. The ultimate goal is to port it to Android, so I'm using unix domain sockets. (I don't know if this is the best option).
I have a kernel module acting as socket client and a c program acting as socket server. And vice-versa, a kernel module acting as socket server and a c program acting as socket client.
Programs are very simple. Servers just send a string to clients and they print it.
I run server_user.c and then I try to insert client_module.ko using insmod. I get the following error:
Kernel panic - not syncing: stack - protector: Kernel stack is corrupted in: ffffffffa0005157
drm-kms-helper: panic occurred, switching back to text console
What's wrong?
Module Server
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/un.h>
#include <net/sock.h>
#define SOCK_PATH "/tmp/usocket"
#define LISTEN 10
struct socket *sock = NULL;
struct socket *newsock = NULL;
static int __init server_module_init( void ) {
int retval;
char* string = "hello_world";
struct sockaddr_un addr;
struct msghdr msg;
struct iovec iov;
mm_segment_t oldfs;
// create
retval = sock_create(AF_UNIX, SOCK_STREAM, 0, &sock);
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, SOCK_PATH);
// bind
retval = sock->ops->bind(sock,(struct sockaddr *)&addr, sizeof(addr));
// listen
retval = sock->ops->listen(sock, LISTEN);
//accept
retval = sock->ops->accept(sock, newsock, 0);
//sendmsg
memset(&msg, 0, sizeof(msg));
memset(&iov, 0, sizeof(iov));
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iov->iov_base = string;
msg.msg_iov->iov_len = strlen(string)+1;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
oldfs = get_fs();
set_fs(KERNEL_DS);
retval = sock_sendmsg(newsock, &msg, strlen(string)+1);
set_fs(oldfs);
return 0;
}
static void __exit server_module_exit( void ) {
printk(KERN_INFO "Exit usocket.");
}
module_init( server_module_init );
module_exit( server_module_exit );
MODULE_LICENSE("GPL");
Module Client
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/un.h>
#include <linux/net.h>
#include <net/sock.h>
#include <linux/socket.h>
#define SOCK_PATH "/tmp/usocket"
#define MAX 100
struct socket *sock = NULL;
static int __init client_module_init( void ) {
int retval;
char str[MAX];
struct sockaddr_un addr;
struct msghdr msg;
struct iovec iov;
mm_segment_t oldfs;
printk(KERN_INFO "Start client module.\n");
// create
retval = sock_create(AF_UNIX, SOCK_STREAM, 0, &sock);
// connect
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, SOCK_PATH);
retval = sock->ops->connect(sock, (struct sockaddr *)&addr, sizeof(addr), 0);
// recvmsg
memset(&msg, 0, sizeof(msg));
memset(&iov, 0, sizeof(iov));
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_iov->iov_base= str;
msg.msg_iov->iov_len= strlen(str)+1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
oldfs = get_fs();
set_fs(KERNEL_DS);
retval = sock_recvmsg(sock, &msg, strlen(str)+1, 0);
set_fs(oldfs);
// print str
printk(KERN_INFO "client module: %s.\n",str);
// release socket
sock_release(sock);
return 0;
}
static void __exit client_module_exit( void )
{
printk(KERN_INFO "Exit client module.\n");
}
module_init( client_module_init );
module_exit( client_module_exit );
MODULE_LICENSE("GPL");
User Server
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define SOCK_PATH "/tmp/usocket"
int send_msg_to_client(int socketfd, char* data) {
struct msghdr msg;
struct iovec iov;
int s;
memset(&msg, 0, sizeof(msg));
memset(&iov, 0, sizeof(iov));
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov.iov_base = data;
iov.iov_len = strlen(data)+1;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
s = sendmsg(socketfd, &msg, 0);
printf("after send - iov_base: %s, length: %d\n", (char *) msg.msg_iov->iov_base, (int) strlen(msg.msg_iov->iov_base));
if(s < 0){
perror("sendmsg");
return 0;
}
return s;
}
int main(int argc, char* argv[])
{
if (argc != 2) {
printf("Usage: $ %s <string>\n",argv[0]);
return 0;
}
int s, s2, len, slen;
socklen_t t;
struct sockaddr_un local, remote;
char* data = argv[1];
printf("print data: %s\n",data);
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
memset(&local, 0, sizeof(local));
local.sun_family = AF_UNIX;
strcpy(local.sun_path, SOCK_PATH);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(s, (struct sockaddr *)&local, len) == -1) {
perror("bind");
exit(1);
}
if (listen(s, 5) == -1) {
perror("listen");
exit(1);
}
printf("Waiting for a connection...\n");
t = sizeof(remote);
if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1) {
perror("accept");
exit(1);
}
printf("Connected.\n");
slen = send_msg_to_client(s2, data);
if(slen < 0)
perror("send");
close(s2);
return 0;
}
User Client
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define SOCK_PATH "/tmp/usocket"
#define MAX 100
int recv_msg_from_server(int socketfd, char data[MAX]) {
struct msghdr msg;
struct iovec iov;
int s;
memset(&msg, 0, sizeof(msg));
memset(&iov, 0, sizeof(iov));
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov.iov_base = data;
iov.iov_len = MAX;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;
s = recvmsg(socketfd, &msg, 0);
printf("after recv - iov_base: %s, length: %d\n", (char *) msg.msg_iov->iov_base, (int) strlen(msg.msg_iov->iov_base));
if(s < 0){
perror("recvmsg");
}
return s;
}
int main(void)
{
int s, len, slen;
struct sockaddr_un remote;
char data[MAX];
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
printf("Trying to connect...\n");
memset(&remote, 0, sizeof(remote));
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, SOCK_PATH);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if (connect(s, (struct sockaddr *)&remote, len) == -1) {
perror("connect");
exit(1);
}
printf("Connected.\n");
slen = recv_msg_from_server(s, data);
if (slen < 0) {
perror("recvmsg");
}
//printf("print data received > %s\n", data);
close(s);
return 0;
}
I have just faced a similar issue (with UNIX datagrams though), and I believe there is a bug in the unix_mkname() function which is part of the kernel: this function makes sure the sun_path field of the given sockaddr_un structure is always null terminated by adding a NUL character after the end of that field. Since this is the last field, it will corrupt the area (stack or heap) where that structure has been allocated.
The best solution is to patch that function in the kernel source code, so that it only sets to NUL the last character of the sun_path field. Meanwhile, you can make your code work by decreasing by 1 byte the size you give for the sockaddr_un structure:
Module Server
// bind
retval = sock->ops->bind(sock,(struct sockaddr *)&addr, sizeof(addr) - 1);
Module Client
retval = sock->ops->connect(sock, (struct sockaddr *)&addr, sizeof(addr) - 1, 0);
As I am using UNIX datagrams, I cannot really tell if it fixes the issue for bind() and connect(), but a least, it fixes it for sock_sendmsg().
#shu-suzuki: thanks for the leads.
After 5 years I came back here...
I again stucked with this problem and found that I did the same thing 5 years ago.
The cause is as in Tey's answer and the solution is OK (sutbract 1 from the length) but here's another solution.
What you can do is to use struct sockaddr_storage as struct sockaddr_un. As far as I read the kernel code this is what they use to handle bind system call from user space.
sockeaddr_storage is larger than sockaddr_un so kernel code can write beyond the sizeof(sockaddr_un).
The code should be like
struct sockaddr_storage addrStorage;
struct sockaddr_un* addr;
memset(&addrStorage, 0, sizeof(addrStorage));
addr = (struct sockaddr_un*)&addrStorage;
addr->sun_family = AF_UNIX;
strcpy(addr->sun_path, "/my/sock/name");
kernel_bind(listenSock, (struct sockaddr*)addr, sizeof(*addr));
This looks working for me.

Categories

Resources