pull/29/merge
ajneu 2017-05-03 02:32:23 +00:00 committed by GitHub
commit c9750774fe
1 changed files with 121 additions and 7 deletions

128
candump.c
View File

@ -61,6 +61,7 @@
#include <linux/can.h>
#include <linux/can/raw.h>
#include <linux/rtnetlink.h>
#include "terminal.h"
#include "lib.h"
@ -103,6 +104,11 @@ extern int optind, opterr, optopt;
static volatile int running = 1;
struct netlink_struc {
int s;
struct sockaddr_nl saddr;
};
void print_usage(char *prg)
{
fprintf(stderr, "\nUsage: %s [options] <CAN interface>+\n", prg);
@ -120,6 +126,8 @@ void print_usage(char *prg)
fprintf(stderr, " -L (use log file format on stdout)\n");
fprintf(stderr, " -n <count> (terminate after receiption of <count> CAN frames)\n");
fprintf(stderr, " -r <size> (set socket receive buffer to <size>)\n");
fprintf(stderr, " -R (Report down-and-up-again status for \"detected\" devices.\n");
fprintf(stderr, " For any device that is only matched via \"any\": Such a device is only \"detected\", once you have received at least one frame from that device.\n");
fprintf(stderr, " -D (Don't exit if a \"detected\" can device goes down.\n");
fprintf(stderr, " -d (monitor dropped CAN frames)\n");
fprintf(stderr, " -e (dump CAN error frames in human-readable format)\n");
@ -152,6 +160,20 @@ void sigterm(int signo)
running = 0;
}
// idx of "detected" devices is cached
int is_idx_cached(int ifidx) {
int cached = 0;
int i;
for (i = 0; i < MAXIFNAMES; i++) {
if (dindex[i] == ifidx) {
cached = 1;
break;
}
}
return cached;
}
int idx2dindex(int ifidx, int socket) {
int i;
@ -201,6 +223,69 @@ int idx2dindex(int ifidx, int socket) {
return i;
}
// http://git.pengutronix.de/?p=tools/libsocketcan.git;a=blob;f=src/libsocketcan.c;hb=HEAD
static int send_dump_request(int fd, int family, int type)
{
struct get_req {
struct nlmsghdr n;
struct rtgenmsg g;
} req = {
.n = {
.nlmsg_len = sizeof(req),
.nlmsg_type = type,
.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH,
.nlmsg_pid = 0,
.nlmsg_seq = 0
},
.g = {
.rtgen_family = family
}
};
return send(fd, &req, sizeof(req), 0);
}
/* altern:
void netlink_getlink(int nsock) from
http://centaur.sch.bme.hu/~leait/projects/openwrt/
http://centaur.sch.bme.hu/~leait/projects/openwrt/files/sample.c
*/
static void handle_netlink_socket(struct netlink_struc *netlink_s, unsigned char down_causes_exit, unsigned char report_down_up)
{
char buf[4096];
struct iovec iov = { buf, sizeof(buf) };
struct msghdr msg = { &netlink_s->saddr, sizeof(netlink_s->saddr), &iov, 1, NULL, 0, 0 };
int len = recvmsg(netlink_s->s, &msg, 0);
struct nlmsghdr *nh;
for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len); nh = NLMSG_NEXT (nh, len)) {
if (nh->nlmsg_type == NLMSG_DONE){
break;
}
if (nh->nlmsg_type == NLMSG_ERROR)
continue;
if (nh->nlmsg_type == RTM_NEWLINK) {
struct ifinfomsg *rtif = NLMSG_DATA(nh);
if (is_idx_cached(rtif->ifi_index)) {
char ifname[IF_NAMESIZE];
const int will_exit = (down_causes_exit && !(rtif->ifi_flags&IFF_RUNNING));
if_indextoname(rtif->ifi_index, ifname);
if (report_down_up || will_exit) {
printf("# %*s is %s\n", max_devname_len, ifname,
(rtif->ifi_flags&IFF_RUNNING) ? "up" : "down");
fflush(stdout);
}
if (will_exit) {
exit(1);
}
}
}
}
}
int main(int argc, char **argv)
{
fd_set rdfs;
@ -209,6 +294,7 @@ int main(int argc, char **argv)
useconds_t bridge_delay = 0;
unsigned char timestamp = 0;
unsigned char down_causes_exit = 1;
unsigned char report_down_up = 0;
unsigned char dropmonitor = 0;
unsigned char extra_msg_info = 0;
unsigned char silent = SILENT_INI;
@ -236,6 +322,7 @@ int main(int argc, char **argv)
struct timeval tv, last_tv;
struct timeval timeout, timeout_config = { 0, 0 }, *timeout_current = NULL;
FILE *logfile = NULL;
struct netlink_struc netlink_s;
signal(SIGTERM, sigterm);
signal(SIGHUP, sigterm);
@ -244,7 +331,7 @@ int main(int argc, char **argv)
last_tv.tv_sec = 0;
last_tv.tv_usec = 0;
while ((opt = getopt(argc, argv, "t:ciaSs:b:B:u:lDdxLn:r:heT:?")) != -1) {
while ((opt = getopt(argc, argv, "t:ciaSs:b:B:u:lDdxLn:Rr:heT:?")) != -1) {
switch (opt) {
case 't':
timestamp = optarg[0];
@ -363,6 +450,10 @@ int main(int argc, char **argv)
}
break;
case 'R':
report_down_up = 1;
break;
case 'T':
errno = 0;
timeout_config.tv_usec = strtol(optarg, NULL, 0);
@ -399,9 +490,22 @@ int main(int argc, char **argv)
silent = SILENT_OFF; /* default output */
}
// netlink to determine down/up
netlink_s.s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
netlink_s.saddr.nl_family = AF_NETLINK;
netlink_s.saddr.nl_groups = RTMGRP_LINK;
if (bind(netlink_s.s, (struct sockaddr *)&netlink_s.saddr, sizeof(netlink_s.saddr)) < 0) {
perror("netlink bind");
return 1;
}
if (send_dump_request(netlink_s.s, AF_PACKET, RTM_GETLINK) < 0) {
perror("Cannot send dump request");
return 1;
}
currmax = argc - optind; /* find real number of CAN devices */
if (currmax > MAXSOCK) {
if (currmax > MAXSOCK-1) { // minus one: one socket already used for netlink
fprintf(stderr, "More than %d CAN devices given on commandline!\n", MAXSOCK);
return 1;
}
@ -451,6 +555,7 @@ int main(int argc, char **argv)
exit(1);
}
addr.can_ifindex = ifr.ifr_ifindex;
idx2dindex(addr.can_ifindex, s[i]);
} else
addr.can_ifindex = 0; /* any can interface */
@ -623,6 +728,7 @@ int main(int argc, char **argv)
while (running) {
FD_ZERO(&rdfs);
FD_SET(netlink_s.s, &rdfs);
for (i=0; i<currmax; i++)
FD_SET(s[i], &rdfs);
@ -635,6 +741,10 @@ int main(int argc, char **argv)
continue;
}
// check netlink socket
if (FD_ISSET(netlink_s.s, &rdfs))
handle_netlink_socket(&netlink_s, down_causes_exit, report_down_up);
for (i=0; i<currmax; i++) { /* check all CAN RAW sockets */
if (FD_ISSET(s[i], &rdfs)) {
@ -651,14 +761,17 @@ int main(int argc, char **argv)
idx = idx2dindex(addr.can_ifindex, s[i]);
if (nbytes < 0) {
if ((errno == ENETDOWN) && !down_causes_exit) {
fprintf(stderr, "%s: interface down\n", devname[idx]);
continue;
if (errno == ENETDOWN) {
if (down_causes_exit) {
printf("# %*s is down!\n", max_devname_len, devname[idx]);
} else {
continue;
}
} else {
perror("read");
}
perror("read");
return 1;
}
if ((size_t)nbytes == CAN_MTU)
maxdlen = CAN_MAX_DLEN;
else if ((size_t)nbytes == CANFD_MTU)
@ -810,6 +923,7 @@ int main(int argc, char **argv)
}
}
close(netlink_s.s);
for (i=0; i<currmax; i++)
close(s[i]);