Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
/* Typical use: "wr-dio-agent wr1" */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include "wr_nic/wr-nic.h"
#include "wr-dio.h"
#define RULER_PROTO 0x5752 /* WR */
/*
* Lazily, use global variables, so the code has less parameter passing.
* Everything in this file is using "agent_" as a prefix, to ease the
* reader -- and remember that <TAB> aligns at 8 spaces, not 4.
*/
char *agent_prgname;
int agent_sock;
char *agent_ifname;
struct ifreq agent_ifr;
/* Boring network stuff extracted from main function */
static int agent_open_wr_sock(char *name)
{
struct sockaddr_ll addr;
int sock, ifindex;
sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sock < 0) {
fprintf(stderr, "%s: socket(): %s\n",
agent_prgname, strerror(errno));
return -1;
}
memset(&agent_ifr, 0, sizeof(agent_ifr));
strncpy(agent_ifr.ifr_name, name, sizeof(agent_ifr.ifr_name));
if (ioctl(sock, PRIV_MEZZANINE_ID, &agent_ifr) < 0
/* EAGAIN is special: it means we have no ID to check yet */
&& errno != EAGAIN) {
fprintf(stderr, "%s: ioctl(PRIV_MEZZANINE_ID(%s)): %s\n",
agent_prgname, name, strerror(errno));
close(sock);
return -1;
}
/* Retieve the interfaceindex */
if (ioctl(sock, SIOCGIFINDEX, &agent_ifr) < 0) {
fprintf(stderr, "%s: SIOCGIFINDEX(%s): %s\n", agent_prgname,
name, strerror(errno));
close(sock);
return -1;
}
ifindex = agent_ifr.ifr_ifindex;
/* Bind to the interface, so to be able to receive */
memset(&addr, 0, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_protocol = htons(RULER_PROTO);
addr.sll_ifindex = ifindex;
addr.sll_pkttype = PACKET_BROADCAST; /* that's what ruler sends */
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
fprintf(stderr, "%s: bind(%s): %s\n", agent_prgname,
name, strerror(errno));
close(sock);
return -1;
}
/* save in globals for later */
agent_sock = sock;
return 0;
}
/* And a simple main with the loop inside */
int main(int argc, char **argv)
{
int len;
/* We are receiving stuff in this frame */
static struct frame {
struct ether_header h;
unsigned char pad[2];
struct wr_dio_cmd cmd;
} f;
if (argc != 2) {
fprintf(stderr, "%s: Use \"%s <wr-if>\"\n",
argv[0], argv[0]);
exit(1);
}
agent_prgname = argv[0];
/* All functions print error messages by themselves, so just exit */
if (agent_open_wr_sock(argv[1]) < 0)
exit(1);
while (1) {
len = recv(agent_sock, &f, sizeof(f), MSG_TRUNC);
if (len != sizeof(f)) {
fprintf(stderr, "%s: recevied unexpected frame length"
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
sizeof(f));
continue;
}
if (ntohs(f.h.ether_type) != RULER_PROTO) {
fprintf(stderr, "%s: received unexpected eth type"
" (%04x instead of %04x)\n", agent_prgname,
ntohs(f.h.ether_type), RULER_PROTO);
continue;
}
if (0)
printf("command %i, ch %i, t %li.%09li\n",
f.cmd.command, f.cmd.channel, f.cmd.t[0].tv_sec,
f.cmd.t[0].tv_nsec);
/* Then simply pass it to the hardware */
agent_ifr.ifr_data = (void *)&f.cmd;
if (ioctl(agent_sock, PRIV_MEZZANINE_CMD, &agent_ifr) < 0) {
fprintf(stderr, "%s: ioctl(PRIV_MEZZANINE_CMD(%s)): "
"%s\n", agent_prgname, agent_ifname,
strerror(errno));
return -1;
}
}
exit(0);
}