Hi Ulrich,
here are code sniplets for the cross routing idea, if you want to do it
with C-code - only if the cangw solution on the commandline does not
fit your needs for some reasons:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <fcntl.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/can/gw.h>
#define VERB(args...) (verbose ? printf(args) : 0)
(..)
int s; /* raw socket */
int nl; /* rtnetlink socket */
char candevice[IFNAMSIZ] = {0};
char appdevice[IFNAMSIZ] = {0};
(..)
/* netlink helpers */
#define NLMSG_TAIL(nmsg) \
((struct rtattr *)(((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
int alen)
{
int len = RTA_LENGTH(alen);
struct rtattr *rta;
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
fprintf(stderr, "addattr_l: message exceeded bound of %d\n",
maxlen);
return -1;
}
rta = NLMSG_TAIL(n);
rta->rta_type = type;
rta->rta_len = len;
memcpy(RTA_DATA(rta), data, alen);
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
return 0;
}
(..)
/* some helpers to handle the CAN interfaces */
int set_if_up(int s, char *name)
{
struct ifreq ifr;
int err;
/* get interface flags */
strcpy(ifr.ifr_name, name);
err = ioctl(s, SIOCGIFFLAGS, &ifr);
if (err < 0)
return err;
/* check if interface is currently up */
if (!(ifr.ifr_flags & IFF_UP)) {
strcpy(ifr.ifr_name, name);
ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
ioctl(s, SIOCSIFFLAGS, &ifr);
VERB("setting %s interface flags to UP\n", name);
} else
VERB("%s interface flags were already UP\n", name);
return 0;
}
int set_if_down(int s, char *name)
{
struct ifreq ifr;
int err;
/* get interface flags */
strcpy(ifr.ifr_name, name);
err = ioctl(s, SIOCGIFFLAGS, &ifr);
if (err < 0)
return err;
/* check if interface is currently down */
if (ifr.ifr_flags & IFF_UP) {
strcpy(ifr.ifr_name, name);
ifr.ifr_flags &= ~IFF_UP;
ioctl(s, SIOCSIFFLAGS, &ifr);
VERB("setting %s interface flags to DOWN\n", name);
} else
VERB("%s interface flags were already DOWN\n", name);
return 0;
}
/* some helpers to handle the CAN routing */
int config_routing(int nl, u_int32_t src, u_int32_t dst, int mode)
{
struct sockaddr_nl nladdr;
char rxbuf[8192]; /* netlink receive buffer */
struct {
struct nlmsghdr nh;
struct rtcanmsg rtcan;
char buf[200];
} req;
struct nlmsghdr *nlh;
struct nlmsgerr *rte;
int err = 0;
memset(&req, 0, sizeof(req));
req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
req.nh.nlmsg_type = mode;
req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtcanmsg));
req.nh.nlmsg_seq = 0;
req.rtcan.can_family = AF_CAN;
req.rtcan.gwtype = CGW_TYPE_CAN_CAN;
req.rtcan.flags = CGW_FLAGS_CAN_ECHO;
addattr_l(&req.nh, sizeof(req), CGW_SRC_IF, &src, sizeof(src));
addattr_l(&req.nh, sizeof(req), CGW_DST_IF, &dst, sizeof(dst));
memset(&nladdr, 0, sizeof(nladdr));
nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid = 0;
nladdr.nl_groups = 0;
err = sendto(nl, &req, req.nh.nlmsg_len, 0,
(struct sockaddr*)&nladdr, sizeof(nladdr));
if (err < 0) {
perror("netlink sendto");
return err;
}
/* clean netlink receive buffer */
bzero(rxbuf, sizeof(rxbuf));
/* Parse the requested netlink acknowledge return values. */
err = recv(nl, &rxbuf, sizeof(rxbuf), 0);
if (err < 0) {
perror("netlink recv");
return err;
}
nlh = (struct nlmsghdr *)rxbuf;
if (nlh->nlmsg_type != NLMSG_ERROR) {
fprintf(stderr, "unexpected netlink answer of type %d\n",
nlh->nlmsg_type);
return -EINVAL;
}
rte = (struct nlmsgerr *)NLMSG_DATA(nlh);
err = rte->error;
if (err < 0)
fprintf(stderr, "netlink error %d (%s)\n", err,
strerror(abs(err)));
return err;
}
int enable_routing(void)
{
int err = 0;
if (!routing_active) {
if (err = config_routing(nl, can_ifidx, app_ifidx,
RTM_NEWROUTE))
return err;
if (err = config_routing(nl, app_ifidx, can_ifidx,
RTM_NEWROUTE))
return err;
routing_active = 1;
}
return err;
}
int disable_routing(void)
{
int err = 0;
if (routing_active) {
if (err = config_routing(nl, can_ifidx, app_ifidx,
RTM_DELROUTE))
return err;
if (err = config_routing(nl, app_ifidx, can_ifidx,
RTM_DELROUTE))
return err;
routing_active = 0;
}
return err;
}
void sigterm(int signo)
{
running = 0;
if (app_ifidx)
disable_routing();
}
(..)
main() {
(..)
strcpy(ifr.ifr_name, candevice);
ioctl(s, SIOCGIFINDEX, &ifr);
addr.can_ifindex = can_ifidx = ifr.ifr_ifindex;
addr.can_family = AF_CAN;
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("raw bind");
exit(1);
}
/* make our VWNM device surely working */
ret = set_if_up(s, candevice);
if (ret)
return ret;
/* check if routing of CAN traffic for CAN applications is needed */
if (appdevice[0]) {
strcpy(ifr.ifr_name, appdevice);
ioctl(s, SIOCGIFINDEX, &ifr);
app_ifidx = ifr.ifr_ifindex;
/* app_ifidx is now our *indication* for routing facility */
if (app_ifidx) {
ret = set_if_up(s, appdevice);
if (ret)
return ret;
/* open netlink socket for acces to the CAN routing
tables */
if ((nl = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE))
< 0) {
perror("netlink socket");
exit(1);
}
}
}
(..)
exit:
if (app_ifidx)
disable_routing();
close(s);
return 0;
}
_______________________________________________
Socketcan-users mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/socketcan-users