Commit ef9aa57f authored by Alessandro Rubini's avatar Alessandro Rubini Committed by Aurelio Colosimo

tools: new dir with ptpdump program

parent ff2cf609
# classic cross-compilation tool-set
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
CFLAGS = -Wall -ggdb -I../include/pptp
PROGS = ptpdump
all: $(PROGS)
$(PROGS): $(wildcard *.h) $(wildcard ../include/pptp/*.h)
%: %.c
$(CC) $(CFLAGS) $*.c $(LDFLAGS) -o $@
clean:
rm -f $(PROGS) *.o *~
/* copied from /usr/include/netinet/ip.h */
#if __BYTE_ORDER == __LITTLE_ENDIAN
#elif __BYTE_ORDER == __BIG_ENDIAN
# error "big endian not supported, yet"
#else
# error "Please fix <bits/endian.h>"
#endif
/* Common Message header (table 18, page 124) -- was "MsgHeader */
struct ptp_header {
/* 0 */
unsigned int messageType:4;
unsigned int transportSpecific:4;
/* 1 */
unsigned int versionPTP:4;
unsigned int reserved1:4;
/* 2 */
uint16_t messageLength;
/* 4 */
uint8_t domainNumber;
uint8_t reserved5;
uint16_t flagField;
/* 8 */
uint64_t correctionField;
/* 16 */
uint32_t reserved16;
uint8_t sourcePortIdentity[10];
/* 30 */
uint16_t sequenceId;
uint8_t controlField;
uint8_t logMessageInterval;
} __attribute__((packed));
/* Fucking fucking ieee specification! */
struct int48 {
uint16_t msb; /* big endian in packet! */
uint32_t lsb;
} __attribute__((packed));
struct stamp {
struct int48 sec;
uint32_t nsec;
} __attribute__((packed));
/*
* What follows is structures for the individual message types
*/
struct ptp_announce { /* page 129 (149 of pdf) */
struct stamp originTimestamp; /* 34 */
Integer16 currentUtcOffset; /* 44 */
uint8_t reserved46;
UInteger8 grandmasterPriority1; /* 47 */
ClockQuality grandmasterClockQuality; /* 48 */
UInteger8 grandmasterPriority2; /* 52 */
ClockIdentity grandmasterIdentity; /* 53 */
UInteger16 stepsRemoved; /* 61 */
Enumeration8 timeSource; /* 63 */
} __attribute__((packed));
struct ptp_sync_etc { /* page 130 (150 of pdf) */
/* doc uses different names in different packets: use simple names */
struct stamp stamp; /* 34 */
uint8_t port[10]; /* 44: only for delay_resp etc */
};
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <linux/if_ether.h>
#include <net/if_arp.h>
#include <netpacket/packet.h>
#include <ieee1588_types.h> /* from ../include/pptp */
#include "decent_types.h"
#ifndef ETH_P_1588
#define ETH_P_1588 0x88F7
#endif
int dumpstruct(FILE *dest, char *name, void *ptr, int size)
{
int ret, i;
unsigned char *p = ptr;
ret = fprintf(dest, "DUMP: %s at %p (size %i)\n",
name, ptr, size);
for (i = 0; i < size; ) {
if ((i & 0xf) == 0)
ret += fprintf(dest, "DUMP: ");
ret += fprintf(dest, "%02x", p[i]);
i++;
ret += fprintf(dest, i & 3 ? " " : i & 0xf ? " " : "\n");
}
if (i & 0xf)
ret += fprintf(dest, "\n");
return ret;
}
static void dump_eth(struct ethhdr *eth)
{
struct timeval tv;
struct tm tm;
unsigned char *d = eth->h_dest;
unsigned char *s = eth->h_source;
gettimeofday(&tv, NULL);
localtime_r(&tv.tv_sec, &tm);
printf("TIME: (%li - 0x%lx) %02i:%02i:%02i.%06li\n",
tv.tv_sec, tv.tv_sec,
tm.tm_hour, tm.tm_min, tm.tm_sec, (long)tv.tv_usec);
printf("ETH: %04x (%02x:%02x:%02x:%02x:%02x:%02x -> "
"%02x:%02x:%02x:%02x:%02x:%02x)\n", ntohs(eth->h_proto),
s[0], s[1], s[2], s[3], s[4], s[5],
d[0], d[1], d[2], d[3], d[4], d[5]);
}
static void dump_ip(struct iphdr *ip)
{
uint32_t s = ntohl(ip->saddr);
uint32_t d = ntohl(ip->daddr);
printf("IP: %i (%i.%i.%i.%i -> %i.%i.%i.%i) len %i\n",
ip->protocol,
(s >> 24) & 0xff, (s >> 16) & 0xff, (s >> 8) & 0xff, s & 0xff,
(d >> 24) & 0xff, (d >> 16) & 0xff, (d >> 8) & 0xff, d & 0xff,
ntohs(ip->tot_len));
}
static void dump_udp(struct udphdr *udp)
{
printf("UDP: (%i -> %i) len %i\n",
ntohs(udp->source), ntohs(udp->dest), ntohs(udp->len));
}
/* Helpers for fucking data structures */
static void dump_1stamp(char *s, struct stamp *t)
{
uint64_t sec = (uint64_t)(ntohs(t->sec.msb)) << 32;
sec |= (uint64_t)(ntohl(t->sec.lsb));
printf("%s%lli.%09i\n", s, sec, ntohl(t->nsec));
}
static void dump_1quality(char *s, ClockQuality *q)
{
printf("%s%02x-%02x-%04x\n", s, q->clockClass, q->clockAccuracy,
q->offsetScaledLogVariance);
}
static void dump_1clockid(char *s, ClockIdentity i)
{
printf("%s%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", s,
i[0], i[1], i[2], i[3], i[4], i[5], i[6], i[7]);
}
static void dump_1port(char *s, unsigned char *p)
{
printf("%s%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", s,
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
}
/* Helpers for each message types */
static void dump_msg_announce(struct ptp_announce *p)
{
dump_1stamp("MSG-ANNOUNCE: stamp ", &p->originTimestamp);
dump_1quality("MSG-ANNOUNCE: grandmaster-quality ",
&p->grandmasterClockQuality);
printf("MSG-ANNOUNCE: grandmaster-prio %i %i\n",
p->grandmasterPriority1, p->grandmasterPriority2);
dump_1clockid("MSG-ANNOUNCE: grandmaster-id ",
p->grandmasterIdentity);
}
static void dump_msg_sync_etc(char *s, struct ptp_sync_etc *p)
{
dump_1stamp(s, &p->stamp);
}
static void dump_msg_resp_etc(char *s, struct ptp_sync_etc *p)
{
dump_1stamp(s, &p->stamp);
dump_1port(s, p->port);
}
/* A big function to dump the ptp information */
static void dump_payload(void *pl, int len)
{
struct ptp_header *h = pl;
void *msg_specific = (void *)(h + 1);
if (h->versionPTP != 2) {
printf("VERSION: unsupported (%i)\n", h->versionPTP);
return;
}
printf("VERSION: %i (type %i, len %i, domain %i)\n",
h->versionPTP, h->messageType,
ntohs(h->messageLength), h->domainNumber);
printf("FLAGS: 0x%04x (correction 0x%08llx)\n", h->flagField,
h->correctionField);
dump_1port("PORT: ", h->sourcePortIdentity);
printf("REST: seq %i, ctrl %i, log-interval %i\n",
ntohs(h->sequenceId), h->controlField, h->logMessageInterval);
#define CASE(t, x) case PPM_ ##x: printf("MESSAGE: (" #t ") " #x "\n")
switch(h->messageType) {
CASE(E, SYNC);
dump_msg_sync_etc("MSG-SYNC: ", msg_specific);
break;
CASE(E, DELAY_REQ);
dump_msg_sync_etc("MSG-DELAY_REQ: ", msg_specific);
break;
CASE(E, PDELAY_REQ);
dump_msg_sync_etc("MSG-PDELAY_REQ: ", msg_specific);
break;
CASE(E, PDELAY_RESP);
dump_msg_resp_etc("MSG-PDELAY_RESP: ", msg_specific);
break;
CASE(G, FOLLOW_UP);
dump_msg_sync_etc("MSG-FOLLOW_UP: ", msg_specific);
break;
CASE(G, DELAY_RESP);
dump_msg_resp_etc("MSG-DELAY_RESP: ", msg_specific);
break;
CASE(G, PDELAY_RESP_FOLLOW_UP);
dump_msg_resp_etc("MSG-PDELAY_RESP_FOLLOWUP: ", msg_specific);
break;
CASE(G, ANNOUNCE);
dump_msg_announce(msg_specific);
break;
CASE(G, SIGNALING);
/* FIXME */
break;
CASE(G, MANAGEMENT);
/* FIXME */
break;
}
/* Finally, binary dump of it all */
dumpstruct(stdout, "payload", pl, len);
}
static int dump_udppkt(void *buf, int len)
{
struct ethhdr *eth = buf;
struct iphdr *ip = buf + ETH_HLEN;
struct udphdr *udp = (void *)(ip + 1);
void *payload = (void *)(udp + 1);
int udpdest = ntohs(udp->dest);
static unsigned char prev[256];
static int prevlen;
if (len < ETH_HLEN + sizeof(*ip) + sizeof(*udp))
return -1;
/* page 239 and following */
if (udpdest != 319 && udpdest != 320)
return -1;
/* for some reasons, we receive it three times, check dups */
if (len == prevlen && !memcmp(buf, prev, len))
return -1;
memcpy(prev, buf, len); prevlen = len;
dump_eth(eth);
dump_ip(ip);
dump_udp(udp);
dump_payload(payload, len - (payload - buf));
putchar('\n');
return 0;
}
static int dump_1588pkt(void *buf, int len)
{
struct ethhdr *eth = buf;
void *payload = (void *)(eth + 1);
dump_eth(eth);
dump_payload(payload, len - (payload - buf));
putchar('\n');
return 0;
}
int main(int argc, char **argv)
{
int sock;
struct packet_mreq req;
struct ifreq ifr;
char *ifname = "eth0";
sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock < 0) {
fprintf(stderr, "%s: socket(): %s\n", argv[0], strerror(errno));
exit(1);
}
if (argc > 1)
ifname = argv[1];
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ifname);
if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
fprintf(stderr, "%s: ioctl(GETIFINDEX(%s)): %s\n", argv[0],
ifname, strerror(errno));
exit(1);
}
fprintf(stderr, "Dumping PTP packets from interface \"%s\"\n", ifname);
memset(&req, 0, sizeof(req));
req.mr_ifindex = ifr.ifr_ifindex;
req.mr_type = PACKET_MR_PROMISC;
if (setsockopt(3, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
&req, sizeof(req)) < 0) {
fprintf(stderr, "%s: set promiscuous(%s): %s\n", argv[0],
ifname, strerror(errno));
exit(1);
}
/* Ok, now we are promiscuous. Just read stuff forever */
while(1) {
struct ethhdr *eth;
struct iphdr *ip;
unsigned char buf[10000];
struct sockaddr_in from;
socklen_t fromlen = sizeof(from);
int len;
len = recvfrom(sock, buf, 10000, MSG_TRUNC,
(struct sockaddr *) &from, &fromlen);
/* now only print ptp packets */
if (len < ETH_HLEN)
continue;
eth = (void *)buf;
ip = (void *)(buf + ETH_HLEN);
switch(ntohs(eth->h_proto)) {
case ETH_P_IP:
if (len < ETH_HLEN + sizeof(*ip))
continue;
if (ip->protocol != IPPROTO_UDP)
continue;
dump_udppkt(buf, len);
break;
case ETH_P_1588:
dump_1588pkt(buf, len);
break;
default:
continue;
}
fflush(stdout);
}
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment