Related
I have aquestion about linux kernel networking.
Assume that I need to send data from kernel to client in user space. In user space I open socket in non blocking mode via issuing connect() function. Then in kernel mode I send data to connected client. Only once. The dmesg command shows me this. But in user mode it starts receiving the data eternally! Once packet received the next packet is the same one! The packet is split into 2 parts. First part is responsible for full message size. What am I doing wrong?
Here is code snippets for driver code:
Data types:
`
struct orlan_tcp_conn_handler_data
{
struct socket *socket;
};
struct orlan_tcp_service
{
volatile int running;
volatile int running_thread;
struct socket *listen_socket;
struct task_struct *thread;
struct orlan_tcp_conn_handler_data *conn_list;
};
`
Initialization:
static int tcp_server_accept(void *data)
{
struct orlan_tcp_service *orlan_data = (struct orlan_tcp_service*)data;
int err = 0;
struct socket *socket;
struct socket *accept_socket = NULL;
struct inet_connection_sock *isock;
struct orlan_tcp_conn_handler_data *conn_handler;
int error_rep_count = 0;
DECLARE_WAITQUEUE(accept_wait, current);
#ifdef MODULE_USE_TRACE
printk(KERN_INFO MODULE_NAME ": start of Accept Thread\n");
#endif
socket = orlan_data->listen_socket;
while (1)
{
accept_socket = sock_alloc();
if (!accept_socket)
{
printk(KERN_ERR MODULE_NAME ": error allocating accept socket!\n");
if (++error_rep_count == 5)
{
orlan_data->running_thread = 1;
return -(ENOMEM);
}
continue;
}
accept_socket->type = socket->type;
accept_socket->ops = socket->ops;
isock = inet_csk(socket->sk);
#ifdef MODULE_USE_TRACE
printk(KERN_INFO MODULE_NAME ": Accept Thread: before wait queue\n");
#endif
add_wait_queue(&socket->sk->sk_wq->wait, &accept_wait);
while (reqsk_queue_empty(&isock->icsk_accept_queue))
{
__set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ);
if (kthread_should_stop() || signal_pending(current))
{
__set_current_state(TASK_RUNNING);
remove_wait_queue(&socket->sk->sk_wq->wait, &accept_wait);
sock_release(accept_socket);
orlan_data->running = 1;
orlan_data->running_thread = 1;
return 0;
}
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(&socket->sk->sk_wq->wait, &accept_wait);
#ifdef MODULE_USE_TRACE
printk(KERN_INFO MODULE_NAME ": Accept Thread before accept\n");
#endif
orlan_data->running = 1;
orlan_data->running_thread = 1;
err = socket->ops->accept(socket, accept_socket, /*O_NONBLOCK*/0, true);
if (err < 0)
{
printk(KERN_ERR MODULE_NAME ": error accepting socket connection!\n");
sock_release(accept_socket);
if (++error_rep_count == 5)
return err;
continue;
}
#ifdef MODULE_USE_TRACE
printk(KERN_INFO MODULE_NAME ": Accept Thread: after accept\n");
#endif
if (orlan_data->conn_list)
{
sock_release(accept_socket);
error_rep_count = 0;
if (kthread_should_stop() || signal_pending(current))
break;
continue;
}
conn_handler = kmalloc(sizeof(struct orlan_tcp_conn_handler_data), GFP_KERNEL);
if (!conn_handler)
{
printk(KERN_ERR MODULE_NAME ": error allocating %u bytes!\n", (unsigned int)sizeof(struct orlan_tcp_conn_handler_data));
sock_release(accept_socket);
if (++error_rep_count == 5)
return -(ENOMEM);
continue;
}
//memset(conn_handler, 0, sizeof(struct orlan_tcp_conn_handler_data));
conn_handler->socket = accept_socket;
orlan_data->conn_list = conn_handler;
#ifdef MODULE_USE_TRACE
printk(KERN_INFO MODULE_NAME ": socket connected\n");
#endif
error_rep_count = 0;
if (kthread_should_stop() || signal_pending(current))
break;
}
#ifdef MODULE_USE_TRACE
printk(KERN_INFO MODULE_NAME ": end of Accept Thread\n");
#endif
return 0;
}
static int ktcp_start_listen(void *data)
{
struct orlan_tcp_service *orlan_data = (struct orlan_tcp_service*)data;
int err;
struct socket *conn_socket;
struct sockaddr_in server;
struct orlan_tcp_conn_handler_data *list;
#ifdef MODULE_USE_TRACE
printk(KERN_INFO MODULE_NAME ": start of Main Thread\n");
#endif
allow_signal(SIGKILL | SIGTERM);
err = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &orlan_data->listen_socket);
if (err < 0)
{
orlan_data->listen_socket = NULL;
printk(KERN_ERR MODULE_NAME ": error creating main socket!\n");
orlan_data->running_thread = 1;
return err;
}
conn_socket = orlan_data->listen_socket;
orlan_data->listen_socket->sk->sk_reuse = 1;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_family = AF_INET;
server.sin_port = htons(TCP_PORT);
err = conn_socket->ops->bind(conn_socket, (struct sockaddr*)&server, sizeof(server));
if (err < 0)
{
sock_release(orlan_data->listen_socket);
orlan_data->listen_socket = NULL;
printk(KERN_ERR MODULE_NAME ": error binding main socket!\n");
orlan_data->running_thread = 1;
return err;
}
err = conn_socket->ops->listen(conn_socket, /*sock_net(conn_socket->sk)->core.sysctl_somaxconn*/2);
if (err < 0)
{
sock_release(orlan_data->listen_socket);
orlan_data->listen_socket = NULL;
printk(KERN_ERR MODULE_NAME ": error listening on main socket!\n");
orlan_data->running_thread = 1;
return err;
}
tcp_server_accept(orlan_data);
list = orlan_data->conn_list;
while (list)
{
struct orlan_tcp_conn_handler_data *p = list;
if (p->socket)
sock_release(p->socket);
list = NULL;
kfree(p);
}
orlan_data->conn_list = NULL;
#ifdef MODULE_USE_TRACE
printk(KERN_INFO MODULE_NAME ": end of Main Thread\n");
#endif
sock_release(orlan_data->listen_socket);
orlan_data->listen_socket = NULL;
orlan_data->running = 0;
orlan_data->running_thread = 0;
return 0;
}
int ktcp_start(void)
{
memset(&orlan_tcp_service, 0, sizeof(orlan_tcp_service));
orlan_tcp_service.thread = kthread_run((void*)ktcp_start_listen, &orlan_tcp_service, MODULE_NAME);
if (orlan_tcp_service.thread)
{
//printk(KERN_INFO MODULE_NAME ": before waiting for listening socket creation\n");
//while (!orlan_tcp_service.running_thread);
//printk(KERN_INFO MODULE_NAME ": after waiting for listening socket creation (running = %d)\n", orlan_tcp_service.running);
//return orlan_tcp_service.running == 1 ? 0 : 1;
return 0;
}
return 1;
}
`
Send message function:
`
static int tcp_send_msg(struct socket *socket, unsigned char *buffer, unsigned long length)
{
struct msghdr msg;
struct kvec vec;
int len;
unsigned long size;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_flags = 0;//MSG_DONTWAIT;
vec.iov_len = length;
vec.iov_base = buffer;
size = length;
while (length)
{
printk(KERN_INFO MODULE_NAME ": before writing to socket\n");
len = kernel_sendmsg(socket, &msg, &vec, length, length);
printk(KERN_INFO MODULE_NAME ": after writing to socket\n");
if (len == -EAGAIN || len == -ERESTARTSYS)
continue;
if (len < 0)
return len;
if (len)
{
length -= (unsigned long)len;
vec.iov_len -= len;
vec.iov_base = (char*)vec.iov_base + len;
}
}
return (int)size;
}
`
Please help me,
Dmitriy
I tried to debug the problem. But nothing helped.
so... context: I'm doing a layer 2 protocol for flexible forwarding in vehicular environment (for now my testbed is in virtual machines), this should take in consideration a different number of interfaces (for multihoming) and multihop.
So what I have:
A way of broadcasting hop-by-hop the service provider.
What I'm triyng to do:
A way to register a session all the way from the client to the provider (And here is the problem)
Problem: I have two types of packets
1st is listened correctly and data payload starts with a 1
2nd for some reason is not detected but I can see the packet is sent and correct with tcpdump
Since I have to register in the application the interface where the connection is made I used select() which seems to be part of the problem since I only guessed how it was used and I'm kind of in the dark about this.
UPDATED v3:
Okay so as soon as I removed most of the stuff about only sending on a specific interface all the stuff worked perfectly (I still need to clean this code... it's kind of messy). Here is code if someone is interested:
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <ifaddrs.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#define ETH_P_CUSTOM 0x0801 /* EtherType of Current Used Protocol*/
#define BUF_SIZE 1024
typedef enum {
false, true
} Bool; /* Boolean Definition*/
typedef struct Stat {
uint8_t maxSocket; /*Number of sockets to use in receive*/
uint8_t nInterfaces; /*Number of interfaces owned by this machine*/
uint8_t nSession; /*Number of Sessions Known in the linked list*/
uint8_t upMac[ETH_ALEN]; /*MAC of this host upstream parent*/
uint8_t nHops; /*Hops to Provider*/
char ifName[IF_NAMESIZE + 1]; /*Interface to Provider*/
} Stat;
typedef struct Node {
uint64_t session; /*Client Session*/
uint8_t nextHop[ETH_ALEN]; /*Next-Hop to Client*/
char ifName[IF_NAMESIZE + 1]; /*Outgoing Interface that connects to Next-Hop*/
struct Node * next; /*Next Session*/
} Node;
typedef struct ifNode {
uint8_t ifIndex; /*Interface index*/
uint8_t sock; /*Index in array of sockets*/
uint8_t mac[ETH_ALEN]; /*Interface MAC*/
char ifName[IF_NAMESIZE + 1]; /*Interface Name*/
struct ifNode * next; /*Next Session*/
} ifNode;
Stat * op; /* Variable which tracks status of certain structures/variables*/
Node * first = NULL, *last = NULL; /* Edges of linked list */
ifNode * iffirst = NULL, *iflast = NULL; /* Edges of interface linked list */
int cargc;
char **cargv;
int receiveP();
int broadServ();
int announceSelf();
Node* create(uint64_t sess, uint8_t n[ETH_ALEN], char interface[IF_NAMESIZE]);
void insert_node(Node * p);
Node* search(uint64_t session);
void update(uint64_t session, Node * p);
ifNode* createif(uint8_t idx, uint8_t sock, uint8_t ifmac[ETH_ALEN],
char interface[IF_NAMESIZE]);
void insert_ifnode(ifNode * p);
ifNode* searchif(uint8_t idx, uint8_t mode);
void updateif(uint8_t idx, ifNode * p);
void display();
void displayif();
void ctrlcoverride(int sig) {
printf("\nCtrl-C - Signal Caught - Exiting\n\n");
printf(
"Current Upstream MAC: %02x:%02x:%02x:%02x:%02x:%02x - NHops : %u - At Interface %s\n\n",
op->upMac[0], op->upMac[1], op->upMac[2], op->upMac[3],
op->upMac[4], op->upMac[5], op->nHops, op->ifName);
display();
exit(EXIT_SUCCESS);
}
Node* create(uint64_t sess, uint8_t n[ETH_ALEN], char interface[IF_NAMESIZE]) {
Node * new = (Node *) malloc(sizeof(Node));
if (new == NULL) {
printf("Could not create new node\n");
return NULL;
} else {
strcpy(new->ifName, interface);
new->session = sess;
int i;
for (i = 0; i < ETH_ALEN; i++)
new->nextHop[i] = n[i];
new->next = NULL;
return new;
}
}
ifNode* createif(uint8_t idx, uint8_t sock, uint8_t ifmac[ETH_ALEN],
char interface[IF_NAMESIZE]) {
ifNode * new = (ifNode *) malloc(sizeof(ifNode));
if (new == NULL) {
printf("Could not create new interface node\n");
return NULL;
} else {
new->ifIndex = idx;
new->sock = sock;
strcpy(new->ifName, interface);
int i;
for (i = 0; i < ETH_ALEN; i++)
new->mac[i] = ifmac[i];
new->next = NULL;
return new;
}
}
void insert_node(Node * p) {
if (first == last && last == NULL) {
first = last = p;
first->next = NULL;
last->next = NULL;
} else {
last->next = p;
last = last->next;
last->next = NULL;
}
}
void insert_ifnode(ifNode * p) {
if (iffirst == iflast && iflast == NULL) {
iffirst = iflast = p;
iffirst->next = NULL;
iflast->next = NULL;
} else {
iflast->next = p;
iflast = iflast->next;
iflast->next = NULL;
}
}
Node* search(uint64_t session) {
if (first == last && last == NULL) {
return NULL;
} else {
Node * temp;
for (temp = first; temp != NULL; temp = temp->next) {
if (temp->session == session) {
return temp;
}
}
return NULL;
}
}
ifNode* searchif(uint8_t idx, uint8_t mode) {
if (iffirst == iflast && iflast == NULL) {
return NULL;
} else {
ifNode * temp;
for (temp = iffirst; temp != NULL; temp = temp->next) {
if (temp->ifIndex == idx && mode == 0) {
return temp;
} else if (temp->sock == idx && mode == 1) {
return temp;
}
}
return NULL;
}
}
void update(uint64_t session, Node * p) {
if (first == last && last == NULL) {
return;
} else {
Node * temp;
for (temp = first; temp != NULL; temp = temp->next) {
if (temp->session == session) {
strcpy(temp->ifName, p->ifName);
temp->next = p->next;
int i;
for (i = 0; i < ETH_ALEN; i++)
temp->nextHop[i] = p->nextHop[i];
return;
}
}
}
}
void updateif(uint8_t idx, ifNode * p) {
if (iffirst == iflast && iflast == NULL) {
return;
} else {
ifNode * temp;
for (temp = iffirst; temp != NULL; temp = temp->next) {
if (temp->ifIndex == idx) {
strcpy(temp->ifName, p->ifName);
temp->sock = p->sock;
temp->next = p->next;
int i;
for (i = 0; i < ETH_ALEN; i++)
temp->mac[i] = p->mac[i];
return;
}
}
}
}
void display() {
Node * temp = first;
while (temp != NULL) {
printf("Session %" PRIu64 " Through %s - NextHop at ", temp->session,
temp->ifName);
int i;
for (i = 0; i < ETH_ALEN; i++)
printf("%02x ", temp->nextHop[i]);
printf("\n");
temp = temp->next;
}
}
void displayif() {
ifNode * temp = iffirst;
while (temp != NULL) {
printf("Interface Index %u Socket Number %u - Name %s with MAC: ",
temp->ifIndex, temp->sock, temp->ifName);
int i;
for (i = 0; i < ETH_ALEN; i++)
printf("%02x ", temp->mac[i]);
printf("\n");
temp = temp->next;
}
}
uint8_t counter() {
Node * temp = first;
uint8_t counter = 0;
while (temp != NULL) {
counter++;
temp = temp->next;
}
return counter;
}
fd_set rfds;
int rec;
int main(int argc, char **argv) {
setbuf(stdout, NULL);
signal(SIGINT, ctrlcoverride);
cargc = argc;
cargv = argv;
/*Setting Base Variables to Initial Values*/
op = (Stat*) malloc(sizeof(Stat));
op->nSession = 0;
memset(op->ifName, 0, IF_NAMESIZE);
op->maxSocket = 0;
op->nHops = UINT8_MAX - 1;
int i;
for (i = 0; i < ETH_ALEN; i++) {
op->upMac[i] = 0x00;
}
memset(&rfds, 0, sizeof(fd_set));
FD_ZERO(&rfds);
if (argc != 2) {
printf("USAGE: sudo %s {provider|node|nodekey}\n", cargv[0]);
exit(EXIT_FAILURE);
} else if (!(strcmp(cargv[1], "provider") == 0
|| strcmp(cargv[1], "node") == 0 || strcmp(cargv[1], "nodekey") == 0)) {
printf("USAGE: sudo %s {provider|node|nodekey}\n", cargv[0]);
exit(EXIT_FAILURE);
}
if (strcmp(cargv[1], "nodekey") == 0) {
srand(time(NULL));
uint8_t myArray[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
insert_node(
create((uint64_t) (100 * ((float) rand() / RAND_MAX)), myArray,
"SOURCE"));
}
struct ifaddrs *ifaddr, *ifa;
if (getifaddrs(&ifaddr) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifaddr, op->nInterfaces = 0; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family == AF_PACKET
&& strncmp(ifa->ifa_name, "lo", strlen("lo")) != 0
&& strncmp(ifa->ifa_name, "tap", strlen("tap")) != 0) {
op->nInterfaces++;
}
}
rec = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_CUSTOM));
int sockopt;
char ifName[IFNAMSIZ];
struct ifreq ifr;
for (i = 1, ifa = ifaddr; ifa != NULL;
ifa = ifa->ifa_next, i++) {
if (ifa->ifa_addr == NULL)
continue;
if (ifa->ifa_addr->sa_family == AF_PACKET
&& strncmp(ifa->ifa_name, "lo", strlen("lo")) != 0
&& strncmp(ifa->ifa_name, "tap", strlen("tap")) != 0) {
uint8_t sock;
if ((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_CUSTOM)))
== -1) {
printf("socket() error: %u - %s\n", errno, strerror(errno));
return EXIT_FAILURE;
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sockopt,
sizeof sockopt) == -1) {
printf("SO_REUSEADDR error: %u - %s\n", errno, strerror(errno));
close(sock);
return EXIT_FAILURE;
}
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_ifindex = i;
strcpy(ifr.ifr_name, ifa->ifa_name);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifa->ifa_name,
IF_NAMESIZE) == -1) {
printf("SO_BINDTODEVICE error: %u - %s\n", errno,
strerror(errno));
close(sock);
return EXIT_FAILURE;
}
struct sockaddr_ll sll;
sll.sll_family = AF_PACKET;
sll.sll_ifindex = i;
sll.sll_protocol = htons(ETH_P_CUSTOM);
if ((bind(sock, (struct sockaddr *) &sll, sizeof(sll))) == -1) {
perror("Error binding raw socket to interface\n");
exit(-1);
}
if ((ioctl(sock, SIOCGIFHWADDR, &ifr)) != 0) {
printf("SIOCGIFHWADDR error: %u - %s\n", errno,
strerror(errno));
return EXIT_FAILURE;
}
int j;
uint8_t ifmac[ETH_ALEN];
for (j = 0; j < ETH_ALEN; j++) {
ifmac[j] = (uint8_t) (ifr.ifr_hwaddr.sa_data)[j];
}
FD_SET(sock, &rfds);
op->maxSocket = (op->maxSocket < sock) ? sock : op->maxSocket;
insert_ifnode(createif(i, sock, ifmac, ifr.ifr_name));
}
}
displayif();
if (strcmp(cargv[1], "provider") == 0) {
struct ifreq if_mac; // interface
char * interface = "eth1";
int sockfd;
if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_CUSTOM))) == -1) {
printf("socket() error: %u - %s\n", errno, strerror(errno));
return EXIT_FAILURE;
}
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, interface, IFNAMSIZ - 1);
if ((ioctl(sockfd, SIOCGIFHWADDR, &if_mac)) != 0) {
printf("SIOCGIFHWADDR error: %u - %s\n", errno, strerror(errno));
return EXIT_FAILURE;
}
int i;
for (i = 0; i < ETH_ALEN; i++)
op->upMac[i] = ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[i];
op->nHops = 0;
close(sockfd);
}
freeifaddrs(ifaddr);
int stat = 0;
while (1) {
if (strcmp(cargv[1], "provider") == 0) {
if ((stat = receiveP()) != 0)
return stat;
if ((stat = broadServ()) != 0)
return stat;
display();
usleep(100000);
} else if (strcmp(cargv[1], "node") == 0
|| strcmp(cargv[1], "nodekey") == 0) {
if ((stat = receiveP()) != 0)
return stat;
if ((stat = announceSelf()) != 0){
return stat;
}
if ((stat = broadServ()) != 0)
return stat;
display();
usleep(100000);
}
}
ifNode * temp = iffirst;
while (temp != NULL) {
close(temp->sock);
temp = temp->next;
}
exit(stat);
}
int receiveP() {
int stat = 0;
struct ifreq ifr;
struct sockaddr saddr;
long unsigned int numbytes = 0;
char buf[BUF_SIZE];
memset(buf, 0, BUF_SIZE);
struct ether_header *eh = (struct ether_header *) buf;
unsigned int saddr_size = sizeof saddr;
struct timeval tv;
tv.tv_sec = 3; /* 3 Secs Timeout */
tv.tv_usec = 0;
setsockopt(rec, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv,
sizeof(struct timeval));
numbytes = recvfrom(rec, buf, BUF_SIZE, 0, &saddr, &saddr_size);
int len;
int ntable;
switch (buf[sizeof(struct ether_header)]) {
case 1:
if (buf[sizeof(struct ether_header) + 1] < op->nHops) {
op->upMac[0] = eh->ether_shost[0];
op->upMac[1] = eh->ether_shost[1];
op->upMac[2] = eh->ether_shost[2];
op->upMac[3] = eh->ether_shost[3];
op->upMac[4] = eh->ether_shost[4];
op->upMac[5] = eh->ether_shost[5];
op->nHops = buf[sizeof(struct ether_header) + 1] + 1;
memset(&ifr, 0, sizeof(struct ifreq));
memset(&ifr.ifr_name, 0, IF_NAMESIZE);
printf(
"Server %u Hops Away - Through %02x:%02x:%02x:%02x:%02x:%02x At Interface %s\n",
op->nHops, eh->ether_shost[0], eh->ether_shost[1],
eh->ether_shost[2], eh->ether_shost[3], eh->ether_shost[4],
eh->ether_shost[5], op->ifName);
printf("\n\n");
}
break;
case 2:
len = sizeof(struct ether_header) + 1;
ntable = buf[len++];
int j;
for (j = 0; j < ntable; j++, len++) {
if (search(buf[len]) == NULL) {
insert_node(create(buf[len], eh->ether_shost, ""));
}
}
break;
}
return stat;
}
int broadServ() {
int stat = 0;
int tx_len = 0;
char sendbuf[BUF_SIZE];
char ifName[IF_NAMESIZE - 1];
struct ether_header *eh = (struct ether_header *) sendbuf;
struct sockaddr_ll socket_address;
int i;
struct ifreq ifr, if_mac;
ifNode * temp = iffirst;
while (temp != NULL) {
/* Get the index of the interface to send on */
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_ifindex = temp->ifIndex;
if (ioctl(temp->sock, SIOCGIFNAME, &ifr) < 0)
perror("SIOCGIFINDEX");
memset(ifName, 0, IF_NAMESIZE - 1);
strncpy(ifName, ifr.ifr_name, IF_NAMESIZE - 1);
/* Get the MAC address of the interface to send on */
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, ifName, IFNAMSIZ - 1);
if (ioctl(temp->sock, SIOCGIFHWADDR, &if_mac) < 0)
perror("SIOCGIFHWADDR");
if (((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[0] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[1] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[2] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[3] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[4] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[5] == 0x00)
continue;
memset(sendbuf, 0, BUF_SIZE);
/* 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] = 0xff;
eh->ether_dhost[1] = 0xff;
eh->ether_dhost[2] = 0xff;
eh->ether_dhost[3] = 0xff;
eh->ether_dhost[4] = 0xff;
eh->ether_dhost[5] = 0xff;
/* Ethertype field */
eh->ether_type = htons(ETH_P_CUSTOM);
tx_len = sizeof(struct ether_header);
/* Packet data */
sendbuf[tx_len++] = 1;
sendbuf[tx_len++] = op->nHops; //+1;
/* Index of the network device */
socket_address.sll_ifindex = temp->ifIndex;
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address.sll_addr[0] = 0xff;
socket_address.sll_addr[1] = 0xff;
socket_address.sll_addr[2] = 0xff;
socket_address.sll_addr[3] = 0xff;
socket_address.sll_addr[4] = 0xff;
socket_address.sll_addr[5] = 0xff;
/* Send packet */
if (sendto(temp->sock, sendbuf, tx_len, 0,
(struct sockaddr*) &socket_address, sizeof(struct sockaddr_ll))
< 0)
printf("Send failed\n");
temp = temp->next;
}
return stat;
}
int announceSelf() {
if (op->upMac[0] == 0x00 && op->upMac[1] == 0x00 && op->upMac[2] == 0x00
&& op->upMac[3] == 0x00 && op->upMac[4] == 0x00
&& op->upMac[5] == 0x00)
return EXIT_SUCCESS;
int stat = 0;
int tx_len = 0;
char sendbuf[BUF_SIZE];
char ifName[IF_NAMESIZE - 1];
struct ether_header *eh = (struct ether_header *) sendbuf;
struct sockaddr_ll socket_address;
int i;
struct ifreq ifr, if_mac;
ifNode * temp = iffirst;
while (temp != NULL) {
memset(&ifr, 0, sizeof(struct ifreq));
ifr.ifr_ifindex = temp->ifIndex;
if (ioctl(temp->sock, SIOCGIFNAME, &ifr) < 0)
perror("SIOCGIFINDEX");
memset(ifName, 0, IF_NAMESIZE - 1);
strncpy(ifName, ifr.ifr_name, IF_NAMESIZE - 1);
/* Get the MAC address of the interface to send on */
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, ifName, IFNAMSIZ - 1);
if (ioctl(temp->sock, SIOCGIFHWADDR, &if_mac) < 0)
perror("SIOCGIFHWADDR");
if (((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[0] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[1] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[2] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[3] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[4] == 0x00
&& ((uint8_t *) &if_mac.ifr_hwaddr.sa_data)[5] == 0x00)
continue;
memset(sendbuf, 0, BUF_SIZE);
/* 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] = op->upMac[0];
eh->ether_dhost[1] = op->upMac[1];
eh->ether_dhost[2] = op->upMac[2];
eh->ether_dhost[3] = op->upMac[3];
eh->ether_dhost[4] = op->upMac[4];
eh->ether_dhost[5] = op->upMac[5];
/* Ethertype field */
eh->ether_type = htons(ETH_P_CUSTOM);
tx_len = sizeof(struct ether_header);
/* Packet data */
sendbuf[tx_len++] = 2;
sendbuf[tx_len++] = counter();
Node *temp1 = first;
for (; temp1 != NULL; temp1 = temp1->next) {
sendbuf[tx_len++] = temp1->session;
}
socket_address.sll_ifindex = temp->ifIndex;
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
socket_address.sll_addr[0] = op->upMac[0];
socket_address.sll_addr[1] = op->upMac[1];
socket_address.sll_addr[2] = op->upMac[2];
socket_address.sll_addr[3] = op->upMac[3];
socket_address.sll_addr[4] = op->upMac[4];
socket_address.sll_addr[5] = op->upMac[5];
/* Send packet */
if (sendto(temp->sock, sendbuf, tx_len, 0,
(struct sockaddr*) &socket_address, sizeof(struct sockaddr_ll))
< 0)
printf("Send failed\n");
temp = temp->next;
}
return stat;
}
So to test this you can have VM with linux connected like this (for example):
Provider ----- Node ----- Node ----- Nodekey
I still had a problem when creating multiple sessions, i wasn't incrementing the buffer when reading and I was reading multiple times the same position. Now it's working good
OK, let's begin with the easiest recommendations but I'm not sure this is going to resolve the problem at once. I did a system like this many years ago for different boards with different processor architectures communicating with each other. All the boards were running within a telecommunication switch. It's a very nice problem and you are facing it in the proper way with a peer-to-peer distributed solution.
I didn't go through all code but it seems each node is discovering the neighbour nodes in the network and everyone is creating a tree.
In select, the first argument should not be FD_SETSIZE but the highest-numbered file descriptor in any of the three sets (in this case the read set), plus 1.
The infinite loop is calling receiveSession which is creating all sockets again and then it reads. If a frame with your specific layer-2 protocol arrives in the middle and there is no socket listening for it, it will be discarded. Maybe your problem could be here.
When you send Ethernet frames directly, the hardware will complete the frame to the minimum Ethernet size: 64 octets (so you might receive padding data up to 46 octets - Octets not Bytes)
Please read here:
http://en.wikipedia.org/wiki/Ethernet_frame
It is good you chose an EtherType ETH_P_CUSTOM higher than 1536 that is not already in use but maybe you want to use a much higher number in order to minimize possibilities of collision with other protocols.
Something important. Your testbed now is with VM's which are usually x86 architectures, 64 bits. When you run your software in real devices with different processors, that might not be the situation. This is very important because you might have different architectures with different endianship and different integer size. That will affect the integer numbers you send, especially in ether_header, and the size of your structures. You have to use the the macros ntohs, ntohl, htons, htonl to change between host and network endianship (session is uint64_t). You should send data in network endianship. This is not solving your very current problem but you might have this problem in the future.
We are using Linux-2.6.28 and 2 Gb NAND Flash in our system ; After some amount of power cycle tests we are observing the following errors :
Volume operational found at volume id 3
read 21966848 bytes from volume 3 to 80400000(buf address)
UBI error: ubi_io_read: error -77 while reading 126976 bytes from PEB 1074:4096, read 126976 bytes
UBI: force data checking
UBI error: ubi_io_read: error -77 while reading 126976 bytes from PEB 1074:4096, read 126976 bytes
UBI warning: ubi_eba_read_leb: CRC error: calculated 0xa7cab743, must be 0x15716fce
read err ffffffb3
These errors are not hardware errors as if we remove the offending partition, we are able to boot the hardware fine; Maybe UBIFS is not correcting the bad UBI block.
Any UBI patches have been added in the latest kernels to address this issue ? Thanks.
The error printed is a UBI error. Lets look at the source near line 177,
ubi_err("error %d while reading %d bytes from PEB %d:%d, "
"read %zd bytes", err, len, pnum, offset, read);
So, error '-77' (normally -EBADFD) was returned from the NAND flash driver when trying to read the 'physical erase block' #1074 at offset 4096 (2nd page for 2k pages). UBI include volume management pages which are typically located at the beginning of a physical erase block (PEB for short).
Note that the latest mainline of io.c has the following comment and code,
/*
* Deliberately corrupt the buffer to improve robustness. Indeed, if we
* do not do this, the following may happen:
* 1. The buffer contains data from previous operation, e.g., read from
* another PEB previously. The data looks like expected, e.g., if we
* just do not read anything and return - the caller would not
* notice this. E.g., if we are reading a VID header, the buffer may
* contain a valid VID header from another PEB.
* 2. The driver is buggy and returns us success or -EBADMSG or
* -EUCLEAN, but it does not actually put any data to the buffer.
*
* This may confuse UBI or upper layers - they may think the buffer
* contains valid data while in fact it is just old data. This is
* especially possible because UBI (and UBIFS) relies on CRC, and
* treats data as correct even in case of ECC errors if the CRC is
* correct.
*
* Try to prevent this situation by changing the first byte of the
* buffer.
*/
*((uint8_t *)buf) ^= 0xFF;
The following code can be used to process a UBI/UbiFS dump and look for abnormalities,
/* -*- mode: c; compile-command: "gcc -Wall -g -o parse_ubi parse_ubi.c"; -*- */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <endian.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define __packed __attribute__((packed))
#include "ubi-media.h"
#define bswap16 be16toh
#define bswap32 be32toh
#define bswap64 be64toh
static int dump_vid = 0;
#define CRCPOLY_LE 0xedb88320
static unsigned int crc32(unsigned int crc, void const *_p, size_t len)
{
unsigned char const *p = _p;
int i;
while (len--) {
crc ^= *p++;
for (i = 0; i < 8; i++)
crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
}
return crc;
}
#define ALEN(a) (sizeof(a)/sizeof(a[0]))
static void print_ec(struct ubi_ec_hdr *ec)
{
if(ec->version != UBI_VERSION || ec->magic != UBI_EC_HDR_MAGIC) {
printf(" Magic: %x\n", ec->magic);
printf(" Version: %d\n", (int)ec->version);
printf(" EC: %llx\n", ec->ec);
printf(" VID offset: %x\n", ec->vid_hdr_offset);
printf(" Data offset: %x\n", ec->data_offset);
printf(" Image seq: %x\n", ec->image_seq);
exit(-1);
}
}
static void read_ec(int fd, struct ubi_ec_hdr *ec)
{
int rval = read(fd, ec,sizeof(*ec));
if(rval == sizeof(*ec)) {
unsigned int crc;
crc = crc32(UBI_CRC32_INIT, ec, UBI_EC_HDR_SIZE_CRC);
ec->magic = bswap32(ec->magic);
ec->vid_hdr_offset = bswap32(ec->vid_hdr_offset);
ec->data_offset = bswap32(ec->data_offset);
ec->image_seq = bswap32(ec->image_seq);
ec->hdr_crc = bswap32(ec->hdr_crc);
ec->ec = bswap64(ec->ec);
if(crc != ec->hdr_crc)
printf("EC CRC: %x/%x\n", crc, ec->hdr_crc);
} else
memset(ec, 0, sizeof(*ec));
}
static void print_vid(int vid_num, struct ubi_vid_hdr *vid)
{
if(vid->magic != UBI_VID_HDR_MAGIC)
printf(" Magic: %x\n", vid->magic);
if(vid->version != UBI_VERSION)
printf(" Version: %d\n", (int)vid->version);
if(!dump_vid) return;
printf("VID %d\n", vid_num);
/* This is usually the same. */
if(vid->vol_id >= UBI_INTERNAL_VOL_START)
printf("Internal vol_id: %d\n", vid->vol_id - UBI_INTERNAL_VOL_START);
if(vid->vol_type != UBI_VID_DYNAMIC)
printf(" vol_type: %s\n",
vid->vol_type == UBI_VID_DYNAMIC ? "dynamic" : "static");
if(vid->used_ebs)
printf(" used_ebs: %d\n", vid->used_ebs);
if(vid->data_pad)
printf(" data_pad: %d\n", vid->data_pad);
if((vid->copy_flag != 1 && vid->data_size) ||
(vid->copy_flag == 0 && vid->data_size))
printf(" copy_flag: %d\n", (int)vid->copy_flag);
printf(" lnum: %d\n", vid->lnum);
if(vid->compat) {
const char *compat[] = {
[UBI_COMPAT_DELETE] = "delete",
[UBI_COMPAT_RO] = "ro",
[UBI_COMPAT_PRESERVE] = "preserve",
[UBI_COMPAT_REJECT] = "reject"
};
printf(" compat: %s\n", compat[vid->compat]);
}
printf(" data_size: %d\n", vid->data_size);
/* printf(" data_crc: %x\n", vid->data_crc); */
printf(" hdr_crc: %x\n", vid->hdr_crc);
printf(" sqnum: %lld\n", vid->sqnum);
}
static int read_vid(int fd, struct ubi_vid_hdr *vid)
{
int rval = read(fd, vid,sizeof(*vid));
if(rval == sizeof(*vid)) {
unsigned int crc;
crc = crc32(UBI_CRC32_INIT, vid, UBI_EC_HDR_SIZE_CRC);
vid->magic = bswap32(vid->magic);
vid->vol_id = bswap32(vid->vol_id);
vid->lnum = bswap32(vid->lnum);
vid->data_size = bswap32(vid->data_size);
vid->used_ebs = bswap32(vid->used_ebs);
vid->data_pad = bswap32(vid->data_pad);
vid->data_crc = bswap32(vid->data_crc);
vid->hdr_crc = bswap32(vid->hdr_crc);
vid->sqnum = bswap64(vid->sqnum);
if(crc != vid->hdr_crc && vid->magic == UBI_VID_HDR_MAGIC)
printf("VID CRC: %x/%x\n", crc, vid->hdr_crc);
} else
memset(vid, 0, sizeof(*vid));
return rval;
}
static void print_vtbl(struct ubi_vtbl_record *vtbl)
{
printf(" Found vtbl [%d] %s\n", vtbl->name_len, vtbl->name);
printf(" Reserved PEBs: %d\n", vtbl->reserved_pebs);
printf(" Align: %d\n", vtbl->alignment);
printf(" Pad: %d\n", vtbl->data_pad);
if(vtbl->vol_type != UBI_VID_DYNAMIC)
printf(" vol_type: %s\n",
vtbl->vol_type == UBI_VID_DYNAMIC ? "dynamic" : "static");
printf(" Update: %d\n", vtbl->upd_marker);
printf(" Flags: %d\n", (int)vtbl->flags);
}
static void read_vtbl(int fd, struct ubi_vtbl_record *vtbl)
{
int rval = read(fd, vtbl, sizeof(*vtbl));
if(rval == sizeof(*vtbl)) {
vtbl->reserved_pebs = bswap32(vtbl->reserved_pebs);
vtbl->alignment = bswap32(vtbl->alignment);
vtbl->data_pad = bswap32(vtbl->data_pad);
vtbl->crc = bswap32(vtbl->crc);
vtbl->name_len = bswap16(vtbl->name_len);
} else
memset(vtbl, 0, sizeof(*vtbl));
}
static void print_fm_sb(struct ubi_fm_sb *fm_sb)
{
int i;
if(fm_sb->magic != UBI_FM_SB_MAGIC)
printf(" Magic: %x\n", fm_sb->magic);
if(fm_sb->version != UBI_VERSION)
printf(" Version: %d\n", (int)fm_sb->version);
printf(" data_crc: %x\n", fm_sb->data_crc);
printf(" used_blocks: %x\n", fm_sb->used_blocks);
for(i = 0; i < fm_sb->used_blocks; i++)
printf(" block_loc[%d]: %d\n", i, fm_sb->block_loc[i]);
for(i=0; i < fm_sb->used_blocks; i++)
printf(" block_ec[%d]: %d\n", i, fm_sb->block_ec[i]);
printf(" sqnum: %lld\n", fm_sb->sqnum);
}
static void read_fm_sb(int fd, struct ubi_fm_sb *fm_sb)
{
int rval = read(fd, fm_sb, sizeof(*fm_sb));
if(rval == sizeof(*fm_sb)) {
int i;
fm_sb->magic = bswap32(fm_sb->magic);
fm_sb->data_crc = bswap32(fm_sb->data_crc);
fm_sb->used_blocks = bswap32(fm_sb->used_blocks);
for(i=0; i < UBI_FM_MAX_BLOCKS; i++)
fm_sb->block_loc[i] = bswap32(fm_sb->block_loc[i]);
for(i=0; i < UBI_FM_MAX_BLOCKS; i++)
fm_sb->block_ec[i] = bswap32(fm_sb->block_ec[i]);
fm_sb->sqnum = bswap64(fm_sb->sqnum);
} else
memset(fm_sb, 0, sizeof(*fm_sb));
}
/* Set logical block at physical. */
static int eba_map[1920];
static int pba_map[1920];
static void usage(char *name)
{
printf("Usage: %s -b [erase block size] -e -v <ubi file> \n", name);
printf("Where,\n -e is dump the logic to physical block map.\n");
printf(" -v is dump the VID headers.\n");
printf(" -b [size] sets the erase block size (flash dependent).\n");
}
typedef struct fastmap {
struct ubi_fm_sb fm_sb;
struct ubi_fm_hdr hdr;
struct ubi_fm_scan_pool pool1;
struct ubi_fm_scan_pool pool2;
/* Free, Used, Scrub and Erase */
struct ubi_fm_ec ec[0];
/* ... */
/* struct ubi_fm_volhdr vol; */
/* struct ubi_fm_eba eba[0]; */
} fastmap;
int main (int argc, char *argv[])
{
int fd, i, erase_block = 0, eba_flag = 0;
int c;
struct ubi_ec_hdr ec;
struct ubi_vid_hdr vid;
int erase_size = 0x20000;
int leb_size;
off_t cur_ec = 0;
int vidless_blocks = 0;
while ((c = getopt (argc, argv, "hveb:")) != -1)
switch (c)
{
case 'h': /* Help */
usage(argv[0]);
goto out;
case 'b':
erase_size = atoi(optarg);
break;
case 'e':
eba_flag = 1;
break;
case 'v':
dump_vid = 1;
break;
case '?':
if (optopt == 'b')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
goto out;
}
if(optind >= argc) {
usage(argv[0]);
goto out;
}
fd = open(argv[optind], O_RDONLY);
if(fd < 0) {
printf("Bad file: %s\n", argv[1]);
goto out;
}
memset(eba_map, -1, sizeof(eba_map));
memset(pba_map, -1, sizeof(pba_map));
/* Process each 'erase block'. */
read_ec(fd,&ec);
while(ec.magic == UBI_EC_HDR_MAGIC) {
leb_size = erase_size - ec.data_offset;
print_ec(&ec);
/* VID present? */
if(lseek(fd, ec.vid_hdr_offset-sizeof(ec), SEEK_CUR) == -1) {
printf("Seek error: %s\n", argv[1]);
goto out;
}
if(read_vid(fd,&vid) != sizeof(vid)) {
printf("File too small: %s\n", argv[1]);
goto out;
}
if(vid.magic == UBI_VID_HDR_MAGIC) {
print_vid(erase_block, &vid);
if(vid.vol_id == 3) {
if(eba_map[vid.lnum] != -1)
printf("EBA dup: %d %d\n", eba_map[vid.lnum], erase_block);
eba_map[vid.lnum] = erase_block;
}
pba_map[erase_block] = vid.lnum;
/* Read volume table. */
if(vid.vol_id == UBI_INTERNAL_VOL_START) {
/* Seek to PEB data offset. */
if(lseek(fd,
ec.data_offset - ec.vid_hdr_offset - sizeof(vid),
SEEK_CUR) == -1)
printf("Seek error: %s\n", argv[1]);
else {
int i;
struct ubi_vtbl_record vtbl;
for(i = 0; i < UBI_MAX_VOLUMES; i++) {
read_vtbl(fd, &vtbl);
if(vtbl.reserved_pebs ||
vtbl.name_len ||
strcmp((char*)vtbl.name, "") != 0) {
printf("VTBL %d\n", i);
print_vtbl(&vtbl);
}
}
}
} else if(vid.vol_id == UBI_FM_SB_VOLUME_ID) {
printf("Found Fastmap super block #PEB %d.\n", erase_block);
if(lseek(fd,
ec.data_offset - ec.vid_hdr_offset - sizeof(vid),
SEEK_CUR) == -1)
printf("Seek error: %s\n", argv[1]);
else {
void *data = alloca(leb_size);
struct ubi_fm_sb *fm_sb = data;
read_fm_sb(fd, data);
print_fm_sb(fm_sb);
}
} else if(vid.vol_id == UBI_FM_DATA_VOLUME_ID) {
printf("Found Fastmap data block #PEB %d.\n", erase_block);
printf("UNSUPPORTED!!!\n");
}
} else if(vid.magic != 0xffffffff){
printf("VID %d corrupt! %x\n", erase_block, vid.magic);
} else {
vidless_blocks++;
}
erase_block++;
cur_ec += erase_size;
cur_ec = lseek(fd, cur_ec, SEEK_SET);
/* Process Erase counter. */
read_ec(fd,&ec);
}
printf("Found %d vidless (free) blocks.\n", vidless_blocks);
if(eba_flag) {
printf("Logical to physical.\n");
for(i = 0; i < ALEN(eba_map); i+=8)
printf("%4d: %4d %4d %4d %4d %4d %4d %4d %4d"
" %4d %4d %4d %4d %4d %4d %4d %4d\n", i,
eba_map[i], eba_map[i+1],
eba_map[i+2], eba_map[i+3],
eba_map[i+4], eba_map[i+5],
eba_map[i+6], eba_map[i+7],
eba_map[i+8], eba_map[i+9],
eba_map[i+10], eba_map[i+11],
eba_map[i+12], eba_map[i+13],
eba_map[i+14], eba_map[i+15]);
printf("Physical to logical.\n");
for(i = 0; i < ALEN(pba_map); i+=8)
printf("%4d: %4d %4d %4d %4d %4d %4d %4d %4d"
" %4d %4d %4d %4d %4d %4d %4d %4d\n", i,
pba_map[i], pba_map[i+1],
pba_map[i+2], pba_map[i+3],
pba_map[i+4], pba_map[i+5],
pba_map[i+6], pba_map[i+7],
pba_map[i+8], pba_map[i+9],
pba_map[i+10], pba_map[i+11],
pba_map[i+12], pba_map[i+13],
pba_map[i+14], pba_map[i+15]);
}
out:
return 0;
}
To build copy ubi-media.h from the UBI directory and run gcc -Wall -g -o parse_ubi parse_ubi.c. The code probably has issues on big-endian platforms; it is also not test with 2.6.28 but I believe it should work as the UBI structures shouldn't change. You may have to remove some fastmap code, if it doesn't compile. The code should give some indication on what is wrong with PEB#1074. Make a copy of the partition when failing and use the code above to analyze the UBI layer.
It is quite possible that the MTD driver does something abnormal which prevents UBI from attaching to an MTD partition. This in-turn prevents UbiFS from mounting. If you know what MTD Nand flash controller is being used, it would help others determine where the issue is.
It can be caused by MTD bugs and/or hardware bugs or UBI/UbiFS issues. If it is UBI/UbiFs, there are backport trees and newer 3.0. You can try to steal the patches from 2.6.32; after applying all, add the 3.0.
Again, the issue can be the MTD driver. Grab MTD changes for your particular CPU/SOCs NAND flash controller. I do this from the mainline; some changes are bug fixes and others infra-structure. You have to look at each patch individually
I wrote a simple module which emulates a force feedback input device so that I can test the underlying FFB implementation. However, the module sometimes crashes the kernel with the "scheduling while atomic" message. According to the backtrace the crash is triggered by ff_dummy_open() and I can reproduce it easily by destroying and recreating the dummy device a couple of times in a row through sysfs. What am I doing wrong?
Source of the module:
#include <linux/input.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/input/ff-logitech.h>
MODULE_LICENSE("GPL");
struct ff_dummy_device {
struct input_dev *dev;
int slot;
};
static struct kobject *ff_dummy_kobj;
static struct ff_dummy_device **ff_dummy_devices;
static int max_device_count;
static unsigned char device_count = 0;
static struct mutex mtx;
static const char *ff_dummy_name = "DumFFBD";
static const signed short ff_dummy_effects[] = {
FF_CONSTANT,
FF_PERIODIC,
FF_TRIANGLE,
FF_SAW_UP,
FF_SAW_DOWN,
FF_SINE,
FF_SQUARE,
FF_SPRING,
FF_DAMPER,
FF_INERTIA,
FF_FRICTION,
FF_RAMP,
-1
};
static int ff_dummy_control(struct input_dev *dev, void *data, const struct lgff_effect_command *command)
{
struct ff_dummy_device *ddev = data;
switch (command->cmd) {
case LGFF_START_COMBINED:
pr_debug("Force X: %d, Force Y: %d, (idx %d)\n", command->u.simple_force.x, command->u.simple_force.y, ddev->slot);
break;
case LGFF_STOP_COMBINED:
pr_debug("Stopping COMBINED effect (idx %d).\n", ddev->slot);
break;
case LGFF_START_UNCOMB:
pr_debug("Starting UNCOMBINABLE effect.\n");
pr_debug("LC(x): %d RC(x): %d, LS(x): %d, RS(x): %d\n",
command->u.uncomb.effect->u.condition[0].left_coeff,
command->u.uncomb.effect->u.condition[0].right_coeff,
command->u.uncomb.effect->u.condition[0].left_saturation,
command->u.uncomb.effect->u.condition[0].right_saturation);
pr_debug("LC(y): %d RC(y): %d, LS(y): %d, RS(y): %d\n",
command->u.uncomb.effect->u.condition[1].left_coeff,
command->u.uncomb.effect->u.condition[1].right_coeff,
command->u.uncomb.effect->u.condition[1].left_saturation,
command->u.uncomb.effect->u.condition[1].right_saturation);
switch (command->u.uncomb.effect->type) {
case FF_DAMPER:
pr_debug("Starting DAMPER id %d\n", command->u.uncomb.id);
break;
case FF_FRICTION:
pr_debug("Starting FRICTION id %d\n", command->u.uncomb.id);
break;
case FF_INERTIA:
pr_debug("Starting INERTIA id %d\n", command->u.uncomb.id);
break;
case FF_SPRING:
pr_debug("Starting SPRING id %d\n", command->u.uncomb.id);
break;
}
break;
case LGFF_STOP_UNCOMB:
pr_debug("Stopping UNCOMBINABLE effect.\n");
switch (command->u.uncomb.effect->type) {
case FF_DAMPER:
pr_debug("Stopping DAMPER id %d\n", command->u.uncomb.id);
break;
case FF_FRICTION:
pr_debug("Stopping FRICTION id %d\n", command->u.uncomb.id);
break;
case FF_INERTIA:
pr_debug("Stopping INERTIA id %d\n", command->u.uncomb.id);
break;
case FF_SPRING:
pr_debug("Stopping SPRING id %d\n", command->u.uncomb.id);
break;
}
break;
}
return 0;
}
static void ff_dummy_close(int idx)
{
if (idx < 0 || idx > max_device_count) {
printk(KERN_WARNING "Invalid device index.\n");
return;
}
if (!ff_dummy_devices[idx])
return;
mutex_lock(&mtx);
input_unregister_device(ff_dummy_devices[idx]->dev);
kfree(ff_dummy_devices[idx]);
ff_dummy_devices[idx] = NULL;
device_count--;
mutex_unlock(&mtx);
printk(KERN_NOTICE "Dummy force feedback %u device removed.\n", idx);
}
static int ff_dummy_open(int idx)
{
struct ff_dummy_device *newdummy;
struct input_dev *newdev;
int i, ret;
if (idx < 0 || idx >= max_device_count) {
printk(KERN_WARNING "Invalid device index.\n");
return -EINVAL;
}
newdummy = kzalloc(sizeof(struct ff_dummy_device *), GFP_KERNEL);
if (!newdummy) {
printk(KERN_ERR "Unable to allocate memory for dummy device slot.\n");
return -ENOMEM;
}
mutex_lock(&mtx);
if (ff_dummy_devices[idx]) {
printk(KERN_WARNING "Selected slot %u already occupied.\n", idx);
mutex_unlock(&mtx);
kfree(newdummy);
return -EINVAL;
}
ff_dummy_devices[idx] = newdummy;
newdev = input_allocate_device();
if (!newdev) {
printk(KERN_ERR "Unable to allocate memory for input device.\n");
ret = -ENOMEM;
goto open_err;
}
newdev->id.bustype = BUS_VIRTUAL;
newdev->id.vendor = 0xffff;
newdev->id.product = 0x0001;
newdev->id.version = 0x0001;
newdev->name = ff_dummy_name;
newdev->uniq = kasprintf(GFP_KERNEL, "%s_%u", ff_dummy_name, idx);
set_bit(EV_FF, newdev->evbit);
/* Make the device look like force feedback device */
for (i = 0; ff_dummy_effects[i] >= 0; i++)
set_bit(ff_dummy_effects[i], newdev->ffbit);
ret = input_register_device(newdev);
if (ret) {
printk(KERN_ERR "Unable to register dummy device.\n");
input_free_device(newdev);
goto open_err;
}
ret = input_ff_create_logitech(newdev, (void *)ff_dummy_devices[idx], ff_dummy_control);
if (ret) {
printk(KERN_ERR "Unable to register dummy device with ff-logitech\n");
input_unregister_device(newdev);
goto open_err;
}
ff_dummy_devices[idx]->dev = newdev;
ff_dummy_devices[idx]->slot = idx;
device_count++;
mutex_unlock(&mtx);
printk(KERN_NOTICE "Dummy force feedback %u device created.\n", idx);
return 0;
open_err:
kfree(ff_dummy_devices[idx]);
ff_dummy_devices[idx] = NULL;
mutex_unlock(&mtx);
return ret;
}
static ssize_t ff_dummy_add_device_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int ret;
mutex_lock(&mtx);
ret = scnprintf(buf, PAGE_SIZE, "%u\n", device_count);
mutex_unlock(&mtx);
return ret;
}
static ssize_t ff_dummy_add_device_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf,
size_t count)
{
int ret;
int idx = 0;
sscanf(buf, "%d", &idx);
ret = ff_dummy_open(idx);
if (ret) {
printk(KERN_ERR "Dummy device creation failed with errno %d\n", ret);
return ret;
}
return count;
}
static ssize_t ff_dummy_del_device_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int i;
int ret = 0;
mutex_lock(&mtx);
for (i = 0; i < max_device_count; i++) {
if (ff_dummy_devices[i])
ret += scnprintf(buf + ret, PAGE_SIZE, "[%u] ", i);
else
ret += scnprintf(buf + ret, PAGE_SIZE, "%u ", i);
}
mutex_unlock(&mtx);
ret += scnprintf(buf + ret, PAGE_SIZE, "\n");
return ret;
}
static ssize_t ff_dummy_del_device_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf,
size_t count)
{
int idx = 0;
sscanf(buf, "%d", &idx);
ff_dummy_close(idx);
return count;
}
static struct kobj_attribute add_device_attr =
__ATTR(add_device, 0644, ff_dummy_add_device_show, ff_dummy_add_device_store);
static struct kobj_attribute del_device_attr =
__ATTR(del_device, 0644, ff_dummy_del_device_show, ff_dummy_del_device_store);
static struct attribute *attrs[] = {
&add_device_attr.attr,
&del_device_attr.attr,
NULL
};
static struct attribute_group attrs_grp = {
.attrs = attrs
};
static void __exit ff_dummy_exit(void)
{
int i;
sysfs_remove_group(ff_dummy_kobj, &attrs_grp);
for (i = 0; i < max_device_count; i++)
if (ff_dummy_devices[i])
ff_dummy_close(i);
kfree(ff_dummy_devices);
kobject_put(ff_dummy_kobj);
printk(KERN_NOTICE "Dummy force feedback module removed.\n");
}
static int __init ff_dummy_init(void)
{
int ret;
if (max_device_count < 1)
max_device_count = 2;
ff_dummy_kobj = kobject_create_and_add("ff_dummy_device_obj", kernel_kobj);
if (!ff_dummy_kobj)
return -ENOMEM;
ff_dummy_devices = kcalloc(max_device_count, sizeof(struct ff_dummy_device *), GFP_KERNEL);
if (!ff_dummy_devices) {
ret = -ENOMEM;
goto err_alloc;
}
mutex_init(&mtx);
ret = sysfs_create_group(ff_dummy_kobj, &attrs_grp);
if (ret)
goto err_sysfs;
ret = ff_dummy_open(0);
if (ret)
goto err_open;
printk(KERN_NOTICE "Dummy force feedback module loaded.\n");
return 0;
err_open:
sysfs_remove_group(ff_dummy_kobj, &attrs_grp);
err_sysfs:
kfree(ff_dummy_devices);
err_alloc:
kobject_put(ff_dummy_kobj);
return ret;
}
module_param_named(max_device_count, max_device_count, int, S_IRUGO);
MODULE_PARM_DESC(max_device_count, "Maximum number of dummy devices that can be created simultaneously.");
module_exit(ff_dummy_exit);
module_init(ff_dummy_init);
EDIT:
The scheduling problem might have been a false lead. The only thing I am certain about is that the crash happens deep inside input_register_device(). "in_atomic()" and "in_interrupt()" return 0.
EDIT:
Solved. The actual bug was caused by a double free error in the underlying ff-logitech module and incorrect allocation of "struct ff_dummy_device *" instead of "struct ff_dummy_device".
the function work ok while i checked it with debuging but after the function finish the array is empty
this is the structs:
typedef struct coordinates
{
int x_l;
int y_l;
int x_r;
int y_r;
} Coordinates;
typedef struct field
{
int Id;
Coordinates location;
int area;
int price;
} Field;
this is the function:
int ReadFromFile(Field *pArr)
{
int size;
int i;
FILE *f = fopen("c:\\migrashim\\migrashim.txt", "r");
if (f == NULL)
{
printf("error open file");
exit (1);
}
fseek(f,0,SEEK_SET);
fscanf(f, "%d\n", &size);
pArr=(Field*)realloc(pArr,sizeof(Field)*(size));
for (i=0 ; i<size ; i++)
{
fscanf(f, "%d\n", &pArr[i].Id);
fscanf(f, "%d %d\n", &pArr[i].location.x_l,&pArr[i].location.y_l);
fscanf(f, "%d %d\n", &pArr[i].location.x_r,&pArr[i].location.y_r);
}
return size;
}
and this is the calling from the main:
{
counter_2=ReadFromFile(pFieldArr);
printf("\nFile loaded successfully!");
New_Field_flag=0;
Exit=0;
break;
}
tnx guys...
You're passing a pointer into ReadFromFile and resizing.
That realloc will try to resize in-place, but if it can't, it'll allocate a new block, copy the existing data, and then free the old block.
Your function doesn't take into account that the block may have moved (you're not returning the pointer which returned by realloc).
EDIT:
The code should look something like this:
int ReadFromFile(Field **pArr)
{
int size;
int i;
FILE *f = fopen("c:\\migrashim\\migrashim.txt", "r");
if (f == NULL)
{
printf("error open file");
exit (1);
}
fscanf(f, "%d\n", &size);
*pArr = (Field*)realloc(*pArr, sizeof(Field)* size);
for (i = 0; i < size; i++)
{
fscanf(f, "%d\n", &(*pArr)[i].Id);
fscanf(f, "%d %d\n", &(*pArr)[i].location.x_l, &(*pArr)[i].location.y_l);
fscanf(f, "%d %d\n", &(*pArr)[i].location.x_r, &(*pArr)[i].location.y_r);
}
fclose(f);
return size;
}
and then:
{
counter_2 = ReadFromFile(&pFieldArr);
printf("\nFile loaded successfully!");
New_Field_flag = 0;
Exit = 0;
break;
}