Linux (Ubuntu) ioctl KDGETLED/KDGKBLED always 0 - linux

Code snippet below; basically, I am grabbing the active vt and issuing an ioctl KDGETLED against that terminal for the current state of the capslock/numlock/scrolllock keys and I always get result=0, regardless of the state of the lock keys.
I've tried this on multiple Linux boxes, all running variants of Ubuntu (e.g. Mint). I've tried other fds for the KDGETLED command such as "/dev/tty", "/dev/console", 0, etc. I'm running into the same problem with KDGKBLED. Are others experiencing the same issue, am I doing something silly, am I running into poorly written drivers, or something else?
int fd;
vt_stat stat;
fd = open("/dev/tty0", O_RDONLY);
if (ioctl(fd, VT_GETSTATE, &stat) == -1) {
fprintf(stderr, "Error on VT_GETSTATE\n");
exit(1);
}
close(fd);
char tty[128];
sprintf(tty, "/dev/tty%d", stat.v_active);
printf("Query tty: %s\n", tty);
char result;
fd = open(tty, O_RDWR | O_NDELAY, 0);
if (ioctl(fd, KDGETLED, &result) == -1) {
fprintf(stderr, "Error on KDGETLED\n");
exit(1);
}
close(fd);
printf("LED flag state: %d\n", result);
Thanks, in advance, to all who review my question.

Checkout the driver code, especially the struct file_operations instance for that driver, and check the function assigned to the .ioctl member - if that is poorly coded (I've seen a lot of shitty stuff happening in ioctls) then that is definitely your issue.
In this case I am pretty sure it is the drivers fault. As long the ioctl command shows no compile error, everything - especially error handling and input checking - is the task of the driver.

Related

Python3 read fron character device in blocking mode

I wrote a character device driver. Now I want to use python to read from it when there is data.
However, I found that the modules "io" as well as "os" do not block upon reading. The latter even when I set os.set_blocking(fd,true).
Is there a way to access the device in blocking mode?
Or do I miss something in the device driver (tail works fine)?
f=io.open("/dev/tstty0","r")
while (1)
data=str(f.read(32))
print("mark") # <--- endless list of marks
#do somthing
The read function of the device driver:
static ssize_t tstty_read(
struct file *filp,
char *buffer,
size_t length,
loff_t *offset)
{
unsigned char b;
unsigned long ofs=0;
devConfig* dev=filp->private_data;
if (dev)
{
while (fifoGet(&dev->tcp2dev,&b) && (ofs<length))
{
if (put_user(b,buffer+ofs))
{
printk(KERN_ERR "Could not copy user data");
return -EINVAL;
}
ofs++;
}
//printk(KERN_INFO "Reading device");
return ofs;
}
printk(KERN_ERR "Unknown device: %s",filp->f_path.dentry->d_iname);
return -EINVAL;
};
The read function reads any bytes available from a fifo. I none is available 0 is returned.
Kudos to Ian Abbott. A character device has to implement the ability to block a read request. The read file operation has to evaluate filp->f_flags & O_NONBLOCK to check if a client has requested blocking I/O.
This link helped me with an example:
simple linux driver code for blocking and non-blocking read
This example works but one has to consider two more things not covered in the example: a) What to do when you want to unload the driver while in read operation (just dont do it or wake up and abort)?
b) How to abort a client caught in blocking I/O?

how to implement tcpdump -i interface arp with libpcap

I want to implement command tcpdump -i eth0 arp to observe arp packets on interface eth0 on my ubuntu. I use libpcap, but the return value of function pcap_next_ex is always 0. With tcpdump -i eth0 arp in the same time , it can observe arp packets.
/*
* compile(root): gcc test.c -lpcap
* run : ./a.out
* output : time out
* time out
* time out
* ...
*/
#include <pcap.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define ARP_REQUEST 1
#define ARP_REPLY 2
typedef struct arp_hdr_s arp_hdr_t;
struct arp_hdr_s {
u_int16_t htype;
u_int16_t ptype;
u_char hlen;
u_char plen;
u_int16_t oper;
u_char sha[6];
u_char spa[4];
u_char tha[6];
u_char tpa[4];
};
#define MAXBYTES2CAPTURE 2048
int
main(int argc, char **argv)
{
char err_buf[PCAP_ERRBUF_SIZE];
const unsigned char *packet;
int i;
int ret;
arp_hdr_t *arp_header;
bpf_u_int32 net_addr;
bpf_u_int32 mask;
pcap_t *desrc;
struct pcap_pkthdr *pkthdr;
struct bpf_program filter;
net_addr = 0;
mask = 0;
memset(err_buf, 0, PCAP_ERRBUF_SIZE);
desrc = pcap_open_live("eth0", MAXBYTES2CAPTURE, 0, 512, err_buf);
if (desrc == NULL) {
fprintf(stderr, "error: %s\n", err_buf);
exit(-1);
}
ret = pcap_lookupnet("eth0", &net_addr, &mask, err_buf);
if (ret < 0) {
fprintf(stderr, "error: %s\n", err_buf);
exit(-1);
}
ret = pcap_compile(desrc, &filter, "arp", 1, mask);
if (ret < 0) {
fprintf(stderr, "error: %s\n", pcap_geterr(desrc));
exit(-1);
}
ret = pcap_setfilter(desrc, &filter);
if (ret < 0) {
fprintf(stderr, "errnor: %s\n", pcap_geterr(desrc));
exit(-1);
}
while (1) {
ret = pcap_next_ex(desrc, &pkthdr, &packet);
if (ret == -1) {
printf("%s\n", pcap_geterr(desrc));
exit(1);
} else if (ret == -2) {
printf("no more\n");
} else if (ret == 0) { // here
printf("time out\n");
continue;
}
arp_header = (arp_hdr_t *)(packet + 14);
if (ntohs(arp_header->htype) == 1 && ntohs(arp_header->ptype == 0x0800)) {
printf("src IP: ");
for (i = 0; i < 4; i++) {
printf("%d.", arp_header->spa[i]);
}
printf("dst IP: ");
for (i = 0; i < 4; i++) {
printf("%d.", arp_header->tpa[i]);
}
printf("\n");
}
}
return 0;
}
Without getting too deep in your code, I can see a major problem:
In your use of pcap_open_live(), you do not set promiscuous mode: the third parameter should be non-zero. If the ARP request is not targeted to your interface IP, pcap will not see it without promiscuous mode. tcpdump does, unless specifically told not to do so by using the --no-promiscuous-mode, use promisc (and hence will require CAP_NET_ADMIN privilege, which you'll get by sudo, which your program will require too).
Side note:
1/ Leak: you may want to free your filter using pcap_freecode() after your pcap_setfilter().
2/ I assume you've read the official tuto here:
http://www.tcpdump.org/pcap.html
...if that's not the case you'd be well advised to do that first. I quote:
A note about promiscuous vs. non-promiscuous sniffing: The two
techniques are very different in style. In standard, non-promiscuous
sniffing, a host is sniffing only traffic that is directly related to
it. Only traffic to, from, or routed through the host will be picked
up by the sniffer. Promiscuous mode, on the other hand, sniffs all
traffic on the wire. In a non-switched environment, this could be all
network traffic. [... more stuff on promisc vs non-promisc]
EDIT:
Actually, looking deeper to you code compared to my code running for +1 year at production level (both in-house and at the customer) I can see many more things that could be wrong:
You never call pcap_create()
You never call pcap_set_promisc(), we've talked about this already
You never call pcap_activate(), this may be the core issue here
...pcap is very touchy about the sequence order of operations to first get a pcap_t handle, and then operate on it.
At the moment, the best advice I can give you - otherwise this is going to a live debugging session between you and me, are:
1/ read and play/tweak with the code from the official tutorial:
http://www.tcpdump.org/pcap.html
This is mandatory.
2/ FWIW, my - definitely working - sequence of operations is this:
pcap_lookupnet()
pcap_create()
pcap_set_promisc()
pcap_set_snaplen(), you may or may not need this
pcap_set_buffer_size(), you may or may not need this
pcap_activate() with a note: Very important: first activate, then set non-blocking from PCAP_SETNONBLOCK(3PCAP): When first activated with pcap_activate() or opened with pcap_open_live() , a capture handle is not in non-blocking mode''; a call to pcap_set-nonblock() is required in order to put it intonon-blocking'' mode.
...and then, because I do not use stinking blocking/blocking with timeout, busy looping:
pcap_setnonblock()
pcap_get_selectable_fd()
...then and only then:
- pcap_compile()
- followed by a pcap_setfilter()
- and then as I mentioned a pcap_freecode()
- and then a select() or family on the file'des' I get from pcap_get_selectable_fd(), to pcap_dispatch(), but this is another topic.
pcap is an old API starting back in the 80's, and its really very very touchy. But don't get discouraged! It's great - once you get it right.
It would probably work better if you did
if (ntohs(arp_header->htype) == 1 && ntohs(arp_header->ptype) == 0x0800) {
rather than
if (ntohs(arp_header->htype) == 1 && ntohs(arp_header->ptype == 0x0800)) {
The latter evaluates arp_header->type == 0x0800, which, when running on a little-endian machine (such as a PC), will almost always evaluate to "false", because the value will look like 0x0008, not 0x0800, in an ARP packet - ARP types are big-endian, so they'll look byte-swapped on a little-endian machine). That means it'll evaluate to 0, and byte-swapping 0 gives you zero, so that if condition will evaluate to "false", and the printing code won't be called.
You'll still get lots of timeouts if you fix that, unless there's a flood of ARP packets, but at least you'll get the occasional ARP packet printed out. (I would advise printing nothing on a timeout; pcap-based programs doing live capturing should expect that timeouts should happen, and should not report them as unusual occurrences.)

how to use SIOCIFDESTROY in FreeBSD?

My app creates a tap interface, and everything works well. But on FreeBSD, when it exits, the tap interface remains. To delete it, I have to manually run this command:
sudo ifconfig tap0 destroy
But I'd like to do this programmatically within my application. Where can I find the docs for SIOCIFDESTROY? Here is what I've tried when my app exits:
struct ifreq ifr;
memset(&ifr, '\0', sizeof(ifr));
strcpy(ifr.ifr_name, "tap0");
int sock = socket(PF_INET, SOCK_STREAM, 0);
err = ioctl(sock, SIOCIFDESTROY, &ifr);
At this point, err is zero, but the tap interface still exists when the app ends. Anyone know what else I might be missing?
The tricky part was trying to find documentation to describe is the parameter to pass to ioctl(). I never did find anything decent to read.
Turns out a completely blank ifreq with just the tap interface name set is all that is needed. In addition to the original code I included in the question, also note that I close the tap device file descriptor prior to deleting the actual tap interface. I can only imagine that might also be relevant:
close(device_fd);
struct ifreq ifr;
memset(&ifr, '\0', sizeof(ifr));
strcpy(ifr.ifr_name, "tap0");
int sock = socket(PF_INET, SOCK_STREAM, 0);
err = ioctl(sock, SIOCIFDESTROY, &ifr);

Embedded Linux poll() returns constantly

I have a particular problem. Poll keeps returning when I know there is nothing to read.
So the setup it as follows, I have 2 File Descriptors which form part of a fd set that poll watches. One is for a Pin high to low change (GPIO). The other is for a proxy input. The problem occurs with the Proxy Input.
The order of processing is: start main functions; it will then poll; write data to proxy; poll will break; accept the data; send the data over SPI; receiving slave device, signals that it wants to send ack, by Dropping GPIO low; poll() senses this drop and reacts;
Infinite POLLINs :(
IF I have no timeout on the Poll function, the program works perfectly. The moment I include a timeout on the Poll. The Poll returns continuously. Not sure what I am doing wrong here.
while(1)
{
memset((void*)fdset, 0, sizeof(fdset));
fdset[0].fd = gpio_fd;
fdset[0].events = POLLPRI; // POLLPRI - There is urgent data to read
fdset[1].fd = proxy_rx;
fdset[1].events = POLLIN; // POLLIN - There is data to read
rc = poll(fdset, nfds, 1000);//POLL_TIMEOUT);
if (rc < 0) // Error
{
printf("\npoll() failed/Interrupted!\n");
}
else if (rc == 0) // Timeout occurred
{
printf(" poll() timeout\n");
}
else
{
if (fdset[1].revents & POLLIN)
{
printf("fdset[1].revents & POLLIN\n");
if ((resultR =read(fdset[1].fd,command_buf,10))<0)
{
printf("Failed to read Data\n");
}
if (fdset[0].revents & POLLPRI)
//if( (gpio_fd != -1) && (FD_ISSET(gpio_fd, &err)))
{
lseek(fdset[0].fd, 0, SEEK_SET); // Read from the start of the file
len = read(fdset[0].fd, reader, 64);
}
}
}
}
So that is the gist of my code.
I have also used GDB and while debugging, I found that the GPIO descriptor was set with revents = 0x10, which means that an error occurred and that POLLPRI also occurred.
In this question, something similar was addressed. But I do read all the time whenever I get POLLIN. It is a bit amazing, that this problem only occurs when I include the timeout, if I replace the poll timeout with -1, it works perfectly.
When poll fails (returning -1) you should do something with errno, perhaps thru perror; and your nfds (the second argument to poll) is not set, but it should be the constant 2.
Probably the GCC compiler would have given a warning, at least with all warnings enabled (-Wall), about nfds not being set.
(I'm guessing that nfds being uninitialized might be some "random" large value.... So the kernel might be polling other "random" file descriptors, those in your fdset after index 2...)
BTW, you could strace your program. And using the fdset name is a bit confusing (it could refer to select(2)).
Assuming I fixed your formatting properly in your question, it looks like you have a missing } after the POLLIN block and the next if() that checks the POLLPRI. It would possibly work better this way:
if (fdset[1].revents & POLLIN)
{
printf("fdset[1].revents & POLLIN\n");
if ((resultR =read(fdset[1].fd,command_buf,10))<0)
{
printf("Failed to read Data\n");
}
}
if (fdset[0].revents & POLLPRI)
//if( (gpio_fd != -1) && (FD_ISSET(gpio_fd, &err)))
{
lseek(fdset[0].fd, 0, SEEK_SET); // Read from the start of the file
len = read(fdset[0].fd, reader, 64);
}
Although you can do whatever you want with indentation in C/C++/Java/JavaScript, not doing it right can bite you really hard. Hopefully, I'm wrong and your original code was correct.
Another one I often see: People not using the { ... } at all and end up writing code like:
if(expr) do_a; do_b;
and of course, do_b; will be executed all the time, whether expr is true or false... and although you could fix the above with a comma like so:
if(expr) do_a, do_b;
the only safe way to do it right is to use the brackets:
if(expr)
{
do_a;
do_b;
}
Always make sure your indentation is perfect and write small functions so you can see that it is indeed perfect.

/proc/devices still shows unregistered device

I am learning to write my first Linux char driver, but can't seem to make it work as expected.
The code for the driver module's init and exit functions are below:
static int __init one_init(void)
{
int result;
printk(KERN_DEBUG "In ones init call");
result = alloc_chrdev_region(&onedev, 0, 4, "one");
printk("Allocated device major: %d, first minor: %d",MAJOR(onedev),MINOR(onedev));
return 0;
}
static void __exit one_exit(void)
{
unregister_chrdev_region(onedev,4);
printk(KERN_DEBUG "In ones exit call");
}
My device still shows in /proc/devices after I unload my driver, whose exit function calls unregister_chrdev_region.
The dmesg command prints shows that my driver's init and exit calls were made.
I saw a few related questions, but the answers did not solve my seemingly simple problem.
What am I doing or expecting wrong?
Use 'rmmod modulename' in the terminal. This should unload the module and remove the associations.

Resources