2 #include <netinet/ether.h>
3 #include <linux/if_packet.h>
5 #include <sys/socket.h>
14 #define NMRP_HDR_LEN 6
15 #define NMRP_OPT_LEN 4
16 #define NMRP_MAX_OPT 6
17 #define NMRP_MIN_PKT_LEN (sizeof(struct ether_header) + NMRP_HDR_LEN)
19 #define ETH_P_NMRP 0x0912
21 #define PACKED __attribute__((__packed__))
22 #define MAX_LOOP_RECV 1024
24 #define IS_OOO_CODE(x) (x == NMRP_C_CLOSE_REQ \
25 || x == NMRP_C_KEEP_ALIVE_REQ \
26 || x == NMRP_C_TFTP_UL_REQ)
28 extern int tftp_put(const char *filename, const char *ipaddr, uint16_t port);
29 extern int sock_set_rx_timeout(int fd, unsigned msec);
38 NMRP_C_KEEP_ALIVE_REQ = 6,
39 NMRP_C_KEEP_ALIVE_ACK = 7,
40 NMRP_C_TFTP_UL_REQ = 16
44 NMRP_O_MAGIC_NO = 0x0001,
45 NMRP_O_DEV_IP = 0x0002,
46 NMRP_O_DEV_REGION = 0x0004,
47 NMRP_O_FW_UP = 0x0101,
48 NMRP_O_ST_UP = 0x0102,
49 NMRP_O_FILE_NAME = 0x0181
69 struct nmrp_opt opts[6];
74 struct ether_header eh;
78 static void msg_update_len(struct nmrp_msg *msg)
81 msg->len = NMRP_HDR_LEN;
82 for (; i != msg->num_opts; ++i) {
83 msg->len += msg->opts[i].len;
87 static void msg_hton(struct nmrp_msg *msg)
91 msg->reserved = htons(msg->reserved);
92 msg->len = htons(msg->len);
94 for (; i != msg->num_opts; ++i) {
95 msg->opts[i].len = htons(msg->opts[i].len);
96 msg->opts[i].type = htons(msg->opts[i].type);
100 static void msg_hdr_ntoh(struct nmrp_msg *msg)
102 msg->reserved = ntohs(msg->reserved);
103 msg->len = ntohs(msg->len);
106 static int msg_ntoh(struct nmrp_msg *msg)
108 struct nmrp_opt *opt = msg->opts;
112 remaining = msg->len - NMRP_HDR_LEN;
114 while (remaining > 0) {
115 if (remaining < NMRP_OPT_LEN) {
116 fprintf(stderr, "malformed message (rem=%d)\n", remaining);
120 opt->type = ntohs(opt->type);
121 opt->len = ntohs(opt->len);
123 remaining -= opt->len;
129 static void msg_dump(struct nmrp_msg *msg)
131 struct nmrp_opt *opt;
132 int remain_len, len, i;
134 printf("res=0x%04x, code=0x%02x, id=0x%02x, len=%u", msg->reserved,
135 msg->code, msg->id, msg->len);
137 remain_len = msg->len - NMRP_HDR_LEN;
138 printf("%s\n", remain_len ? "" : " (no opts)");
142 while (remain_len > 0) {
144 printf(" opt type=%u, len=%u", opt->type, len);
145 for (i = 0; i != len - NMRP_OPT_LEN; ++i) {
150 printf("%02x ", ((char*)&opt->val)[i] & 0xff);
154 opt = (struct nmrp_opt*)(((char*)opt) + len);
158 static int intf_get_index_and_addr(int fd, const char *name, int *index,
163 memset(&ifr, 0, sizeof(ifr));
164 strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
166 if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
167 perror("ioctl(SIOCGIFINDEX)");
170 *index = ifr.ifr_ifindex;
172 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
173 perror("ioctl(SIOCGIFHWADDR)");
176 memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
181 static int pkt_send(int fd, struct sockaddr_ll *addr, struct nmrp_pkt *pkt)
183 size_t len = ntohs(pkt->msg.len) + sizeof(pkt->eh);
184 return sendto(fd, pkt, len, 0, (struct sockaddr*)addr, sizeof(*addr));
187 static int pkt_recv(int fd, struct nmrp_pkt *pkt)
189 struct sockaddr_ll from;
193 memset(pkt, 0, sizeof(*pkt));
194 bytes = recvfrom(fd, pkt, NMRP_MIN_PKT_LEN, MSG_PEEK,
195 (struct sockaddr*)&from, &addrlen);
198 if (errno == EAGAIN) {
201 perror("recvfrom(pkt)");
203 } else if (ntohs(pkt->eh.ether_type) != ETH_P_NMRP) {
205 } else if (bytes < NMRP_MIN_PKT_LEN) {
206 fprintf(stderr, "short packet (%zi bytes)\n", bytes);
210 msg_hdr_ntoh(&pkt->msg);
211 len = pkt->msg.len + sizeof(pkt->eh);
213 bytes = recvfrom(fd, pkt, len, MSG_DONTWAIT, NULL, NULL);
215 perror("recvfrom(msg)");
217 } else if (bytes != len) {
218 fprintf(stderr, "short message (%zi bytes)\n", len);
221 if (msg_ntoh(&pkt->msg) != 0) {
232 static int sock_bind_to_intf(int fd, const char *name)
236 strncpy(ifr.ifr_name, name, IFNAMSIZ - 1);
237 if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) {
238 perror("setsockopt(SO_BINDTODEVICE)");
245 //static const char *arg_filename = "EX2700-V1.0.1.8.img";
246 static unsigned arg_rx_timeout = 250;
247 static unsigned arg_ul_timeout = 60000;
248 static const char *arg_filename = "bad.img";
249 static const char *arg_ipaddr = "192.168.2.2";
250 static const char *arg_ipmask = "255.255.255.0";
251 static const char *arg_intf = "enp4s0";
252 static uint16_t arg_port = 69;
254 static uint8_t target[ETH_ALEN] = { 0xa4, 0x2b, 0x8c, 0x10, 0xc2, 0x96 };
256 static uint8_t target[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
259 static const char *spinner = "\\|/-";
261 int main(int argc, char **argv)
263 struct nmrp_pkt tx, rx;
264 struct sockaddr_ll addr;
265 uint8_t hwaddr[ETH_ALEN];
266 int i, fd, err, ulreqs, expect;
270 fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_NMRP));
276 if (intf_get_index_and_addr(fd, arg_intf, &addr.sll_ifindex, hwaddr)) {
280 if (sock_bind_to_intf(fd, arg_intf)) {
284 if (sock_set_rx_timeout(fd, arg_rx_timeout)) {
288 addr.sll_family = PF_PACKET;
289 //addr.sll_hatype = ARPHRD_ETHER;
290 //addr.sll_pkttype = PACKET_OTHERHOST;
291 addr.sll_protocol = htons(ETH_P_NMRP);
292 addr.sll_halen = ETH_ALEN;
293 memcpy(addr.sll_addr, target, ETH_ALEN);
295 memcpy(tx.eh.ether_shost, hwaddr, ETH_ALEN);
296 memcpy(tx.eh.ether_dhost, target, ETH_ALEN);
297 tx.eh.ether_type = htons(ETH_P_NMRP);
300 tx.msg.code = NMRP_C_ADVERTISE;
303 tx.msg.opts[0].type = NMRP_O_MAGIC_NO;
304 tx.msg.opts[0].len = NMRP_OPT_LEN + 4;
305 tx.msg.opts[0].val.magic[0] = 'N';
306 tx.msg.opts[0].val.magic[1] = 'T';
307 tx.msg.opts[0].val.magic[2] = 'G';
308 tx.msg.opts[0].val.magic[3] = 'R';
310 msg_update_len(&tx.msg);
316 printf("\rAdvertising NMRP server on %s ... %c", arg_intf, spinner[i]);
320 if (pkt_send(fd, &addr, &tx) < 0) {
325 err = pkt_recv(fd, &rx);
328 } else if (err == 1) {
336 expect = NMRP_C_CONF_REQ;
340 if (expect != NMRP_C_NONE && rx.msg.code != expect) {
341 fprintf(stderr, "Received code 0x%02x while waiting for 0x%02x!\n",
342 rx.msg.code, expect);
345 tx.msg.code = NMRP_C_NONE;
353 switch (rx.msg.code) {
354 case NMRP_C_CONF_REQ:
355 tx.msg.code = NMRP_C_CONF_ACK;
358 tx.msg.opts[0].type = NMRP_O_DEV_IP;
359 tx.msg.opts[0].len = NMRP_OPT_LEN + 2 * IP_LEN;
361 inet_aton(arg_ipaddr,
362 (struct in_addr*)tx.msg.opts[0].val.ip.addr);
363 inet_aton(arg_ipmask,
364 (struct in_addr*)tx.msg.opts[0].val.ip.mask);
366 tx.msg.opts[1].type = NMRP_O_FW_UP;
367 tx.msg.opts[1].len = NMRP_OPT_LEN;
369 expect = NMRP_C_TFTP_UL_REQ;
371 printf("Configuration request received from "
372 "%02x:%02x:%02x:%02x:%02x:%02x.\n",
373 rx.eh.ether_shost[0], rx.eh.ether_shost[1],
374 rx.eh.ether_shost[2], rx.eh.ether_shost[3],
375 rx.eh.ether_shost[4], rx.eh.ether_shost[5]);
376 printf("Sending configuration: ip %s, mask %s.\n", arg_ipaddr,
380 case NMRP_C_TFTP_UL_REQ:
382 fprintf(stderr, "Device re-requested file upload %d "
383 "times; aborting.\n", ulreqs);
384 tx.msg.code = NMRP_C_CLOSE_REQ;
387 printf("Uploading %s ... ", arg_filename);
389 err = tftp_put(arg_filename, arg_ipaddr, arg_port);
391 printf("OK\nWaiting for router to respond.\n");
392 sock_set_rx_timeout(fd, arg_ul_timeout);
393 expect = NMRP_C_CLOSE_REQ;
394 } else if (err != -3) {
398 case NMRP_C_KEEP_ALIVE_REQ:
399 tx.msg.code = NMRP_C_KEEP_ALIVE_ACK;
401 case NMRP_C_CLOSE_REQ:
402 tx.msg.code = NMRP_C_CLOSE_ACK;
404 case NMRP_C_CLOSE_ACK:
408 fprintf(stderr, "Unhandled message code 0x%02x!\n",
412 if (tx.msg.code != NMRP_C_NONE) {
413 msg_update_len(&tx.msg);
416 if (pkt_send(fd, &addr, &tx) < 0) {
422 if (rx.msg.code == NMRP_C_CLOSE_REQ) {
423 printf("Remote requested to close connection.\n");
427 err = pkt_recv(fd, &rx);
430 fprintf(stderr, "Timeout while waiting for 0x%02x.\n", expect);
435 sock_set_rx_timeout(fd, arg_rx_timeout);