I am trying to implement event triggered serial port read with Gtk3+.
When the data is received, GUI is getting unresponsive. I think after data receive event the loop does not go to gtk_main(). Sometimes data flow continue from sender device on serial port and GUI turn back to responsive.
So, how to return gtk_main(() loop after receive some bytes from serial?
This is the code that I wrote;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <errno.h>
#include <termios.h>
#include <gtk/gtk.h>
void signal_handler_IO (int status); /* definition of signal handler */
volatile int n, fd;
volatile char buf [100];
int connected;
struct termios termAttr;
struct sigaction saio;
void UartInit(){
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd == -1)
{
perror("open_port: Unable to open /dev/ttyO1\n");
exit(1);
}
saio.sa_handler = signal_handler_IO;
saio.sa_flags = 0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
fcntl(fd, F_SETFL, FNDELAY);
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, O_ASYNC ); /**<<<<<<------This line made it work.**/
tcgetattr(fd,&termAttr);
//baudRate = B115200; /* Not needed */
cfsetispeed(&termAttr,B115200);
cfsetospeed(&termAttr,B115200);
termAttr.c_cflag &= ~PARENB;
termAttr.c_cflag &= ~CSTOPB;
termAttr.c_cflag &= ~CSIZE;
termAttr.c_cflag |= CS8;
termAttr.c_cflag |= (CLOCAL | CREAD);
termAttr.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
termAttr.c_iflag &= ~(IXON | IXOFF | IXANY);
termAttr.c_oflag &= ~OPOST;
tcsetattr(fd,TCSANOW,&termAttr);
printf("UART1 configured....\n");
//close(fd);
}
int main(int argc, char *argv[])
{
GtkWidget *main_window, *label, *image, *image_alt;
GtkWidget *main_box; /* VBox to hold main_hbox and the controls */
GtkWidget *controls; /* HBox to hold the buttons and the slider */
gtk_init(&argc, &argv); //Inititalize GTK
main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_size_request(main_window, 480, 800);
label = gtk_label_new("deeneme");
//gtk_container_add(GTK_CONTAINER(window), label);
gtk_window_set_decorated(GTK_WINDOW(main_window), FALSE); //Hide menu bar
image = gtk_image_new_from_file("/home/x/Desktop/downArrow2.png");
image_alt = gtk_image_new_from_file("/home/x/Desktop/arcelik.png");
//gtk_container_add(GTK_CONTAINER(main_window), image);
controls = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_pack_start (GTK_BOX (controls), image, FALSE, FALSE, 50);
gtk_box_pack_start (GTK_BOX (controls), label, FALSE, FALSE, 0);
main_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start (GTK_BOX (main_box), controls, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (main_box), image_alt, FALSE, FALSE, 0); //altda ki image ekle
gtk_container_add (GTK_CONTAINER (main_window), main_box);
gtk_widget_show_all(main_window); //Show all widgets
// gtk_widget_hide(image);
UartInit(); //Initialize UART
gtk_label_set_markup(GTK_LABEL(label), "<span foreground=\"white\" size='300100'>1</span>"); //Set number color and size......1234
gtk_main(); //Start main loop
return 0;
}
void signal_handler_IO (int status)
{
int n = read (fd, &buf, sizeof buf);
if(n > 1)
{
buf[n] = '\0';
printf("Receive OK %s\n",buf);
}
}
Related
This program is intended to communicate over an unreliable serial channel via a PL2303 usb converter with a distant microcontroller. The main loop uses g_io_add_watch to listen for data from the micro. It then calls g_io_read_chars to read the data and g_io_write_chars to send a one-byte acknowledge. The micro echos this back. The read and write are called from within ReadStationMessage. If the micro is slow to respond, the ReadStationMessage() function is called twice, once to read the data and again to receive the echo. However, if it responds immediately, ReadStationMessage() is called only once and the echo byte is appended to the data. I don't understand how this is possible when g_io_write_chars does not send the acknowledge until after g_io_read_chars returns and the micro does nothing until it receives the acknowledge.
#include <gtk/gtk.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
g_print("Error from tcgetattr: %s\n", strerror(errno));
return -1; }
cfmakeraw(&tty);
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cc[VMIN] = 0; tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
g_print("Error from tcsetattr: %s\n", strerror(errno));
return -1; }
return 0;
}
static gboolean ReadStationMessage( GIOChannel *channel, GIOCondition condition, guchar* user_data )
{
guchar buf[128];
gsize bytes_read, bytes_written;
gint i;
g_print("\nentering ReadStationMessage\n");
g_io_channel_read_chars( channel, buf, 128, &bytes_read, NULL );
for( i=0; i<bytes_read; i++ ) g_print("%u ", buf[i]);
buf[0] = 0;
g_io_channel_write_chars( channel, buf, 1, &bytes_written, NULL );
return TRUE;
}
int main( int argc, char *argv[] )
{
char *portname = "/dev/ttyUSB0";
gint fd;
GIOChannel *channel;
static guchar user_data[128];
GError *error=NULL;
guint EventSource_id;
fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC );
set_interface_attribs(fd, B9600);
channel = g_io_channel_unix_new(fd);
g_io_channel_set_encoding(channel, NULL, &error); // raw data, no encoding
GIOCondition condition = G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
gtk_init (&argc, &argv);
EventSource_id = g_io_add_watch( channel, condition, (GIOFunc) ReadStationMessage, user_data );
return 0;
}
Fixed! I need to g-io-channel-flush after write.
I coded a program in C of a tcp socket but once executed, the server returns an error from the accept function but i can't find out why..
If you guys can help me, that would be appreciated. Also, if you have any advice on the way i programmed this, please feel free to tell me.
Here is my code :
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
int listenSocket, status, socketClient;
unsigned short int msgLength;
struct addrinfo hints, *servinfo;
struct sockaddr_in clientAddress;
socklen_t clientAddressLength = sizeof clientAddress;
char msg[101];
//Test port number
if (argc != 2) {
fprintf(stderr,"Usage : %s [NUMERO_PORT]\n",argv[0]);
return 2;
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_DGRAM; // UDP
hints.ai_flags = 0; //Car on fait le test sur la meme machine
if ((status = getaddrinfo(NULL, argv[1], &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status));
return 3;
}
if ((listenSocket = socket(servinfo->ai_family, servinfo-
>ai_socktype, servinfo->ai_protocol)) == -1) {
perror("socket:");
return 4;
}
if (bind(listenSocket, servinfo->ai_addr, servinfo->ai_addrlen) ==
-1) {
close(listenSocket);
perror("bind:");
return 5;
}
listen(listenSocket,5);
int sizeOfSockAddr = sizeof(clientAddress);
socketClient= accept(listenSocket, NULL, NULL);
if (socketClient < 0) {
fprintf(stderr,"Erreur accept\n");
return 6;
}
freeaddrinfo(servinfo);
printf("Waiting for a client's request %s\n", argv[1]);
while (1) {
//some things
}
}`
I am trying to map reserved memory (30M with offset of 2G) at boot time (boot kernel parameters mem=2G memmap=30M$2G) to user space using the remap_pfn_range, bellow is my driver code:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
// #include <asm/error.h>
#define MAP_MAJOR 150
#define RAW_DATA_SIZE 0x1E00000 // 30 Mo
#define RAW_DATA_OFFSET 0x80000000 //2G
int results;
static void *rawdataStart = NULL;
static int map_mmap(struct file *filp, struct vm_area_struct *vma);
struct file_operations map_fops = {
.open = nonseekable_open,
.mmap = map_mmap
};
static int map_mmap(struct file *filp, struct vm_area_struct *vma) {
if (rawdataStart == NULL) {
printk(KERN_ERR "Memory not mapped!\n");
return -EAGAIN;
}
if ((vma->vm_end - vma->vm_start) != RAW_DATA_SIZE) {
printk(KERN_ERR "Error: sizes don't match (buffer size = %d, requested size = %lu)\n", RAW_DATA_SIZE, vma->vm_end - vma->vm_start);
return -EAGAIN;
}
results = remap_pfn_range(vma, vma->vm_start, RAW_DATA_OFFSET >> PAGE_SHIFT, RAW_DATA_SIZE, PAGE_SHARED);
if (results != 0) {
printk(KERN_ERR "Error in calling remap_pfn_range: returned %d\n", results);
return -EAGAIN;
}
return 0;
}
static int __init map_init(void)
{
printk("init map module\n");
if (register_chrdev(MAP_MAJOR,"mapReserved", &map_fops) <0 )
{
printk("unable to get major for map module\n");
return -EBUSY;
}
rawdataStart = ioremap(RAW_DATA_OFFSET, RAW_DATA_SIZE);
if (rawdataStart == NULL) {
printk(KERN_ERR "Unable to remap memory\n");
return 1;
}
printk(KERN_INFO "ioremap returned %p\n", rawdataStart);
return 0;
}
void __exit map_cleanup(void)
{
printk("exit map module\n");
unregister_chrdev(MAP_MAJOR,"mapReserved");
if (rawdataStart != NULL) {
printk(KERN_INFO "Unmapping memory at %p\n", rawdataStart);
iounmap(rawdataStart);
} else {
printk(KERN_WARNING "No memory to unmap!\n");
}
return;
}
MODULE_LICENSE("GPL");
module_init( map_init);
module_exit( map_cleanup);
and my user space app is below
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#define RAW_DATA_SIZE 0x1E00000
int main(void)
{
void * data;
int fd = open("/dev/mapReserved", O_RDWR);
if (fd == -1) {
perror("open error...\n");
return -1;
}
data = mmap(NULL, RAW_DATA_SIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 4096);
close(fd);
return 0;
}
when i insert the module it's return
[ 873.621763] init map module
[ 873.623175] ioremap returned fb580000
but when i am executing the user space app it's return error
open error...
I've resolved this problem following those references :
1- Reserve memory in Linux driver module and share it using driver mmap
2- mmap of several GB of reserved memory using
in my case i am reserving 30M from the offset 2G and bellow is the code
module:
// #include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/debugfs.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/mm.h>
#include <linux/kdev_t.h>
#include <asm/page.h>
#include <linux/cdev.h>
#include <linux/device.h>
#ifndef VM_RESERVED
# define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP)
#endif
#define RAW_DATA_SIZE 31457280
#define RAW_DATA_OFFSET 0x80000000UL
void *rawdataStart;
struct dentry *file;
/*
* Open the device; in fact, there's nothing to do here.
*/
int simple_open (struct inode *inode, struct file *filp)
{
return 0;
}
/*
* Closing is just as simpler.
*/
static int simple_release(struct inode *inode, struct file *filp)
{
return 0;
}
static int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
unsigned long mapoffset;
mapoffset = RAW_DATA_OFFSET + (vma->vm_pgoff << PAGE_SHIFT);
ret = remap_pfn_range(vma, vma->vm_start, mapoffset >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, PAGE_SHARED);
if ( ret != 0 ) {
printk("Error remap_pfn_range. \n");
return -EAGAIN;
}
return 0;
}
/* Device uses remap_pfn_range */
static struct file_operations simple_remap_ops = {
.owner = THIS_MODULE,
.open = simple_open,
.release = simple_release,
.mmap = simple_remap_mmap,
};
/*
* Module housekeeping.
*/
static int simple_init(void)
{
file = debugfs_create_file("mmap_example", 0644, NULL, NULL, &simple_remap_ops);
rawdataStart = ioremap(RAW_DATA_OFFSET, RAW_DATA_SIZE);
if (rawdataStart!=NULL){
printk("rawdataStart at:%p \n", rawdataStart);
memset(rawdataStart, 'c', 20971520);
memset(rawdataStart+20971520, '$', 100);
}else{
printk("rawdataStart is NULL \n");
return -1;
}
return 0;
}
static void simple_cleanup(void)
{
debugfs_remove(file);
if (rawdataStart != NULL) {
printk(KERN_INFO "Unmapping memory at %p\n", rawdataStart);
iounmap(rawdataStart);
} else {
printk(KERN_WARNING "No memory to unmap!\n");
}
}
module_init(simple_init);
module_exit(simple_cleanup);
MODULE_AUTHOR("Jonathan Corbet");
MODULE_LICENSE("Dual BSD/GPL");
and the user space App:
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#define RAW_DATA_SIZE 31457280
int main(int argc, char **argv) {
int configfd;
char * address = NULL;
unsigned long chkSum;
FILE *fp = fopen("results.log", "w+");
configfd = open("/sys/kernel/debug/mmap_example", O_RDWR);
if (configfd < 0) {
perror("Open call failed");
return -1;
}
address = (unsigned char*) mmap(NULL, RAW_DATA_SIZE, PROT_WRITE,
MAP_PRIVATE, configfd, 0);
if (address == MAP_FAILED) {
perror("mmap operation failed");
return -1;
}
fputs(address, fp);
fclose(fp);
close(configfd);
return 0;
}
I'm actually back to programming in C, and I want to code a UDP Client.
My problem is that I'm having an error when executing the sendto function... getting errno : 22 and the message error : Invalid argument
char query[1024];
int querySize = strlen(query);
SOCKADDR_IN dest = { 0 };
int destSize = sizeof dest;
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr('192.168.0.3');
dest.sin_port = htons(6000);
sendto(sock, query, querySize, 0, (SOCKADDR *) &dest, destSize)
Hope someone could help me?
Here is my full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#if defined (WIN32)
#include <winsock2.h>
typedef int socklen_t;
#elif defined (linux)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define closesocket(param) close(param)
typedef int SOCKET;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
#endif
int main(int argc, char *argv[]) {
#if defined (WIN32)
WSADATA WSAData;
WSAStartup(MAKEWORD(2,2), &WSAData);
#endif
char source_ip[15] = "192.168.0.20";
int source_port = 5000;
char query[1024];
printf("- Opening Socket\n");
SOCKET sock;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock == INVALID_SOCKET) {
perror("[ERROR] socket()");
exit(errno);
}
printf("- Configuring socket source to : [%s:%d]\n", source_ip, source_port);
SOCKADDR_IN source;
source.sin_family = AF_INET;
source.sin_addr.s_addr = inet_addr(source_ip);
source.sin_port = htons(source_port);
if(bind(sock, (SOCKADDR *)&source, sizeof(source)) == SOCKET_ERROR) {
perror("[ERROR] bind()");
exit(errno);
}
int querySize = strlen(query);
SOCKADDR_IN dest = { 0 };
int destSize = sizeof dest;
dest.sin_family = AF_INET;
printf("- Sending packets\n");
dest.sin_addr.s_addr = inet_addr('192.168.0.3');
dest.sin_port = htons(6000);
if(sendto(sock, query, querySize, 0, (SOCKADDR *) &dest, destSize) < 0) {
perror("[ERROR] sendto()");
printf("%d\n", errno);
exit(errno);
}
printf("\n\n##############################\n");
printf("Closing socket ...\n");
closesocket(sock);
#if defined (WIN32)
WSACleanup();
#endif
printf("Program finished.\n");
return 0;
}
Did you notice,
that query is not being initialized?
So strlen(query) might result in a "very long" buffer.
That would be a good candidate for an EINVAL.
I referenced C code on this website: https://gist.github.com/austinmarton/2862515
Here is a image to explain:
I edit it at two parts, one pat is for ethertype(change 0x0800 to a custom-protocol 0x1234)
and another part is deleting code for IP header processing (because original code is based on IP, but I need a raw ethernet frame).
I used wireshark to detect packets, and I can receive the packets I sent(in left of image),and I can see send.out exactly sending packets(bottom right of image). But recv.out cannot receive packet !?(upper right of image).
However, if I use 0x0800 for protocol, recv.out can receive packets from outside, but still cannot receive the packets I sent.
Is there any mistake for setting socket
Here is my code:
send.c
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#define MY_DEST_MAC0 0xbc
#define MY_DEST_MAC1 0xee
#define MY_DEST_MAC2 0x7b
#define MY_DEST_MAC3 0x75
#define MY_DEST_MAC4 0x56
#define MY_DEST_MAC5 0x2a
#define DEFAULT_IF "eth0"
#define BUF_SIZ 1024
int main(int argc, char *argv[])
{
int sockfd;
struct ifreq if_idx;
struct ifreq if_mac;
int tx_len = 0;
char sendbuf[BUF_SIZ];
struct ether_header *eh = (struct ether_header *) sendbuf; /*structure*/
struct iphdr *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header));
struct sockaddr_ll socket_address;
char ifName[IFNAMSIZ];
unsigned short proto = 0x1234;
/* Get interface name *//*eth0*/
if (argc > 1)
strcpy(ifName, argv[1]);
else
strcpy(ifName, DEFAULT_IF);
/* Open RAW socket to send on *//*IPv4*/
if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(proto))) == -1) {
perror("socket");
}
/* Get the index of the interface to send on *//*0*/
memset(&if_idx, 0, sizeof(struct ifreq));
strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)/*save INDEX info into if_idx*/
perror("SIOCGIFINDEX");
/* Get the MAC address of the interface to send on *//*local*//*save MAC info into if_mac*/
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, ifName, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
perror("SIOCGIFHWADDR");
/* Construct the Ethernet header */
memset(sendbuf, 0, BUF_SIZ);
/* Ethernet header */
eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];
eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];
eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];
eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];
eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];
eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];
eh->ether_dhost[0] = MY_DEST_MAC0;
eh->ether_dhost[1] = MY_DEST_MAC1;
eh->ether_dhost[2] = MY_DEST_MAC2;
eh->ether_dhost[3] = MY_DEST_MAC3;
eh->ether_dhost[4] = MY_DEST_MAC4;
eh->ether_dhost[5] = MY_DEST_MAC5;
/* Ethertype field */
eh->ether_type = htons(proto);
tx_len += sizeof(struct ether_header);
/* Packet data */
sendbuf[tx_len++] = "h";
sendbuf[tx_len++] = "e";
sendbuf[tx_len++] = "l";
sendbuf[tx_len++] = "l";
sendbuf[tx_len++] = "o";
/* Index of the network device */
socket_address.sll_ifindex = if_idx.ifr_ifindex;
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address.sll_addr[0] = MY_DEST_MAC0;
socket_address.sll_addr[1] = MY_DEST_MAC1;
socket_address.sll_addr[2] = MY_DEST_MAC2;
socket_address.sll_addr[3] = MY_DEST_MAC3;
socket_address.sll_addr[4] = MY_DEST_MAC4;
socket_address.sll_addr[5] = MY_DEST_MAC5;
/* Send packet */
int cnt=0;
while(cnt<5){
if (sendto(sockfd, sendbuf, tx_len, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");
else
printf("success!\n");
cnt++;
}
return 0;
}
recv.c
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>
#define DEST_MAC0 0xbc
#define DEST_MAC1 0xee
#define DEST_MAC2 0x7b
#define DEST_MAC3 0x75
#define DEST_MAC4 0x56
#define DEST_MAC5 0x2a
#define ETHER_TYPE 0x1234
#define DEFAULT_IF "eth0"
#define BUF_SIZ 1024
int main(int argc, char *argv[])
{
char sender[INET6_ADDRSTRLEN];
int sockfd, ret, i;
int sockopt;
ssize_t numbytes;
struct ifreq ifopts; /* set promiscuous mode */
struct sockaddr_storage their_addr;
uint8_t buf[BUF_SIZ];
char ifName[IFNAMSIZ];
/* Get interface name *//*eth0*/
if (argc > 1)
strcpy(ifName, argv[1]);
else
strcpy(ifName, DEFAULT_IF);
/* Header structures */
struct ether_header *eh = (struct ether_header *) buf;
/* Open PF_PACKET socket, listening for EtherType ETHER_TYPE *//*0x1234*/
if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1) {
perror("listener: socket");
return -1;
}
/* Set interface to promiscuous mode - do we need to do this every time? *//*cpy ifname into ifr_name*/
strncpy(ifopts.ifr_name, ifName, IFNAMSIZ-1);
ioctl(sockfd, SIOCGIFFLAGS, &ifopts); /*set promisc mode*/
ifopts.ifr_flags |= IFF_PROMISC;
ioctl(sockfd, SIOCSIFFLAGS, &ifopts);
/* Allow the socket to be reused - incase connection is closed prematurely */
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
perror("setsockopt");
close(sockfd);
exit(EXIT_FAILURE);
}
/* Bind to device */
if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ-1) == -1) {
perror("SO_BINDTODEVICE");
close(sockfd);
exit(EXIT_FAILURE);
}
repeat: printf("listener: Waiting to recvfrom...\n");
numbytes = recvfrom(sockfd, buf, BUF_SIZ, 0, NULL, NULL);
printf("listener: got packet %lu bytes\n", numbytes);
/* Check the packet is for me */
if (eh->ether_dhost[0] == DEST_MAC0 &&
eh->ether_dhost[1] == DEST_MAC1 &&
eh->ether_dhost[2] == DEST_MAC2 &&
eh->ether_dhost[3] == DEST_MAC3 &&
eh->ether_dhost[4] == DEST_MAC4 &&
eh->ether_dhost[5] == DEST_MAC5) {
printf("Correct destination MAC address\n");
} else {
printf("Wrong destination MAC: %x:%x:%x:%x:%x:%x\n",
eh->ether_dhost[0],
eh->ether_dhost[1],
eh->ether_dhost[2],
eh->ether_dhost[3],
eh->ether_dhost[4],
eh->ether_dhost[5]);
ret = -1;
goto done;
}
/* Print packet */
printf("\tData:");
for (i=0; i<numbytes; i++) printf("%02x:", buf[i]);
printf("\n");
done: goto repeat;
close(sockfd);
return ret;
}
you can get All frames from your target with below changes in your receive code :
please replace line :
if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1) {
with this line :
if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
Because in your original code you changed normal ethernet header type then OS can not detect its process listener(your program) and get it to you but when you set this line, OS can get you all results so you can get your special answers.
I'm starting to do socket programming so someone should confirm this.
I'm pretty sure the interface will drop the packet because the source and destination mac are the same... try using another PC and change the destination mac on each side to confirm this (virtual machines work as well)
I have also used a similar code to transfer Ethernet frames. This type of socket does not work locally. As #Goncalo suggested use a different PC or if you have two NICs on your PC you should use them. Here is the Code I used to receive Frames.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <sys/ioctl.h>
union ethframe
{
struct
{
struct ethhdr header;
unsigned char data[ETH_DATA_LEN];
} field;
unsigned char buffer[ETH_FRAME_LEN];
};
int main(int argc, char **argv) {
char *iface = "eth1";
unsigned char dest[ETH_ALEN]
= { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
unsigned short proto = 0x1234;
int recv_result,i;
char buff[ETH_FRAME_LEN];
unsigned short data_len;
int s;
if ((s = socket(AF_PACKET, SOCK_RAW, htons(proto))) < 0) {
printf("Error: could not open socket\n");
return -1;
}
struct ifreq buffer;
int ifindex;
memset(&buffer, 0x00, sizeof(buffer));
strncpy(buffer.ifr_name, iface, IFNAMSIZ);
if (ioctl(s, SIOCGIFINDEX, &buffer) < 0) {
printf("Error: could not get interface index\n");
close(s);
return -1;
}
ifindex = buffer.ifr_ifindex;
unsigned char source[ETH_ALEN];
if (ioctl(s, SIOCGIFHWADDR, &buffer) < 0) {
printf("Error: could not get interface address\n");
close(s);
return -1;
}
memcpy((void*)source, (void*)(buffer.ifr_hwaddr.sa_data),
ETH_ALEN);
struct sockaddr_ll saddrll;
memset((void*)&saddrll, 0, sizeof(saddrll));
saddrll.sll_family = PF_PACKET;
saddrll.sll_ifindex = ifindex;
saddrll.sll_halen = ETH_ALEN;
memcpy((void*)(saddrll.sll_addr), (void*)dest, ETH_ALEN);
socklen_t sll_len = (socklen_t)sizeof(saddrll);
if (recv_result = recvfrom(s, buff, ETH_FRAME_LEN, 0,
(struct sockaddr *)&saddrll, &sll_len) > 0)
printf("Success!\n");
else
printf("Error, could not send\n");
data_len=sizeof(buff);
printf("\tData:");
for (i=0; i<data_len; i++) printf("%c", buff[i]);
printf("\tDone: \n");
close(s);
return 0;
}