From: Radek Matějka Date: Fri, 8 Feb 2013 22:44:01 +0000 (-0600) Subject: support for ipv6 added X-Git-Url: http://rtime.felk.cvut.cz/gitweb/can-eth-gw.git/commitdiff_plain/b4fd40efa92a6a967f196b9f3eb6fdd67c8f2af2 support for ipv6 added --- diff --git a/can-utils b/can-utils index 0d6378d..7081955 160000 --- a/can-utils +++ b/can-utils @@ -1 +1 @@ -Subproject commit 0d6378dffe86fecbbb5b02c4c59a3e1b01fcff75 +Subproject commit 7081955244c944791c05eab1fb7440c26038575c diff --git a/kernel/canethgw.c b/kernel/canethgw.c index d5b0302..36da707 100644 --- a/kernel/canethgw.c +++ b/kernel/canethgw.c @@ -26,21 +26,22 @@ MODULE_LICENSE("GPL"); static int cegw_udp2can(void *data); static int cegw_udp_send(struct socket *udp_sock, struct can_frame *cf, - struct sockaddr_in* addr); + struct sockaddr* addr, int addrlen); static int cegw_can2udp(void *data); static int cegw_can_send(struct socket *can_sock, struct can_frame *cf); static int cegw_thread_start(void *data); static int cegw_thread_stop(struct cegw_job *job); static void cegw_job_release(struct kref *ref); -static int cegw_udp_send(struct socket *udp_sock, struct can_frame *cf, struct sockaddr_in* addr) +static int cegw_udp_send(struct socket *udp_sock, struct can_frame *cf, struct sockaddr *addr, + int addrlen) { struct msghdr mh; struct kvec vec; int err; mh.msg_name = addr; - mh.msg_namelen = sizeof(*addr); + mh.msg_namelen = addrlen; mh.msg_control = NULL; mh.msg_controllen = 0; mh.msg_flags = 0; @@ -117,6 +118,7 @@ static int cegw_can2udp(void* data) { struct msghdr mh; struct kvec vec; + struct sockaddr *udst; struct can_frame cf; struct cegw_job* job = (struct cegw_job*)data; struct socket* udp_sock = job->udp_sock; @@ -137,7 +139,8 @@ static int cegw_can2udp(void* data) cf.can_id = cpu_to_be32(cf.can_id); for (i=0; iudp_dstcnt; i++) { - cegw_udp_send(udp_sock, &cf, &job->udp_dst[i]); + udst = (struct sockaddr *)(job->udp_dst + i*job->udp_addrlen); + cegw_udp_send(udp_sock, &cf, udst, job->udp_addrlen); } } @@ -242,9 +245,11 @@ static int cegw_release(struct inode *inode, struct file *file) static long cegw_ioctl_start(struct file *file, unsigned long arg) { int i; + int chckfam; int err = 0; __u32 dstcnt = 0; __u32 addrlen = 0; + struct sockaddr *sa; struct cegw_ioctl gwctl; struct cegw_job *job = NULL; @@ -255,11 +260,11 @@ static long cegw_ioctl_start(struct file *file, unsigned long arg) dstcnt = gwctl.udp_dstcnt; addrlen = gwctl.udp_addrlen; - if (addrlen != sizeof(struct sockaddr_in)) + if (addrlen != sizeof(struct sockaddr_in) && addrlen != sizeof(struct sockaddr_in6)) return -EAFNOSUPPORT; - /* */ - job = kmalloc(GFP_KERNEL, sizeof(*job) + dstcnt*addrlen ); + /* ToDo: consider dstcnt maximum */ + job = kmalloc(GFP_KERNEL, sizeof(*job) + dstcnt*addrlen); if (job == NULL) return -ENOMEM; @@ -269,8 +274,14 @@ static long cegw_ioctl_start(struct file *file, unsigned long arg) return -EFAULT; } - for (i=0; iudp_dst[i].sin_family != AF_INET) { + /* */ + if (dstcnt > 0) + sa = (struct sockaddr *)job->udp_dst; + chckfam = sa->sa_family; + + for (i=1; iudp_dst + i*addrlen); + if (sa->sa_family != chckfam) { kfree(job); return -EAFNOSUPPORT; } @@ -290,6 +301,7 @@ static long cegw_ioctl_start(struct file *file, unsigned long arg) } job->udp_dstcnt = dstcnt; + job->udp_addrlen = addrlen; err = cegw_thread_start(job); if (err != 0) diff --git a/kernel/canethgw.h b/kernel/canethgw.h index 65d9cc5..ab1b6c1 100644 --- a/kernel/canethgw.h +++ b/kernel/canethgw.h @@ -9,7 +9,7 @@ struct cegw_ioctl __u32 udp_sock; __u32 udp_dstcnt; __u32 udp_addrlen; - struct sockaddr_in udp_dst[0]; + __u8 udp_dst[0]; }; #ifdef __KERNEL__ @@ -18,8 +18,9 @@ struct cegw_job struct kref refcount; struct socket* can_sock; struct socket* udp_sock; - __u32 udp_dstcnt; - struct sockaddr_in udp_dst[0]; + u32 udp_dstcnt; + u32 udp_addrlen; + u8 udp_dst[0]; }; #endif diff --git a/utils/cegw/cegw.c b/utils/cegw/cegw.c index feb083a..0036dbb 100644 --- a/utils/cegw/cegw.c +++ b/utils/cegw/cegw.c @@ -32,23 +32,6 @@ unsigned int cegw_errno = 0; -enum { - CEGW_ERR_UNKNOWN, - CEGW_ERR_COLON, - CEGW_ERR_GETADDRI, - CEGW_ERR_FLTALCK, - CEGW_ERR_FLTPARSE -}; - -char *cegw_errlist[] = { - - [CEGW_ERR_UNKNOWN ] = "", - [CEGW_ERR_COLON ] = "expected ':' (:)", - [CEGW_ERR_GETADDRI] = "getaddrinfo failed", - [CEGW_ERR_FLTALCK ] = "filter alloc failed", - [CEGW_ERR_FLTPARSE] = "filter parsing failed" -}; - static const char help_msg[] = "usage:\n" " %s [,filter]* : :\n" " [list of additional udp recipients :]\n" @@ -61,26 +44,10 @@ static const char help_msg[] = "usage:\n" " therefore cloned. Notice that there can be more udp recipients.\n" " The can filter is specified in the same way as in candump utility.\n"; -const struct addrinfo hints = { - .ai_family = AF_INET, +struct addrinfo hints = { .ai_socktype = SOCK_DGRAM }; -static void perr(char *s) -{ - if (s) { - if (cegw_errno == 0) { - fprintf(stderr, "error: %s\n", s); - - } else { - fprintf(stderr, "error: %s, %s\n", s, cegw_errlist[cegw_errno]); - } - return; - } - - fprintf(stderr, "error: %s\n", cegw_errlist[cegw_errno]); -} - /** * readsockaddr - parses @in for eth address. * Valid input is e.g. 127.0.0.1:10502. If parsing fails @@ -91,7 +58,7 @@ static void perr(char *s) * @param[out] addr filled sockaddr_in structure * @return 0 on success, -1 otherwise */ -int readsockaddr(char *arg, struct sockaddr_in *addr) +int readsockaddr(char *arg, struct sockaddr *addr, int ai_family) { int ret; char *delim; @@ -100,21 +67,22 @@ int readsockaddr(char *arg, struct sockaddr_in *addr) delim = strchr(arg, ':'); if (delim == NULL) { - cegw_errno = CEGW_ERR_COLON; - return -1; + fprintf(stderr, "expected ':' (:)"); + exit(1); } *delim = '\0'; delim++; + hints.ai_family = ai_family; + ret = getaddrinfo(arg, delim, &hints, &res); if (ret != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret)); - cegw_errno = CEGW_ERR_GETADDRI; - return -1; + fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(ret)); + exit(1); } - memcpy(addr, res->ai_addr, sizeof(*addr)); + memcpy(addr, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); return 0; @@ -139,8 +107,8 @@ int readfilter(char *nptr, struct can_filter **filter, int *out_numfilter, can_e rfilter = malloc(numfilter * sizeof(*rfilter)); if (!rfilter) { - cegw_errno = CEGW_ERR_FLTALCK; - return -1; + fprintf(stderr, "filter malloc failed"); + exit(1); } numfilter = 0; @@ -163,9 +131,8 @@ int readfilter(char *nptr, struct can_filter **filter, int *out_numfilter, can_e rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG; numfilter++; } else if (sscanf(ptr, "#%x", err_mask) != 1) { - cegw_errno = CEGW_ERR_FLTPARSE; - free(rfilter); - return -1; + fprintf(stderr, "filter parsing failed"); + exit(1); } } @@ -183,27 +150,31 @@ int main(int argc, char *argv[]) char *nptr; int numfilter = 0; int udp_sock, can_sock; + int addrlen; can_err_mask_t err_mask = 0; - struct sockaddr_in udp_addr; struct sockaddr_can can_addr; - struct sockaddr_in *dst = NULL; + struct sockaddr *dst = NULL; struct cegw_ioctl *gwctl = NULL; struct can_filter *filter = NULL; + /* udp_addr can store both - in and in6 addresses */ + struct sockaddr_in6 udp6_addr; + struct sockaddr *udp_addr = (struct sockaddr *) &udp6_addr; + + if (argc == 1) { printf(help_msg, argv[0], argv[0]); return 0; } if (argc < 4) { - perr("not enough arguments"); + fprintf(stderr, "not enough arguments\n"); printf(help_msg, argv[0], argv[0]); /* ToDo: print usage */ return 1; } dstcnt = argc-3; - gwctl = (struct cegw_ioctl*)malloc(sizeof(*gwctl) + (dstcnt)*sizeof(struct sockaddr_in)); for (i=1; isa_family) { + case AF_INET: + addrlen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + addrlen = sizeof(struct sockaddr_in6); + break; + default: + fprintf(stderr, "unexpected sockaddr family"); + break; } + gwctl = (struct cegw_ioctl*)malloc(sizeof(*gwctl) + dstcnt*addrlen); break; default: /* udp destination */ - dst = &gwctl->udp_dst[i-3]; - if (readsockaddr(argv[i], dst) != 0) { - perr("reading udp destination failed"); - free(gwctl); - return 1; - } + dst = (struct sockaddr *)(gwctl->udp_dst + (i-3)*addrlen); + readsockaddr(argv[i], dst, udp_addr->sa_family); + break; } } /* prepare udp socket */ - udp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + udp_sock = socket(udp_addr->sa_family, SOCK_DGRAM, IPPROTO_UDP); if (udp_sock == -1) { - perror("udp socket()"); - free(gwctl); + perror("udp socket(..)"); return 1; } - if (bind(udp_sock, (struct sockaddr *)&udp_addr, sizeof(struct sockaddr_in)) != 0) { + if (bind(udp_sock, udp_addr, addrlen) != 0) { perror("bind(udp)"); - free(gwctl); return 1; } /* prepare can socket */ can_sock = socket(PF_CAN, SOCK_RAW, CAN_RAW); if (can_sock == -1) { - perror("can socket()"); - free(gwctl); + perror("can socket(..)"); return 1; } if (bind(can_sock, (struct sockaddr *)&can_addr, sizeof(struct sockaddr_can)) != 0) { perror("bind(can)"); - free(gwctl); return 1; } /* can filter */ - if (nptr && (readfilter(nptr, &filter, &numfilter, &err_mask) != 0)) { - perr("can filter"); - free(gwctl); - return 1; - } + if (nptr) + readfilter(nptr, &filter, &numfilter, &err_mask); if (err_mask) setsockopt(can_sock, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, @@ -288,18 +257,16 @@ int main(int argc, char *argv[]) fd = open("/dev/canethgw", O_RDONLY); if (fd == -1) { perror("/dev/canethgw"); - free(gwctl); return 1; } gwctl->can_sock = can_sock; gwctl->udp_sock = udp_sock; gwctl->udp_dstcnt = dstcnt; - gwctl->udp_addrlen = sizeof(struct sockaddr_in); + gwctl->udp_addrlen = addrlen; if (ioctl(fd, CEGW_IOCTL_START, gwctl) != 0) { perror("ioctl"); - free(gwctl); return 1; } printf("gateway successfully set and running\n");