Intercepting winsock recvfrom function gives invalid address error - c

I'm trying to intercept winsock2 calls to troubleshoot a case where UDP packets between processes on the same host intermittently vanish. When they "vanish" they vanish for something like 20 seconds, which is enough to abort the process being run.
I managed to get the DLL injection to work, and 2 winsock calls are intercepted correctly (I hope) because I can do a simple print, but I need to be able to process the address information so I can track who sends what to whom...
Unfortunately, the upstream process I'm injecting into is apparently calling recvfrom (Yes, not the WSA... equivalent, this is old ported POSIX code) with NULL's for the "from" and "fromlen" parameters. If I don't fiddle with them at all the receive works. If I do the below, I get "Invalid Address" errors (Winsock error 10014).
An I doing something stupid here? Not that I would be surprised.... And yes, it would be easier to rebuild the target application with the desired debugging, but the build environment is down due to a data center migration, and I need ammunition to say "it's not the application."
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include "mhook.h"
#include <winsock2.h>
// typedefs for function pointers...
typedef int(WINAPI *rcvfrom_ptr) (
SOCKET s,
char *buf,
int len,
int flags,
struct sockaddr *from,
int *fromlen
);
typedef int(WINAPI *sendto_ptr) (
_In_ SOCKET s,
_In_ const char *buf,
_In_ int len,
_In_ int flags,
_In_ const struct sockaddr *to,
_In_ int tolen
);
// Function pointers for original calls.
rcvfrom_ptr orig_rcvfrom;
sendto_ptr orig_sendto;
//
// Helper functions.
//
typedef union sockaddrs {
struct sockaddr from;
struct sockaddr_in in_from;
// Need to verify Ipv6 support. may need to remigrate back to VS 2015
//struct sockaddr_in6 in6_from;
} tsockaddrs;
char *printaddr(char *buff,const int buffsz, const tsockaddrs *addr)
{
...
}
// Shim functions.
//
// Still working on getting them to actually work and do what I need.
// But I may as well develop the skeleton
int WINAPI Myrecvfrom(SOCKET s,
char *buf,
int len,
int flags,
struct sockaddr *from,
int *fromlen
)
{
int result;
struct sockaddr *all_froms;
char addrbuff[100] = "";
int newfromlen = sizeof(struct sockaddr);
all_froms = (struct sockaddr *)malloc(sizeof(struct sockaddr));
memset((void *)all_froms,0,sizeof(struct sockaddr));
printf("Receiving Packet!\n");
if (from == NULL) {
printf("\tFrom addr == null, using internal structures\n");
result = (orig_rcvfrom)(s, buf, len, flags, all_froms, &newfromlen);
} else {
printf("\tFrom addr != null, using passed structures\n");
result = (orig_rcvfrom)(s, buf, len, flags, from, fromlen);
memcpy_s((void*)&all_froms,sizeof(all_froms),(void *)from,*fromlen);
if (fromlen != NULL) {
newfromlen=*fromlen;
} else {
newfromlen=sizeof(struct sockaddr);
}
}
if (result >0) {printf("received %d bytes\n",result);}
else if (result == SOCKET_ERROR) {printf("Socket Error %d occurred!\n",WSAGetLastError());}
if (newfromlen >0) {
if (printaddr(addrbuff,sizeof(addrbuff),(tsockaddrs *)all_froms)!=NULL) {
printf("received %d bytes from on port %d from host %s\n",result,((tsockaddrs *)(all_froms))->in_from.sin_port,addrbuff);
}
if (from != NULL) {
memcpy_s((void*)from,sizeof(struct sockaddr),(void*)&all_froms,newfromlen);
}
else
{
}
if (fromlen != NULL) *fromlen=newfromlen;
}
else {
printf("received %d bytes from unknown port and host\n",result);
}
if (all_froms != NULL) {free(all_froms);}
return result;
}
int WINAPI Mysendto(SOCKET s,
const char *buf,
int len,
int flags,
const struct sockaddr *to,
int tolen
)
{
printf("Sending packet!\n");
return orig_sendto(s, buf, len, flags, to, tolen);
}
BOOL AttachHooks(void)
{
BOOL sethooks;
orig_rcvfrom = (rcvfrom_ptr)GetProcAddress(GetModuleHandle(L"ws2_32"), "recvfrom");
sethooks = Mhook_SetHook((PVOID*)&orig_rcvfrom, Myrecvfrom);
if (sethooks) {
orig_sendto = (sendto_ptr)GetProcAddress(GetModuleHandle(L"ws2_32"), "sendto");
sethooks &= Mhook_SetHook((PVOID*)&orig_sendto, Mysendto);
}
return sethooks;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
printf_s("This is an attached DLL!\n");
AttachHooks();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

The cause of the issue is that the ACTUAL size of the reply was more than the size of "struct sockaddr." It in fact was a SOCKADDR_IN6 structure coming back. Used an arbitrary buffer of 200 bytes instead of the 28-byte sockaddr structure and I was able to pull in the data.
In the process, I wound up converting to "peeking" the received data instead of processing it after it was pulled in. When the PC with the source code finishes installing updates, I'll post it.
Working from home is fairly isolating, and there isn't anyone who lives in winsock in my office anyway. It was really helpful to "chat" in the comments.

Related

libuv slow in establishing a multiple connections?

I am trying to evaluate the performance of libuv because of the promise that it can manage 100,000 of TCP sockets and can generate 10,000 of new TCP sessions/second.
Created the following code snippet based on a gist to validate the performance of libuv. However, when it runs against a server, it's surprisingly slow according to wireshark pcap capture
TCP handshakes were done one after another, I was expecting TCP SYNs to be sent in parallel
The TCP data was sent after all the sessions were established. I had expected the TCP data to be sent as soon as the TCP handshake is complete.
This test was run on Ubuntu 14.04 (64bit core i7 cpu).
Not sure if there is problem with libuv or with this code snippet.
I know this has some memory leaks, but it doesn't matter since I am only doing evaluation.
#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
//based on https://gist.githubusercontent.com/snatchev/5255976/
//raw/8392c42d719bb775053036e32b21affdf932c1b7/libuv-tcp-client.c
static void on_close(uv_handle_t* handle);
static void on_connect(uv_connect_t* req, int status);
static void on_write(uv_write_t* req, int status);
static uv_loop_t *loop;
static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) {
return uv_buf_init(malloc(size), size);
}
void on_close(uv_handle_t* handle)
{
printf("closed.");
}
void on_write(uv_write_t* req, int status)
{
if (status) {
uv_err_t err = uv_last_error(loop);
fprintf(stderr, "uv_write error: %s\n", uv_strerror(err));
return;
}
printf("wrote.\n");
free(req);
//uv_close((uv_handle_t*)req->handle, on_close);
}
void on_read(uv_stream_t* tcp, ssize_t nread, uv_buf_t buf)
{
printf("on_read. %p\n",tcp);
if(nread >= 0) {
//printf("read: %s\n", tcp->data);
printf("read: %s\n", buf.base);
}
else {
//we got an EOF
uv_close((uv_handle_t*)tcp, on_close);
}
//cargo-culted
free(buf.base);
}
void write2(uv_stream_t* stream, char *data, int len2) {
uv_buf_t buffer[] = {
{.base = data, .len = len2}
};
uv_write_t *req = malloc(sizeof(uv_write_t));
uv_write(req, stream, buffer, 1, on_write);
}
void on_connect(uv_connect_t* connection, int status)
{
if (status < 0) {
printf("failed to connect\n"); return;
}
printf("connected. %p %d\n",connection, status);
uv_stream_t* stream = connection->handle;
free(connection);
write2(stream, "echo world!", 12);
uv_read_start(stream, alloc_cb, on_read);
}
void startConn(char *host, int port) {
uv_tcp_t *pSock = malloc(sizeof(uv_tcp_t));
uv_tcp_init(loop, pSock);
uv_tcp_keepalive(pSock, 1, 60);
struct sockaddr_in dest = uv_ip4_addr(host, port);
uv_connect_t *pConn = malloc(sizeof(uv_connect_t));
printf("allocated %p\n", pConn);
uv_tcp_connect(pConn, pSock, dest, on_connect);
}
int main(int argc, char **argv) {
loop = uv_default_loop();
int i;
for (i=0; i<10; i++)
startConn("0.0.0.0", 1234);
uv_run(loop, UV_RUN_DEFAULT);
}
This example is compiled against libuv 0.1.
After it's adapted to compile and run against libuv1.x, it works as expected. Here is the gist.
There is considerable difference between libuv 0.1 and libuv 1.0. Hope this version could be helpful to those who are looking for a working example of libuv.c. By the way, there are many good examples in libuv repo in github, check the "test" subdirectory.

parameter values of usrsctp data received callback became nonsense

I am recently working on a project based on usrsctp.
When creating a new SCTP socket, one can specify a callback function which will be called when new data is available as shown in the code below.
create a new SCTP socket:
struct socket *s = usrsctp_socket(AF_CONN, SOCK_STREAM, IPPROTO_SCTP,
sctp_data_received_cb, NULL, 0, sctp);
callback function:
static int
sctp_data_received_cb(struct socket *sock, union sctp_sockstore addr, void *data,
size_t len, struct sctp_rcvinfo recv_info, int flags, void *user_data)
{
struct sctp_transport *sctp = (struct sctp_transport *)user_data;
if (sctp == NULL || len == 0)
return -1;
fprintf(stdout, "Data of length %u received on stream %u with SSN %u, TSN %u, PPID %u\n",
(uint32_t)len,
recv_info.rcv_sid,
recv_info.rcv_ssn,
recv_info.rcv_tsn,
ntohl(recv_info.rcv_ppid));
if (flags & MSG_NOTIFICATION)
handle_notification_message(sctp, (union sctp_notification *)data, len);
else
handle_rtcdc_message(sctp, data, len, ntohl(recv_info.rcv_ppid), recv_info.rcv_sid);
free(data);
return 0;
}
This callback function is called properly, but its parameter values are just nonsense. Output of the code above is like
Data of length 675381504 received on stream 31504 with SSN 34835, TSN 32651, PPID 8470824
which should have been like
Data of length 18 received on stream 0 with SSN 0, TSN 4117987333, PPID 50
I read the source code of usrsctp and found where the callback is called:
if (control->spec_flags & M_NOTIFICATION) {
flags |= MSG_NOTIFICATION;
}
inp->recv_callback(so, addr, buffer, control->length, rcv, flags, inp->ulp_info);
SCTP_TCB_LOCK(stcb);
Change it to the code below and recompile the library
if (control->spec_flags & M_NOTIFICATION) {
flags |= MSG_NOTIFICATION;
}
fprintf(stdout, "[LIB] Data of length %u received on stream %u with SSN %u, TSN %u, PPID %u\n",
control->length,
rcv.rcv_sid,
rcv.rcv_ssn,
rcv.rcv_tsn,
ntohl(rcv.rcv_ppid));
inp->recv_callback(so, addr, buffer, control->length, rcv, flags, inp->ulp_info);
SCTP_TCB_LOCK(stcb);
I can get expected output:
[LIB] Data of length 18 received on stream 0 with SSN 0, TSN 4117987333, PPID 50
Why did parameter values become nonsense in the callback function?
I have found a similar question here, but couldn't understand its answer. I am quite sure it is the same issue.
[update1]
the prototype of usrsctp_socket in usrsctp.h:
struct socket *
usrsctp_socket(int domain, int type, int protocol,
int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data,
size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info),
int (*send_cb)(struct socket *sock, uint32_t sb_free),
uint32_t sb_threshold,
void *ulp_info);
[update2]
I am quite sure that no extra tricks as suggested in the old similar thread are needed, since I see no weird castings in the official examples and they just work well.
for example in echo_server.c:
static int
receive_cb(struct socket *sock, union sctp_sockstore addr, void *data,
size_t datalen, struct sctp_rcvinfo rcv, int flags, void *ulp_info)
{
char namebuf[INET6_ADDRSTRLEN];
const char *name;
uint16_t port;
if (data) {
if (flags & MSG_NOTIFICATION) {
printf("Notification of length %d received.\n", (int)datalen);
} else {
switch (addr.sa.sa_family) {
#ifdef INET
case AF_INET:
name = inet_ntop(AF_INET, &addr.sin.sin_addr, namebuf, INET_ADDRSTRLEN);
port = ntohs(addr.sin.sin_port);
break;
#endif
#ifdef INET6
case AF_INET6:
name = inet_ntop(AF_INET6, &addr.sin6.sin6_addr, namebuf, INET6_ADDRSTRLEN),
port = ntohs(addr.sin6.sin6_port);
break;
#endif
case AF_CONN:
#ifdef _WIN32
_snprintf(namebuf, INET6_ADDRSTRLEN, "%p", addr.sconn.sconn_addr);
#else
snprintf(namebuf, INET6_ADDRSTRLEN, "%p", addr.sconn.sconn_addr);
#endif
name = namebuf;
port = ntohs(addr.sconn.sconn_port);
break;
default:
name = NULL;
port = 0;
break;
}
printf("Msg of length %d received from %s:%u on stream %d with SSN %u and TSN %u, PPID %d, context %u.\n",
(int)datalen,
name,
port,
rcv.rcv_sid,
rcv.rcv_ssn,
rcv.rcv_tsn,
ntohl(rcv.rcv_ppid),
rcv.rcv_context);
if (flags & MSG_EOR) {
struct sctp_sndinfo snd_info;
snd_info.snd_sid = rcv.rcv_sid;
snd_info.snd_flags = 0;
if (rcv.rcv_flags & SCTP_UNORDERED) {
snd_info.snd_flags |= SCTP_UNORDERED;
}
snd_info.snd_ppid = rcv.rcv_ppid;
snd_info.snd_context = 0;
snd_info.snd_assoc_id = rcv.rcv_assoc_id;
if (usrsctp_sendv(sock, data, datalen, NULL, 0, &snd_info, sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) {
perror("sctp_sendv");
}
}
}
free(data);
}
return (1);
}
OK, I figured out why myself. It is silly but I will post the solution here in case someone would need it.
The defination of union sctp_sockstore (type of the second parameter of the callback function) is shown below.
union sctp_sockstore {
#if defined(INET)
struct sockaddr_in sin;
#endif
#if defined(INET6)
struct sockaddr_in6 sin6;
#endif
struct sockaddr_conn sconn;
struct sockaddr sa;
};
INET and INET6 are defined in usrsctp library but not in my code, since I handcrafted the Makefile and omitted them. The parameters were shifted (like 16bit) because of different sizes of the unions and so became nonsense.
Defining INET and INET6 (especially INET6) when you compile your own code solves the problem.

C code to get the interface name for the IP address in Linux

How can I get the interface name for the IP address in linux from C code ?
e.g. I'd like to get the interface name ( like etho , eth1 , l0 ) assigned for the IP address 192.168.0.1
Using /proc/net/arp you can match it. Here is a command line tool example.
usage: getdevicebyip 192.168.0.1
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv){
if (argc < 2) return 1;
FILE *fp = fopen("/proc/net/arp", "r");
char ip[99], hw[99], flags[99], mac[99], mask[99], dev[99], dummy[99];
fgets(dummy, 99, fp); //header line
while (fscanf(fp, "%s %s %s %s %s %s\n", ip, hw, flags, mac, mask, dev) != EOF)
if (!strcmp(argv[1],ip))
printf("%s\n",dev);
return 0;
}
You can use getifaddrs. See man 3 getifaddrs for usage information. This will only work on a Unix-like systems.
netlink is a way to do this on Linux. I think it might even be a proper way to do it on Linux (even though it isn't portable).
The strategy is:
Get a list of addresses on interfaces from the kernel by sending a netlink message.
Find the address you want (I have hard coded the one I want as address_dq) and record its interface (a number at this stage)
Get a list of interfaces by sending another netlink message,
Find the number of the interface matching the number you recorded in step (2).
Get the name of the interface.
The code below is not pretty, but I'm sure you could do a better job of it. I have been a especially sloppy by not checking for a multipart message (checking for the NLM_F_MULTI flag and for a message type of NLMSG_DONE is the way to do it). Instead I have just assumed the response to the first message is multipart -- it is on my machine -- and chewed up the NLMSG_DONE message which follows.
Code...
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, void ** argv) {
// This is the address we want the interface name for,
// expressed in dotted-quad format
char * address_dq = "127.0.0.1";
// Convert it to decimal format
unsigned int address;
inet_pton(AF_INET, address_dq, &address);
char buf[16384];
// Our first message will be a header followed by an address payload
struct {
struct nlmsghdr nlhdr;
struct ifaddrmsg addrmsg;
} msg;
// Our second message will be a header followed by a link payload
struct {
struct nlmsghdr nlhdr;
struct ifinfomsg infomsg;
} msg2;
struct nlmsghdr *retmsg;
// Set up the netlink socket
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
// Fill in the message
// NLM_F_REQUEST means we are asking the kernel for data
// NLM_F_ROOT means provide all the addresses
// RTM_GETADDR means we want address information
// AF_INET means limit the response to ipv4 addresses
memset(&msg, 0, sizeof(msg));
msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg.nlhdr.nlmsg_type = RTM_GETADDR;
msg.addrmsg.ifa_family = AF_INET;
// As above, but RTM_GETLINK means we want link information
memset(&msg2, 0, sizeof(msg2));
msg2.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
msg2.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg2.nlhdr.nlmsg_type = RTM_GETLINK;
msg2.infomsg.ifi_family = AF_UNSPEC;
// Send the first netlink message
send(sock, &msg, msg.nlhdr.nlmsg_len, 0);
int len;
// Get the netlink reply
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
// Loop through the reply messages (one for each address)
// Each message has a ifaddrmsg structure in it, which
// contains the prefix length as a member. The ifaddrmsg
// structure is followed by one or more rtattr structures,
// some of which (should) contain raw addresses.
while NLMSG_OK(retmsg, len) {
struct ifaddrmsg *retaddr;
retaddr = (struct ifaddrmsg *)NLMSG_DATA(retmsg);
int iface_idx = retaddr->ifa_index;
struct rtattr *retrta;
retrta = (struct rtattr *)IFA_RTA(retaddr);
int attlen;
attlen = IFA_PAYLOAD(retmsg);
char pradd[128];
// Loop through the routing information to look for the
// raw address.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFA_ADDRESS) {
// Found one -- is it the one we want?
unsigned int * tmp = RTA_DATA(retrta);
if (address == *tmp) {
// Yes!
inet_ntop(AF_INET, RTA_DATA(retrta), pradd, sizeof(pradd));
printf("Address %s ", pradd);
// Now we need to get the interface information
// First eat up the "DONE" message waiting for us
len = recv(sock, buf, sizeof(buf), 0);
// Send the second netlink message and get the reply
send(sock, &msg2, msg2.nlhdr.nlmsg_len, 0);
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
while NLMSG_OK(retmsg, len) {
struct ifinfomsg *retinfo;
retinfo = NLMSG_DATA(retmsg);
if (retinfo->ifi_index == iface_idx) {
retrta = IFLA_RTA(retinfo);
attlen = IFLA_PAYLOAD(retmsg);
char prname[128];
// Loop through the routing information
// to look for the interface name.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFLA_IFNAME) {
strcpy(prname, RTA_DATA(retrta));
printf("on %s\n", prname);
exit(EXIT_SUCCESS);
}
retrta = RTA_NEXT(retrta, attlen);
}
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
}
retrta = RTA_NEXT(retrta, attlen);
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
When run as above, returns Address 127.0.0.1 on lo.
Using "192.168.1.x" instead of "127.0.0.1" it instead returns Address 192.168.1.x on eth0.

pf_ring and libpcap if_index not returning

I have recently been getting involved with having to utilize pf_ring / libpcap. I have never developed with libpcap or pf_ring so please forgive what might appear to be a silly question, as network programming is semi new to me... In broad terms what I am trying to do is access the if_index for packets received. I currently have a simple raw packet sniffer created with "C" utilizing pf_ring as shown below:
#include <pcap.h>
#include <pfring.h>
#include <string.h>
#include <stdlib.h>
#define MAXBYTES2CAPTURE 2048
void processRingPacket(const struct pfring_pkthdr* pkthdr, const u_char* packet, const u_char *arg)
{
int i=0, *counter = (int*)arg;
printf("Packet Count: %d ", ++(*counter));
printf("Received Packet Size: %d ", pkthdr->len);
printf("ifIndex: %d ", pkthdr->extended_hdr.if_index);
printf("Payload:\n");
for(i=0; i < pkthdr->len; i++)
{
if(isprint(packet[i]))
{
printf("%c ", packet[i]);
}
else
{
printf(". ");
}
if((i % 16 == 0) && (i != 0) || (i == pkthdr->len-1))
{
printf("\n");
}
}
return;
}
int main()
{
int count = 0;
char *device = "eth0";
printf("Opening Device: %s\n", device);
pfring* ring = pfring_open(device, MAXBYTES2CAPTURE, 0);
pfring_enable_ring(ring);
pfring_loop(ring, processRingPacket, (u_char*)&count, 1);
return 0;
}
Looking at the pfring_pkthdr struct within the pf_ring API, I should be able to do the following:
pkthdr->extended_hdr.if_index
However, when I try to print out the index it just prints 0. I am guessing the if_index is not actually being set, as when I actually call the pf_ring function to get the device if index, I actually receive a value for the specified device:
pfring_get_device_ifindex (pfring *ring, char *device_name, int *if_index)
The problem is I am trying to view the if_index for each packet, hence within the call back function "processRingPacket" there is no way to generically specify the device. I say generically here because there will be two interfaces capturing packets. Any ideas on what my rookie mistake might be?
I think you need to pass in PF_RING_LONG_HEADER as a flag to pfring_open(). So it becomes, pfring_open(device, MAXBYTES2CAPTURE, PF_RING_LONG_HEADER);
If pkthdr->extended_hdr.if_index isn't set in the callback function, you can always pass it in to your callback function in the arg argument.
struct Dev {
int count;
int if_index;
};
...
char *device = "eth0";
struct Dev dev;
dev.count = 0;
dev.if_index = if_nametoindex(device); //from #include <net/in.h>
printf("Opening Device: %s\n", device);
pfring* ring = pfring_open(device, MAXBYTES2CAPTURE, 0);
pfring_enable_ring(ring);
pfring_loop(ring, processRingPacket, (u_char*)&dev, 1);
And recover that in the callback function:
void processRingPacket(const struct pfring_pkthdr* pkthdr, const u_char* packet, const u_char *arg)
{
struct Dev *dev = (struct Dev*)arg;
int i=0, *counter = (int*)&dev->count;
//and use dev->if_index; whenever you need to.

copy_to_user not working - where I am on mistake?

I am trying to get some message from kernel space to userspace, when a condition fails!
Here's my kernel code:
#define MESSAGTOUSER 1
int ret_val;
struct siginfo sinfo;
pid_t id;
struct task_struct *task;
unsigned char msgBuffer[20];
unsigned char buf1[20]= "HI";
static int major_no;
static struct class *safe_class;
static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static int device_open(struct inode *inode, struct file *file);
static int device_write(struct file *file, const char *gdata, size_t len, loff_t *off);
static int device_read(struct file *file, char *buf, size_t len, loff_t *off);
static int device_release(struct inode *inode, struct file *file);
int failureDetection (char* faultMsg) {
strcpy (msgBuffer, faultMsg);
printk(KERN_ALERT"\nMessage from HBM %s\n", msgBuffer);
printk(KERN_ALERT".......... RETURN VALUE ...... : %d", ret_val);
int Reg_Dev(void);
memset (&sinfo, 0, sizeof(struct siginfo));
sinfo.si_signo = SIGUSR1;
sinfo.si_code = SI_USER;
if (id == 0) {
printk("\ncan't find User PID: %d\n", id);
}else {
//task = pid_task(find_vpid(pid), PIDTYPE_PID);
task = find_task_by_vpid(id);
send_sig_info(SIGUSR1, &sinfo, task);
}
return 0;
}
static int device_open(struct inode *inode, struct file *file){
/*sucess*/
return 0;
}
void strPrint(void) {
printk("value of msgBuffer: %s", msgBuffer);
}
static int device_write(struct file *file, const char *gdata, size_t len, loff_t *off){
get_user (id,(int *)gdata);
if(id <0)
printk(KERN_ALERT"Cann't find PID from userspace its : %i", id);
else
printk(KERN_ALERT"Successfully received the PID of userspace %i", id);
return len;
}
static int
device_read(struct file *file, char *buf, size_t len, loff_t *off){
/*success*/
return 0;
}
static int device_release(struct inode *inode, struct file *file){
/*success*/
return 0;
}
static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
switch (cmd) {
case MESSAGTOUSER:
ret_val = copy_to_user((char *)arg, msgBuffer, sizeof(arg));
printk("Msg of Kernel %s", msgBuffer);
break;
default:
break;
}
return 0;
}
static struct file_operations fops = {
.open = device_open,
.write = device_write,
.read = device_read,
.release = device_release,
.unlocked_ioctl = device_ioctl
};
int Reg_Dev(void) {
major_no = register_chrdev(0, "safe_dev", &fops);
safe_class = class_create(THIS_MODULE, "safe_dev");
device_create(safe_class,NULL, MKDEV(major_no, 0), "safe_dev");
printk("\n Device Registered and Created \n");
return 0;
}
void UnReg_dev (void) {
printk("\nUser PID : %d\n", id);
unregister_chrdev(major_no, "safe_dev");
device_destroy(safe_class, MKDEV(major_no,0));
class_unregister(safe_class);
class_destroy(safe_class);
printk("\n Device Un-Registered and Destroyed \n");
}
extern int Reg_Dev(void);
for he userspace i have this code:
#define PORT 9930
#define G_IP "192.168.10.71"
#define BUFLEN 512
#define MESSAGTOUSER 0
unsigned char *str[20];
char b1[BUFLEN], b2[BUFLEN];
struct sockaddr_in me,client;
int s, i, n=sizeof(me);
int fd;
void error_handler(char *s) {
perror(s);
exit(1);
}
void signal_handler (int signum) {
if(signum == SIGUSR1)
{
printf("\n%s\n",str);
if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
error_handler("\nERROR: in Socket\n");
memset((char *) &me, 0, sizeof(me));
me.sin_family = AF_INET;
me.sin_port = PORT;
if (inet_aton(G_IP, &me.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
printf("Message from Kernel : %s", &str);
//strcpy (str, newStr);
int cntr =0; sprintf(b2, "\nFailure Message: %s\n",str);
printf("\nsending Fault to PMN Group : Tick - %d\n", cntr++);
if(sendto(s, str, sizeof(str),0,(struct sockaddr *) &me,n)==-1)
error_handler("\nERROR: in sendto()\n");
close (s);
// counter ++;
// sendAndReceiveOverUDP();
return;
}
}
int main() {
pid_t u_id;
u_id = getpid();
int i = 1;
fd = open("/dev/safe_dev",O_RDWR);
write(fd, &u_id, 4);
ioctl (fd, MESSAGTOUSER, &str);
printf("\n PID sent to device successfully: %d \n", u_id);
close(fd);
signal(SIGUSR1, signal_handler);
printf("\nMy PID is: %d\n",u_id);
//printf("Subnet 1 working fine.. Tick - %d", tv.tv_sec);
while (1)
sleep(1);
return 0;
}
Now what I am expecting to receive on Userspace:
Message from Kernel: A<->B
Sending Fault o PMN Group : tick - 0
Message from Kernel: B<->B
Sending Fault o PMN Group : tick - 1
....
...
but what is the output:
Message from Kernel:
Sending Fault o PMN Group : tick - 0
Message from Kernel:
Sending Fault o PMN Group : tick - 1
....
...
It seems that copy_to_user is not working, while in simple program just copying a string from kernel to user is working fine, but while i am using in this scenario then its not working, its compiling without any warning,
Some other Details:
failureDetection() is getting a string like A<->B mentioned in output from rest of the programs..
the same message from failureDetection is printing on kernel level but not transferring at the user level.
I have also tried to create an own string in this and tried to transfer that, but it is also not working! suppose msgBuffer = HI, then I should receive HI on to the userspace. but its not happening! can anyone please please make me correct whats wrong with this code? how can i get updates onto the userspace!!??
Sindhu..
The copy_to_user() only happens in response to the ioctl(), which only happens once, very early on in your code. Presumably at that point the kernel buffer msgBuffer is empty, because the failureDetection() function has not yet run at that point. It doesn't matter if failureDetection() runs later and sets msgBuffer then, because your userspace program never calls the ioctl() again so it doesn't see the new contents of msgBuffer.
You also have a bug in your copy_to_user() call - instead of sizeof(args) (which is a constant 4) you should probably use sizeof msgBuffer.
#caf: Thank you so much..
void signal_handler (int signum) {
if(signum == SIGUSR1)
{
fd = open ("/dev/safe_dev",O_RDWR);
ioctl (fd, MESSAGTOUSER, &str);
close (fd);
if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
error_handler("\nERROR: in Socket\n");
memset((char *) &me, 0, sizeof(me));
me.sin_family = AF_INET;
me.sin_port = PORT;
if (inet_aton(G_IP, &me.sin_addr)==0)
{
fprintf(stderr, "inet_aton() failed\n");
exit(1);
}
printf("Failure Detected on Eth Cards as : %s are non reachable.", str);
printf("\nsending Fault to PMN Group : Tick - %d\n", cntr++);
sprintf(b2, "\nFailure Message: %s\n",str);
if(sendto(s, str, sizeof(str),0,(struct sockaddr *) &me,n)==-1)
error_handler("\nERROR: in sendto()\n");
close (s);
return;
}
}
I was just making a stupid mistake.. hehehe.. i was not adding it in between file open and close block.. your suggestion resolved my issue...
Thank you so much for your response..
Rahee..

Resources