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

Reply via email to