I have a code in contiki cooja. I have 2 sending nodes and 2 receiving nodes as you can see in the picture1. the broadcast senders and receivers are as follows.
#include "contiki.h"
#include "lib/random.h"
#include "sys/etimer.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "net/ip/uip-debug.h"
#include "simple-udp.h"
#include <stdio.h>
#include <string.h>
#define SEND_INTERVAL (20 * CLOCK_SECOND)
#define SEND_TIME (random_rand() % (SEND_INTERVAL))
static struct simple_udp_connection broadcast_connection;
/*---------------------------------------------------------------------------*/
PROCESS(broadcast_example_process, "UDP broadcast example process");
AUTOSTART_PROCESSES(&broadcast_example_process);
/*---------------------------------------------------------------------------*/
static void
receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
printf("Data received from ");
uip_debug_ipaddr_print(sender_addr);
printf(" on port %d from port %d with length %d: %s \n",
receiver_port, sender_port, datalen, data);
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(broadcast_example_process, ev, data)
{
static struct etimer periodic_timer;
static struct etimer send_timer;
uip_ipaddr_t addr;
char message[20];
sprintf(message," hello ");
PROCESS_BEGIN();
simple_udp_register(&broadcast_connection, 1234,
NULL, 1900,
receiver);
etimer_set(&periodic_timer, SEND_INTERVAL);
while(1) {
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&periodic_timer));
etimer_reset(&periodic_timer);
etimer_set(&send_timer, SEND_TIME);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&send_timer));
printf("Sending broadcast\n");
uip_create_linklocal_allnodes_mcast(&addr);
simple_udp_sendto(&broadcast_connection, message , strlen(message) , &addr);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
and receivers:
#include "contiki.h"
#include "lib/random.h"
#include "sys/ctimer.h"
#include "sys/etimer.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "simple-udp.h"
#include "net/ip/uip-debug.h"
#include <stdio.h>
#include <string.h>
#define UDP_PORT 1900
static struct simple_udp_connection broadcast_connection;
/*---------------------------------------------------------------------------*/
PROCESS(broadcast_example_process, "UDP broadcast example process");
AUTOSTART_PROCESSES(&broadcast_example_process);
/*---------------------------------------------------------------------------*/
static void
receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
printf("Data received from ");
uip_debug_ipaddr_print(sender_addr);
printf(" on port %d from port %d with length %d: %s \n",
receiver_port, sender_port, datalen, data);
/* this line should work,right?*/
simple_udp_sendto(&broadcast_connection, "hello",5, sender_addr);
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(broadcast_example_process, ev, data)
{
PROCESS_BEGIN();
simple_udp_register(&broadcast_connection, 1900,
NULL, 1234,
receiver);
while(1) {
PROCESS_WAIT_EVENT();
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
Now the problem is replying to the sender. I want each receiver node reply to the sender which has sent that message to it.
I don't know how to do that?
simple_udp_sendto() does not work.Can I use this function for this job? How should I use that?
You normally have an RDC function : packet_received. When an IT trigger, packet_received is called with the data in ptr. You just have to send again by reading the address of the sender.
Edit : you probably have a packet_received on the network layer, with same function. If you don't, you should implements one.
Related
How to allow request coming from specific IP address only in 0MQ request-reply pattern.
I don't want to receive request from any other IP address. I want to communicate only between two IP address first one is request maker and second one is reply maker.
request.c
#include <zmq.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
void *context = zmq_ctx_new();
void *requester = zmq_socket(context, ZMQ_REQ);
zmq_connect(requester, "tcp://127.0.0.1:5555");
char buffer[10];
printf ("Sending Hello\n");
zmq_send(requester, "Hello", 5, 0);
zmq_recv(requester, buffer, 10, 0);
printf("Received: %s\n", buffer);
zmq_close (requester);
zmq_ctx_destroy (context);
return 0;
}
reply.c
#include <zmq.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
int main(void) {
void *context = zmq_ctx_new();
void *responder = zmq_socket(context, ZMQ_REP);
int rc = zmq_bind(responder, "tcp://127.0.0.1:5555");
assert(rc == 0);
char buffer[10];
zmq_recv(responder, buffer, 10, 0);
printf("Recived: %s\n", buffer);
sleep(1);
zmq_send(responder, "World", 5, 0);
return 0;
}
From comments:
From stackoverflow.com/questions/20336954/0mq-get-message-ip it is
impossible. Do not use 0MQ and use other tool.
Using libevent 2.1.11, reading the input evbuffer is limited to 4096 bytes. Due to EVBUFFER_MAX_READ 4096 in buffer.c
Given this information, the next read callback should be called after the first read callback with the remaining data.
Running this program, when the read callback is first called, there is only 4096 bytes which is normal given the EVBUFFER_MAX_READ 4096. Then the callback is called again but the length is only 1 bytes.
Ouptut when sending data over 4096 bytes.
Received data is: 4096 bytes
received: {string of 4096 bytes}
Received data is: 1 bytes
received:
How to retrieve all the data sent to the server.
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
static const int PORT = 2048;
static void conn_readcb(struct bufferevent *bev, void *arg) {
struct evbuffer *buffer = bufferevent_get_input(bev);
const size_t len = evbuffer_get_length(buffer);
printf("Received data is: %ld bytes\n", len);
if(len < 1)
return;
char *data = malloc(len);
evbuffer_remove(buffer, data, len);
printf("received: %s\n", data);
free(data);
}
static void conn_writecb(struct bufferevent *bev, void *arg) {}
static void conn_eventcb(struct bufferevent *bev, short events, void *arg) {
bufferevent_free(bev);
}
static void signal_cb(evutil_socket_t sig, short events, void *evb) {
struct event_base *base = evb;
struct timeval delay = {2, 0};
event_base_loopexit(base, &delay);
}
static void listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
struct sockaddr *sa, int socklen, void *evb) {
struct event_base *base = evb;
struct bufferevent *bev;
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if(!bev) {
fprintf(stderr, "Error constructing bufferevent");
event_base_loopbreak(base);
return;
}
bufferevent_setcb(bev, conn_readcb, conn_writecb, conn_eventcb, NULL);
bufferevent_enable(bev, EV_WRITE|EV_READ);
}
int main(int argc, char* argv[]) {
struct event_base *base;
struct evconnlistener *listener;
struct event *signal_event;
struct sockaddr_in sin = {0};
base = event_base_new();
if(!base) {
fprintf(stderr, "Could not get new event base");
return -1;
}
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE, -1, (struct sockaddr*)&sin,
sizeof(sin));
if(!listener) {
fprintf(stderr, "Could not create a listener");
return -1;
}
signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
if(!signal_event || event_add(signal_event, NULL) < 0) {
fprintf(stderr, "Could not create or add a singal event");
return -1;
}
event_base_dispatch(base);
evconnlistener_free(listener);
event_free(signal_event);
event_base_free(base);
return 0;
}
I'm trying to implement my version of clustering in Contiki-ng. I took some inspiration from this code: Clustring example
What I did basically was that I created two connection:
static struct simple_udp_connection broad_conn;
static struct simple_udp_connection uni_conn;
However, though the code compiles and starts running in cooja, it stops showing me an error in the stack. I traced the error message and it looked like it came from this part of the code in stack-check.c:
if(p >= (uint8_t*)GET_STACK_ORIGIN()) {
/* This means the stack is screwed. */
return -1;
}
actual = stack_check_get_usage();
allowed = stack_check_get_reserved_size();
if(actual < 0 || allowed < 0) {
LOG_ERR("Check in inconsistent state: %" PRId32 " vs. %" PRId32 "\n", actual, allowed);
There is no memory overflow, and besides the callback functions, there is nothing in the code. The only thing that I think off is that it's because of the connections, but I just don't see why.
This is the code of nodes.c:
#include "contiki.h"
#include "simple-udp.h"
#include "sys/log.h"
#define LOG_MODULE "SensorNode"
#define LOG_LEVEL LOG_LEVEL_INFO
#define UDP_PORT_BROADCAST 1234
#define UDP_PORT_UNICAST 4321
static struct simple_udp_connection broadcast_conn;
static struct simple_udp_connection unicast_conn;
static uip_ipaddr_t CH_address;
PROCESS(nodes_process, "Nodes");
AUTOSTART_PROCESSES(&nodes_process);
/*---------------------------------Not Me------------------------------------------*/
static void
broadcast_receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
LOG_INFO("Received broadcast '%.*s' from ", datalen, (char *) data);
LOG_INFO_6ADDR(sender_addr);
LOG_INFO_("\n");
uip_ipaddr_copy(&CH_address, sender_addr);
}
/*---------------------------------------------------------------------------*/
static void
unicast_receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
LOG_INFO("Received reply '%.*s' from ", datalen, (char *) data);
LOG_INFO_6ADDR(sender_addr);
LOG_INFO_("\n");
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(nodes_process, ev, data)
{
static struct etimer periodic_timer;
static unsigned count;
static char str[32];
PROCESS_BEGIN();
/* Not me also */
/* Initialize UDP broadcast connection */
simple_udp_register(&broadcast_conn, UDP_PORT_BROADCAST, NULL,
UDP_PORT_BROADCAST, broadcast_receiver);
/* Initialize UDP unicast connection */
simple_udp_register(&unicast_conn, UDP_PORT_UNICAST, NULL,
UDP_PORT_UNICAST, unicast_receiver);
/* Send messages to the clusterhead every 60 seconds */
etimer_set(&periodic_timer, 60*CLOCK_SECOND);
while(1) {
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&periodic_timer));
LOG_INFO("Sending message %u to ", count);
LOG_INFO_6ADDR(&CH_address);
LOG_INFO_("\n");
snprintf(str, sizeof(str), "hello %d", count);
simple_udp_sendto(&unicast_conn, str, strlen(str), &CH_address);
count++;
etimer_reset(&periodic_timer);
}
PROCESS_END();
}
Any help in explaining this would be great.
Thank you.
I'm trying to build an application in contiki3.0 where several nodes broadcast their sensor data while writing it in a log and then every 3 min send the log to a sink and start a new log.
I also want the sink to acknowledge receiving the log.
I've been trying to do that for a month but I couldn't get the code to work properly, I would appreciate any help.
This is the code of the nodes:
#include "contiki-conf.h"
#include "dev/button-sensor.h"
#include "dev/light-sensor.h"
#include "dev/leds.h"
#include "net/linkaddr.h"
#include "contiki.h"
#include "lib/random.h"
#include "sys/ctimer.h"
#include "sys/etimer.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-ds6.h"
#include "event-post.h"
#include "simple-udp.h"
#include <limits.h>
#include <stdio.h>
#include <string.h>
#define UDP_PORT 1234
#define SEND_INTERVAL (20 * CLOCK_SECOND)
#define SEND_TIME (random_rand() % (SEND_INTERVAL))
/*---------------------------------------------------------------------------*/
static struct simple_udp_connection broadcast_connection;
static process_event_t event_data_ready;
/*---------------------------------------------------------------------------*/
PROCESS(sara, "broadcast");
PROCESS(broadcast_example_process, "BB");
AUTOSTART_PROCESSES(&sara, &broadcast_example_process);
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(sara, ev, data)
{
static struct etimer timer;
static struct event_struct es;
PROCESS_BEGIN();
es.s_val = SHRT_MAX-2;
es.i_val = INT_MAX-2;
es.l_val = LONG_MAX-2;
/* sizeof(long long) == sizeof(long) on sensinodes - see other examples*/
es.ll_val = LONG_MAX-2;
/* and some typedef-ed unsigned variables */
es.u8_val = UCHAR_MAX-2;
es.u16_val = USHRT_MAX-2;
es.u32_val = ULONG_MAX-2;
event_data_ready = process_alloc_event();
printf("Contiki allocated event ID %d.\r\n", event_data_ready);
etimer_set(&timer, CLOCK_CONF_SECOND * 2);
while(1){
printf("Sensor process: Wait for timer event...\r\n");
/* Wait on our timer */
PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER);
/* blip */
/* leds_toggle(LEDS_BLUE); */
/* Set the 'sensor' value before throwing the event */
printf("Sensor Process: Incrementing values...%d,%d,%d,%d,%d,%d, %d\r\n", es.s_val++, es.i_val++, es.l_val++, es.ll_val++, es.u8_val++, es.u16_val++,es.u32_val++);
/* Post our event.
* N.B. es is declared static.
* Try passing a volatile variable and observe the results... */
printf("Sensor Process: Generating 'Data Ready' event.\r\n");
process_post(&broadcast_example_process, event_data_ready, &es);
/* reset the timer so we can wait on it again */
etimer_reset(&timer);
}
SENSORS_ACTIVATE(button_sensor);
SENSORS_ACTIVATE(light_sensor);
static int counter=0;
printf("Light: \%u\n", light_sensor);
counter++;
if (counter == 4){
printf("Hello, world you have read the light 4 times \n");
}
PROCESS_END();
}
static void
receiver(struct simple_udp_connection *c,
const uip_ipaddr_t *sender_addr,
uint16_t sender_port,
const uip_ipaddr_t *receiver_addr,
uint16_t receiver_port,
const uint8_t *data,
uint16_t datalen)
{
printf("Data received on port %d from port %d with length %d\n",
receiver_port, sender_port, datalen);
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(broadcast_example_process, ev, data)
{
static struct etimer periodic_timer;
static struct etimer send_timer;
uip_ipaddr_t addr;
PROCESS_BEGIN();
simple_udp_register(&broadcast_connection, UDP_PORT,
NULL, UDP_PORT,
receiver);
etimer_set(&periodic_timer, SEND_INTERVAL);
while(1) {
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&periodic_timer));
etimer_reset(&periodic_timer);
etimer_set(&send_timer, SEND_TIME);
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&send_timer));
printf("Sending broadcast\n");
uip_create_linklocal_allnodes_mcast(&addr);
simple_udp_sendto(&broadcast_connection, data, sizeof(data), &addr);
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
and this is the sink code, which is a udp-sink code from Contiki examples:
#include "contiki.h"
#include "contiki-lib.h"
#include "contiki-net.h"
#include "net/ip/uip.h"
#include "net/rpl/rpl.h"
#include "net/linkaddr.h"
#include "net/netstack.h"
#include "dev/button-sensor.h"
#include "dev/serial-line.h"
#if CONTIKI_TARGET_Z1
#include "dev/uart0.h"
#else
#include "dev/uart1.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "collect-common.h"
#include "collect-view.h"
#define DEBUG DEBUG_PRINT
#include "net/ip/uip-debug.h"
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
#define UDP_CLIENT_PORT 8775
#define UDP_SERVER_PORT 5688
static struct uip_udp_conn *server_conn;
PROCESS(udp_server_process, "UDP server process");
AUTOSTART_PROCESSES(&udp_server_process,&collect_common_process);
/*---------------------------------------------------------------------------*/
void
collect_common_set_sink(void)
{
}
/*---------------------------------------------------------------------------*/
void
collect_common_net_print(void)
{
printf("I am sink!\n");
}
/*---------------------------------------------------------------------------*/
void
collect_common_send(void)
{
/* Server never sends */
}
/*---------------------------------------------------------------------------*/
void
collect_common_net_init(void)
{
#if CONTIKI_TARGET_Z1
uart0_set_input(serial_line_input_byte);
#else
uart1_set_input(serial_line_input_byte);
#endif
serial_line_init();
PRINTF("I am sink!\n");
}
/*---------------------------------------------------------------------------*/
static void
tcpip_handler(void)
{
uint8_t *appdata;
linkaddr_t sender;
uint8_t seqno;
uint8_t hops;
if(uip_newdata()) {
appdata = (uint8_t *)uip_appdata;
sender.u8[0] = UIP_IP_BUF->srcipaddr.u8[15];
sender.u8[1] = UIP_IP_BUF->srcipaddr.u8[14];
seqno = *appdata;
hops = uip_ds6_if.cur_hop_limit - UIP_IP_BUF->ttl + 1;
collect_common_recv(&sender, seqno, hops,
appdata + 2, uip_datalen() - 2);
}
}
/*---------------------------------------------------------------------------*/
static void
print_local_addresses(void)
{
int i;
uint8_t state;
PRINTF("Server IPv6 addresses: ");
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(state == ADDR_TENTATIVE || state == ADDR_PREFERRED) {
PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr);
PRINTF("\n");
/* hack to make address "final" */
if (state == ADDR_TENTATIVE) {
uip_ds6_if.addr_list[i].state = ADDR_PREFERRED;
}
}
}
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(udp_server_process, ev, data)
{
uip_ipaddr_t ipaddr;
struct uip_ds6_addr *root_if;
PROCESS_BEGIN();
PROCESS_PAUSE();
SENSORS_ACTIVATE(button_sensor);
PRINTF("UDP server started\n");
#if UIP_CONF_ROUTER
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 1);
/* uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); */
uip_ds6_addr_add(&ipaddr, 0, ADDR_MANUAL);
root_if = uip_ds6_addr_lookup(&ipaddr);
if(root_if != NULL) {
rpl_dag_t *dag;
dag = rpl_set_root(RPL_DEFAULT_INSTANCE,(uip_ip6addr_t *)&ipaddr);
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
rpl_set_prefix(dag, &ipaddr, 64);
PRINTF("created a new RPL dag\n");
} else {
PRINTF("failed to create a new RPL DAG\n");
}
#endif /* UIP_CONF_ROUTER */
print_local_addresses();
/* The data sink runs with a 100% duty cycle in order to ensure high
packet reception rates. */
NETSTACK_RDC.off(1);
server_conn = udp_new(NULL, UIP_HTONS(UDP_CLIENT_PORT), NULL);
udp_bind(server_conn, UIP_HTONS(UDP_SERVER_PORT));
PRINTF("Created a server connection with remote address ");
PRINT6ADDR(&server_conn->ripaddr);
PRINTF(" local/remote port %u/%u\n", UIP_HTONS(server_conn->lport),
UIP_HTONS(server_conn->rport));
while(1) {
PROCESS_YIELD();
if(ev == tcpip_event) {
tcpip_handler();
} else if (ev == sensors_event && data == &button_sensor) {
PRINTF("Initiaing global repair\n");
rpl_repair_root(RPL_DEFAULT_INSTANCE);
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
I am writing a small kernel module for measuring the time that a network packet takes to exit a node.
This module is a hook in the netfilter library.
For each packet it receives it calculates an hash, gets the tstamp from skbuff and the actual timestamp, and saves all this data in a linked list.
To pass this data to userspace I've created a proc device, and when the user reads from the device I send one of the entries of the linked list.
To make changes to the list (read and write) I have a spinlock. The problem is that sometimes when I read from the proc device while I am processing packets the system crash.
I think that the problem is in the function "dump_data_to_proc", more specifically when try to acquire the spinlock. I've made some tests and it only crashes(softlockup) when running in a tplink router. When I run the module in a "normal" pc(single core) it don't crash,
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/spinlock.h>
#include <net/ipv6.h>
#include <linux/proc_fs.h> /* Necessary because of proc fs */
#include <asm/uaccess.h> /* for copy_from_user */
#include "kmodule_measure_process_time.h"
#include "hash.c"
//DEBUG >=5 is very slow in the tplink
#define DEBUG 2
#define PROCFS_MAX_SIZE 64
#define PROCFS_NAME "measures"
#define MAXIMUM_SAMPLES 10000
static struct nf_hook_ops nfho;
unsigned int total_packets_processed= 0;
unsigned int total_packets_discarded=0;
int temp_counter=0;
struct values_list *HEAD;
spinlock_t list_lock ;
static int hello_proc(struct seq_file *m, void *v) {
seq_printf(m, " stats Mod initialized.\n");
return 0;
}
static int proc_open(struct inode *inode, struct file *file) {
return single_open(file, hello_proc, NULL);
}
ssize_t dump_data_to_proc(struct file *filp, char *buffer, size_t length, loff_t *offset){
int bytesRead = 0;
struct values_list *temp=NULL;
int bytesError=0;
char buff[PROCFS_MAX_SIZE];
spin_lock(&list_lock);
temp=HEAD;
if(temp!=NULL){
HEAD = temp->next;
}
spin_unlock(&list_lock);
if(temp!=NULL){
bytesRead = snprintf(buff, PROCFS_MAX_SIZE ,"%u|%llu|%llu\n", temp->hash,temp->arrival_timestap, temp->exit_timestap);
length = length - bytesRead+1;
kfree(temp);
temp_counter--;
}
bytesError= copy_to_user(buffer, buff, bytesRead);
if(bytesError!=0){
#if DEBUG >0
printk(KERN_INFO "Error: failed to copy to user");
#endif
}
return bytesRead;
}
static const struct file_operations proc_fops = {
.owner = THIS_MODULE,
.open = proc_open,
.read = dump_data_to_proc,
.llseek = seq_lseek,
.release = single_release,
};
static unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
uint32_t hash=0;
ktime_t now_timeval;
struct timespec now;
u64 timestamp_arrival_time=0;
u64 timestamp_now=0;
struct ipv6hdr * ipheader;
struct values_list *node;
int number_of_samples=0;
spin_lock(&list_lock);
number_of_samples=temp_counter;
spin_unlock(&list_lock);
if(number_of_samples > MAXIMUM_SAMPLES){
#if DEBUG > 5
printk(KERN_INFO "Discarded one sample because the list is full.\n");
#endif
total_packets_discarded++; // probably this should be inside a spinlock
return NF_ACCEPT;
}
//calculate arrival time and actual time in ns
timestamp_arrival_time = ktime_to_ns(skb->tstamp);
getnstimeofday(&now);
now_timeval = timespec_to_ktime(now);
timestamp_now = ktime_to_ns(now_timeval);
//get Ipv6 addresses
ipheader = (struct ipv6hdr *)skb_network_header(skb);
hash=simple_hash((char *)&ipheader->saddr,sizeof(struct in6_addr)*2,hash);
total_packets_processed++;
node = (struct values_list *) kmalloc(sizeof(struct values_list),GFP_ATOMIC);
if(!node){
#if DEBUG >0
printk(KERN_INFO "Error cannot malloc\n");
#endif
return NF_ACCEPT;
}
node->hash=hash;
node->arrival_timestap=timestamp_arrival_time;
node->exit_timestap=timestamp_now;
spin_lock(&list_lock);
node->next=HEAD;
HEAD=node;
temp_counter++;
spin_unlock(&list_lock);
return NF_ACCEPT;
}
static int __init init_main(void)
{
nfho.hook = hook_func;
nfho.hooknum = NF_INET_POST_ROUTING;
nfho.pf = PF_INET6;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho);
#if DEBUG >0
printk(KERN_INFO " kernel module: Successfully inserted protocol module into kernel.\n");
#endif
proc_create(PROCFS_NAME, 0, NULL, &proc_fops);
spin_lock_init(&list_lock);
//Some distros/devices disable timestamping of packets
net_enable_timestamp();
return 0;
}
static void __exit cleanup_main(void)
{
struct values_list *temp;
nf_unregister_hook(&nfho);
#if DEBUG >0
printk(KERN_INFO " kernel module: Successfully unloaded protocol module.\n");
printk(KERN_INFO "Number of packets processed:%d\n",total_packets_processed);
printk(KERN_INFO "Number of packets discarded:%d\n",total_packets_discarded);
#endif
remove_proc_entry(PROCFS_NAME, NULL);
while(HEAD!=NULL){
temp=HEAD;
HEAD= HEAD->next;
kfree(temp);
}
}
module_init(init_main);
module_exit(cleanup_main);
/* * Declaring code as GPL. */
MODULE_LICENSE("GPLv3");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
There are 2 problems with your code:
Use Linux kernel macro for your code. http://makelinux.com/ldd3/chp-11-sect-5 . Just add struct list_head as element to your struct values_list and use list_entry, list_add and other
Netfilter hools are run in softirq context, so you must use spin_lock_irqsave and spin_unlock_irqrestore. This is most likely reason why your system crashes with softlockup. Read carefully http://makelinux.com/ldd3/chp-5-sect-5