1
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
5
* Copyright (c) 2006-2008 Miru Limited.
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28
# include <sys/types.h>
29
# include <sys/socket.h>
30
# include <netinet/in.h>
31
# include <netinet/ip.h>
32
# include <arpa/inet.h>
34
# include <ws2tcpip.h>
38
#include <impl/framework.h>
39
#include <impl/packet_test.h>
40
#include "dump-json.h"
45
#define OPTIONS_TOTAL_LEN(x) *(guint16*)( ((char*)(x)) + sizeof(guint16) )
48
int verify_ip_header (struct pgm_ip*, guint);
49
void print_ip_header (struct pgm_ip*);
50
int verify_pgm_header (struct pgm_header*, guint);
51
void print_pgm_header (struct pgm_header*);
52
int verify_spm (struct pgm_header*, char*, guint);
53
void print_spm (struct pgm_header*, char*);
54
int verify_poll (struct pgm_header*, char*, guint);
55
void print_poll (struct pgm_header*, char*);
56
int verify_polr (struct pgm_header*, char*, guint);
57
void print_polr (struct pgm_header*, char*);
58
int verify_odata (struct pgm_header*, char*, guint);
59
void print_odata (struct pgm_header*, char*);
60
int verify_rdata (struct pgm_header*, char*, guint);
61
void print_rdata (struct pgm_header*, char*);
62
static int generic_verify_nak (const char*, struct pgm_header*, char*, guint);
63
static void generic_print_nak (const char*, struct pgm_header*, char*);
64
int verify_nak (struct pgm_header*, char*, guint);
65
void print_nak (struct pgm_header*, char*);
66
int verify_nnak (struct pgm_header*, char*, guint);
67
void print_nnak (struct pgm_header*, char*);
68
int verify_ncf (struct pgm_header*, char*, guint);
69
void print_ncf (struct pgm_header*, char*);
70
int verify_spmr (struct pgm_header*, char*, guint);
71
void print_spmr (struct pgm_header*, char*);
72
int verify_options (char*, guint);
73
void print_options (char*);
85
printf ("\t\"id\": %i,\n", ++count);
89
struct pgm_ip* ip = (struct pgm_ip*)data;
90
if (verify_ip_header (ip, len) < 0) {
91
puts ("\t\"valid\": false");
96
struct pgm_header* pgm = (struct pgm_header*)(data + (ip->ip_hl * 4));
97
guint pgm_len = len - (ip->ip_hl * 4);
98
if (verify_pgm_header (pgm, pgm_len) < 0) {
99
puts ("\t\"valid\": false");
104
char* pgm_data = (char*)(pgm + 1);
105
guint pgm_data_len = pgm_len - sizeof(struct pgm_header);
106
switch (pgm->pgm_type) {
107
case PGM_SPM: retval = verify_spm (pgm, pgm_data, pgm_data_len); break;
108
case PGM_POLL: retval = verify_poll (pgm, pgm_data, pgm_data_len); break;
109
case PGM_POLR: retval = verify_polr (pgm, pgm_data, pgm_data_len); break;
110
case PGM_ODATA: retval = verify_odata (pgm, pgm_data, pgm_data_len); break;
111
case PGM_RDATA: retval = verify_rdata (pgm, pgm_data, pgm_data_len); break;
112
case PGM_NAK: retval = verify_nak (pgm, pgm_data, pgm_data_len); break;
113
case PGM_NNAK: retval = verify_nnak (pgm, pgm_data, pgm_data_len); break;
114
case PGM_NCF: retval = verify_ncf (pgm, pgm_data, pgm_data_len); break;
115
case PGM_SPMR: retval = verify_spmr (pgm, pgm_data, pgm_data_len); break;
119
puts ("\t\"valid\": false");
123
/* packet verified correct */
124
puts ("\t\"valid\": true,");
126
print_ip_header (ip);
127
print_pgm_header (pgm);
129
switch (pgm->pgm_type) {
130
case PGM_SPM: print_spm (pgm, pgm_data); break;
131
case PGM_POLL: print_poll (pgm, pgm_data); break;
132
case PGM_POLR: print_polr (pgm, pgm_data); break;
133
case PGM_ODATA: print_odata (pgm, pgm_data); break;
134
case PGM_RDATA: print_rdata (pgm, pgm_data); break;
135
case PGM_NAK: print_nak (pgm, pgm_data); break;
136
case PGM_NNAK: print_nnak (pgm, pgm_data); break;
137
case PGM_NCF: print_ncf (pgm, pgm_data); break;
138
case PGM_SPMR: print_spmr (pgm, pgm_data); break;
153
/* minimum size should be IP header plus PGM header */
154
if (len < (sizeof(struct pgm_ip) + sizeof(struct pgm_header)))
156
printf ("\t\"message\": \"IP: packet size too small: %i bytes, expecting at least %" G_GSIZE_FORMAT " bytes.\",\n", len, sizeof(struct pgm_header));
160
/* IP packet header: IPv4
163
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
164
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
165
* |Version| HL | ToS | Length |
166
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
167
* | Fragment ID |R|D|M| Fragment Offset |
168
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
169
* | TTL | Protocol | Checksum |
170
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
171
* | Source IP Address |
172
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
173
* | Destination IP Address |
174
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
175
* | IP Options when present ...
176
* +-+-+-+-+-+-+-+-+-+-+-+-+ ...
183
/* decode IP header */
184
if (ip->ip_v != 4 && ip->ip_v != 6) { /* IP version, 4 or 6 */
185
printf ("\t\"message\": \"IP: unknown IP version %i.\",\n", ip->ip_v);
189
guint ip_header_length = ip->ip_hl * 4; /* IP header length in 32bit octets */
190
if (ip_header_length < sizeof(struct pgm_ip)) {
191
printf ("\t\"message\": \"IP: bad IP header length %i, should be at least %" G_GSIZE_FORMAT "lu bytes.\",\n", ip_header_length, sizeof(struct pgm_ip));
195
/* ip_len can equal packet_length - ip_header_length in FreeBSD/NetBSD
196
* Stevens/Fenner/Rudolph, Unix Network Programming Vol.1, p.739
198
* RFC3828 allows partial packets such that len < packet_length with UDP lite
200
#ifndef CONFIG_HOST_ORDER_IP_LEN
201
guint packet_length = g_ntohs(ip->ip_len); /* total packet length */
203
guint packet_length = ip->ip_len;
205
if (len == packet_length + ip_header_length) {
206
packet_length += ip_header_length;
209
if (len < packet_length) { /* redundant: often handled in kernel */
210
printf ("\t\"message\": \"IP: truncated IP packet: header reports %i actual length %i bytes.\",\n", (int)len, (int)packet_length);
214
/* TCP Segmentation Offload (TSO) might have zero length here */
215
if (packet_length < ip_header_length) {
216
printf ("\t\"message\": \"IP: header reports %i less than IP header length %i.\",\n", (int)packet_length, (int)ip_header_length);
220
/* packets that fail checksum will generally not be passed upstream except with rfc3828
222
#ifdef PGM_CHECK_IN_CKSUM
223
int sum = in_cksum((char*)ip, ip_header_length, 0);
225
const int ip_sum = g_ntohs(ip->ip_sum);
226
printf ("\t\"message\": \"IP: IP header checksum incorrect: %#x.\",\n", ip_sum);
231
if (ip->ip_p != IPPROTO_PGM) {
232
printf ("\t\"message\": \"IP: packet IP protocol not PGM: %i.\",\n", ip->ip_p);
236
/* fragmentation offset, bit 0: 0, bit 1: do-not-fragment, bit 2: more-fragments */
237
#ifndef CONFIG_HOST_ORDER_IP_OFF
238
int offset = g_ntohs(ip->ip_off);
240
int offset = ip->ip_off;
242
if ((offset & 0x1fff) != 0) {
243
printf ("\t\"message\": \"IP: fragmented IP packet, ignoring.\",\n");
255
puts ("\t\"IP\": {");
256
printf ("\t\t\"version\": %i,\n",
259
printf ("\t\t\"headerLength\": %i,\n",
262
printf ("\t\t\"ToS\": %i,\n",
265
printf ("\t\t\"length\": %i,\n",
266
#ifndef CONFIG_HOST_ORDER_IP_LEN
272
printf ("\t\t\"fragmentId\": %i,\n",
275
printf ("\t\t\"DF\": %s,\n",
276
(g_ntohs(ip->ip_off) & 0x4000) ? "true" : "false"
278
printf ("\t\t\"MF\": %s,\n",
279
(g_ntohs(ip->ip_off) & 0x2000) ? "true" : "false"
281
printf ("\t\t\"fragmentOffset\": %i,\n",
282
g_ntohs(ip->ip_off) & 0x1fff
284
printf ("\t\t\"TTL\": %i,\n",
287
printf ("\t\t\"protocol\": %i,\n",
290
printf ("\t\t\"sourceIp\": \"%s\",\n",
291
inet_ntoa(*(struct in_addr*)&ip->ip_src)
293
printf ("\t\t\"destinationIp\": \"%s\",\n",
294
inet_ntoa(*(struct in_addr*)&ip->ip_dst)
296
puts ("\t\t\"IpOptions\": {");
303
struct pgm_header* pgm,
308
/* PGM payload, header looks as follows:
311
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
312
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
313
* | Source Port | Destination Port |
314
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
315
* | Type | Options | Checksum |
316
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
317
* | Global Source ID ... |
318
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
319
* | ... Global Source ID | TSDU Length |
320
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
321
* | Type specific data ...
322
* +-+-+-+-+-+-+-+-+-+- ...
324
if (pgm_len < sizeof(pgm)) {
325
printf ("\t\"message\": \"PGM: packet size less than PGM header: %i bytes.\",\n", pgm_len);
329
if (pgm->pgm_checksum)
331
int sum = pgm->pgm_checksum;
332
pgm->pgm_checksum = 0;
333
int pgm_sum = pgm_csum_fold (pgm_csum_partial ((const char*)pgm, pgm_len, 0));
334
pgm->pgm_checksum = sum;
335
if (pgm_sum != sum) {
336
printf ("\t\"message\": \"PGM: PGM packet checksum incorrect, packet %#x calculated %#x.\",\n", sum, pgm_sum);
340
if (pgm->pgm_type != PGM_ODATA && pgm->pgm_type != PGM_RDATA) {
341
printf ("\t\"message\": \"PGM: No PGM checksum value, mandatory for ODATA/RDATA.\",\n");
346
if ( pgm->pgm_type != PGM_SPM &&
347
pgm->pgm_type != PGM_POLL &&
348
pgm->pgm_type != PGM_POLR &&
349
pgm->pgm_type != PGM_ODATA &&
350
pgm->pgm_type != PGM_RDATA &&
351
pgm->pgm_type != PGM_NAK &&
352
pgm->pgm_type != PGM_NNAK &&
353
pgm->pgm_type != PGM_NCF &&
354
pgm->pgm_type != PGM_SPMR )
356
printf ("\t\"message\": \"PGM: Not a valid PGM packet type: %i.\",\n", pgm->pgm_type);
363
/* note: output trails tsdu length line to allow for comma
368
struct pgm_header* pgm
371
puts ("\t\"PGM\": {");
372
printf ("\t\t\"sourcePort\": %i,\n", g_ntohs(pgm->pgm_sport));
373
printf ("\t\t\"destinationPort\": %i,\n", g_ntohs(pgm->pgm_dport));
374
printf ("\t\t\"type\": \"%s\",\n", pgm_type_string(pgm->pgm_type & 0xf));
375
printf ("\t\t\"version\": %i,\n", (pgm->pgm_type & 0xc0) >> 6);
376
puts ("\t\t\"options\": {");
377
printf ("\t\t\t\"networkSignificant\": %s,\n", (pgm->pgm_options & PGM_OPT_NETWORK) ? "true" : "false");
378
printf ("\t\t\t\"parityPacket\": %s,\n", (pgm->pgm_options & PGM_OPT_PARITY) ? "true" : "false");
379
printf ("\t\t\t\"variableLength\": %s\n", (pgm->pgm_options & PGM_OPT_VAR_PKTLEN) ? "true" : "false");
381
printf ("\t\t\"checksum\": %i,\n", pgm->pgm_checksum);
382
printf ("\t\t\"gsi\": \"%i.%i.%i.%i.%i.%i\",\n",
389
printf ("\t\t\"tsduLength\": %i", g_ntohs(pgm->pgm_tsdu_length));
392
/* 8.1. Source Path Messages (SPM)
395
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
396
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
397
* | SPM's Sequence Number |
398
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
399
* | Trailing Edge Sequence Number |
400
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
401
* | Leading Edge Sequence Number |
402
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
403
* | NLA AFI | Reserved |
404
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
406
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+
407
* | Option Extensions when present ... |
408
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+
410
* NLA = Network Layer Address
411
* NLA AFI = NLA Address Family Indicator: rfc 1700 (ADDRESS FAMILY NUMBERS)
412
* => Path NLA = IP address of last network element
417
struct pgm_header* header,
424
/* truncated packet */
425
if (len < sizeof(struct pgm_spm)) {
426
printf ("\t\"message\": \"SPM: packet length: %i less than minimum SPM length: %" G_GSIZE_FORMAT "lu bytes.\",\n", len, sizeof(struct pgm_spm));
431
struct pgm_spm* spm = (struct pgm_spm*)data;
432
char* opt_offset = (char*)(spm + 1);
433
guint opt_len = len - sizeof(spm);
435
switch (g_ntohs(spm->spm_nla_afi)) {
437
if (len < sizeof(struct pgm_spm6)) {
438
printf ("\t\"message\": \"SPM: packet length: %i less than minimum IPv6 SPM length: %" G_GSIZE_FORMAT "lu bytes.\",\n", len, sizeof(struct pgm_spm6));
442
opt_offset += sizeof(struct pgm_spm6) - sizeof(struct pgm_spm);
443
opt_len -= sizeof(struct pgm_spm6) - sizeof(struct pgm_spm);
449
printf ("\t\"message\": \"SPM: invalid AFI of source NLA: %i.\",\n", g_ntohs(spm->spm_nla_afi));
454
/* option extensions */
455
if (header->pgm_options & PGM_OPT_PRESENT)
457
retval = verify_options (opt_offset, opt_len);
466
struct pgm_header* header,
470
struct pgm_spm* spm = (struct pgm_spm*)data;
471
struct pgm_spm6* spm6 = (struct pgm_spm6*)data;
472
char* opt_offset = (char*)(spm + 1);
475
printf ("\t\t\"spmSqn\": %i,\n", g_ntohl(spm->spm_sqn));
476
printf ("\t\t\"spmTrail\": %i,\n", g_ntohl(spm->spm_trail));
477
printf ("\t\t\"spmLead\": %i,\n", g_ntohl(spm->spm_lead));
478
printf ("\t\t\"spmNlaAfi\": %i,\n", g_ntohs (spm->spm_nla_afi));
480
char s[INET6_ADDRSTRLEN];
481
switch (g_ntohs(spm->spm_nla_afi)) {
483
pgm_inet_ntop ( AF_INET, &spm->spm_nla, s, sizeof (s) );
487
pgm_inet_ntop ( AF_INET6, &spm6->spm6_nla, s, sizeof (s) );
488
opt_offset += sizeof(struct pgm_spm6) - sizeof(struct pgm_spm);
492
printf ("\t\t\"spmNla\": \"%s\"", s);
494
/* option extensions */
495
if (header->pgm_options & PGM_OPT_PRESENT)
498
print_options (opt_offset);
504
/* 14.7.1. Poll Request
507
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
508
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
509
* | POLL's Sequence Number |
510
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
511
* | POLL's Round | POLL's Sub-type |
512
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
513
* | NLA AFI | Reserved |
514
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+
517
* | POLL's Back-off Interval |
518
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
520
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
521
* | Matching Bit-Mask |
522
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
523
* | Option Extensions when present ... |
524
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+
526
* Sent to ODATA multicast group with IP Router Alert option.
529
#define PGM_MIN_POLL_SIZE ( sizeof(struct pgm_poll) )
533
G_GNUC_UNUSED struct pgm_header* header,
534
G_GNUC_UNUSED char* data,
535
G_GNUC_UNUSED guint len
543
G_GNUC_UNUSED struct pgm_header* header,
544
G_GNUC_UNUSED char* data
549
/* 14.7.2. Poll Response
552
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
553
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
554
* | POLR's Sequence Number |
555
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
556
* | POLR's Round | reserved |
557
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
558
* | Option Extensions when present ... |
559
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+
564
G_GNUC_UNUSED struct pgm_header* header,
565
G_GNUC_UNUSED char* data,
566
G_GNUC_UNUSED guint len
574
G_GNUC_UNUSED struct pgm_header* header,
575
G_GNUC_UNUSED char* data
583
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
584
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
585
* | Data Packet Sequence Number |
586
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
587
* | Trailing Edge Sequence Number |
588
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
589
* | Option Extensions when present ... |
590
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+
597
struct pgm_header* header,
604
if (len < sizeof(struct pgm_data)) {
605
printf ("\t\"message\": \"ODATA: packet length: %i less than minimum ODATA length: %" G_GSIZE_FORMAT " bytes.\",\n", len, sizeof(struct pgm_data));
610
char* tsdu = data + sizeof(struct pgm_data);
611
guint tsdu_len = len - sizeof(struct pgm_data);
612
if (header->pgm_options & PGM_OPT_PRESENT)
614
retval = verify_options (tsdu, tsdu_len);
616
guint opt_total_len = g_ntohs( OPTIONS_TOTAL_LEN(tsdu) );
617
tsdu += opt_total_len;
618
tsdu_len -= opt_total_len;
621
if (!retval && g_ntohs(header->pgm_tsdu_length) != tsdu_len) {
622
printf ("\t\"message\": \"ODATA: TSDU truncated expected %i, found %i bytes.\",\n", g_ntohs(header->pgm_tsdu_length), tsdu_len);
631
struct pgm_header* header,
635
struct pgm_data* odata = (struct pgm_data*)data;
636
char* tsdu = data + sizeof(struct pgm_data);
639
printf ("\t\t\"odSqn\": %lu,\n", (gulong)g_ntohl(odata->data_sqn));
640
printf ("\t\t\"odTrail\": %lu,\n", (gulong)g_ntohl(odata->data_trail));
642
/* option extensions */
643
if (header->pgm_options & PGM_OPT_PRESENT)
645
print_options (tsdu);
646
tsdu += g_ntohs( OPTIONS_TOTAL_LEN(tsdu) );
651
printf ("\t\t\"data\": \"");
652
char* end = tsdu + g_ntohs (header->pgm_tsdu_length);
670
struct pgm_header* header,
677
if (len < sizeof(struct pgm_data)) {
678
printf ("\t\"message\": \"RDATA: packet length: %i less than minimum RDATA length: %" G_GSIZE_FORMAT " bytes.\",\n", len, sizeof(struct pgm_data));
683
char* tsdu = data + sizeof(struct pgm_data);
684
guint tsdu_len = len - sizeof(struct pgm_data);
685
if (header->pgm_options & PGM_OPT_PRESENT)
687
retval = verify_options (tsdu, tsdu_len);
689
guint opt_total_len = g_ntohs( OPTIONS_TOTAL_LEN(tsdu) );
690
tsdu += opt_total_len;
691
tsdu_len -= opt_total_len;
694
if (!retval && g_ntohs(header->pgm_tsdu_length) != tsdu_len) {
695
printf ("\t\"message\": \"RDATA: tsdu truncated expected %i, found %i bytes.\",\n", g_ntohs(header->pgm_tsdu_length), tsdu_len);
704
struct pgm_header* header,
708
struct pgm_data* rdata = (struct pgm_data*)data;
709
char* tsdu = data + sizeof(struct pgm_data);
712
printf ("\t\t\"rdSqn\": %lu,\n", (gulong)g_ntohl(rdata->data_sqn));
713
printf ("\t\t\"rdTrail\": %lu,\n", (gulong)g_ntohl(rdata->data_trail));
715
/* option extensions */
716
if (header->pgm_options & PGM_OPT_PRESENT)
718
print_options (tsdu);
719
tsdu += g_ntohs( OPTIONS_TOTAL_LEN(tsdu) );
724
printf ("\t\t\"data\": \"");
725
char* end = tsdu + g_ntohs (header->pgm_tsdu_length);
740
* Technically the AFI of the source and multicast group can be different
741
* but that would be very wibbly wobbly. One example is using a local DLR
742
* with a IPv4 address to reduce NAK cost for recovery on wide IPv6
746
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
747
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
748
* | Requested Sequence Number |
749
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
750
* | NLA AFI | Reserved |
751
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
753
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+
754
* | NLA AFI | Reserved |
755
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
756
* | Multicast Group NLA ... |
757
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+
758
* | Option Extensions when present ...
759
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ...
764
struct pgm_header* header,
769
return generic_verify_nak ("NAK", header, data, len);
774
struct pgm_header* header,
779
return generic_verify_nak ("NCF", header, data, len);
784
struct pgm_header* header,
789
return generic_verify_nak ("NNAK", header, data, len);
794
const char* name, /* upper case */
795
G_GNUC_UNUSED struct pgm_header* header,
802
/* truncated packet */
803
if (len < sizeof(struct pgm_nak)) {
804
printf ("\t\"message\": \"%s: packet length: %i less than minimum %s length: %" G_GSIZE_FORMAT " bytes.\",\n",
805
name, len, name, sizeof(struct pgm_nak));
810
struct pgm_nak* nak = (struct pgm_nak*)data;
811
int nak_src_nla_afi = g_ntohs (nak->nak_src_nla_afi);
812
int nak_grp_nla_afi = -1;
814
/* check source NLA: unicast address of the ODATA sender */
815
switch (nak_src_nla_afi) {
817
nak_grp_nla_afi = g_ntohs (nak->nak_grp_nla_afi);
821
nak_grp_nla_afi = g_ntohs (((struct pgm_nak6*)nak)->nak6_grp_nla_afi);
825
printf ("\t\"message\": \"%s: invalid AFI of source NLA: %i.\",\n",
826
name, nak_src_nla_afi);
831
/* check multicast group NLA */
832
switch (nak_grp_nla_afi) {
834
switch (nak_src_nla_afi) {
835
/* IPv4 + IPv6 NLA */
837
if (len < ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) )) {
838
printf ("\t\"message\": \"%s: packet length: %i less than joint IPv4/6 %s length: %" G_GSIZE_FORMAT " bytes.\",\n",
839
name, len, name, ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) ));
844
/* IPv6 + IPv6 NLA */
846
if (len < sizeof(struct pgm_nak6)) {
847
printf ("\t\"message\": \"%s: packet length: %i less than IPv6 %s length: %" G_GSIZE_FORMAT " bytes.\",\n",
848
name, len, name, sizeof(struct pgm_nak6));
856
if (nak_src_nla_afi == AFI_IP6) {
857
if (len < ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) )) {
858
printf ("\t\"message\": \"%s: packet length: %i less than joint IPv6/4 %s length: %" G_GSIZE_FORMAT " bytes.\",\n",
859
name, len, name, ( sizeof(struct pgm_nak) + sizeof(struct in6_addr) - sizeof(struct in_addr) ));
866
printf ("\t\"message\": \"%s: invalid AFI of group NLA: %i.\",\n",
867
name, nak_grp_nla_afi);
878
struct pgm_header* header,
882
generic_print_nak ("nak", header, data);
887
struct pgm_header* header,
891
generic_print_nak ("ncf", header, data);
896
struct pgm_header* header,
900
generic_print_nak ("nnak", header, data);
905
const char* name, /* lower case */
906
struct pgm_header* header,
910
struct pgm_nak* nak = (struct pgm_nak*)data;
911
struct pgm_nak6* nak6 = (struct pgm_nak6*)data;
912
char* opt_offset = (char*)(nak + 1);
915
printf ("\t\t\"%sSqn\": %lu,\n", name, (gulong)g_ntohl(nak->nak_sqn));
917
guint16 nak_src_nla_afi = g_ntohs (nak->nak_src_nla_afi);
918
guint16 nak_grp_nla_afi = 0;
919
char s[INET6_ADDRSTRLEN];
921
printf ("\t\t\"%sSourceNlaAfi\": %i,\n", name, nak_src_nla_afi);
924
switch (nak_src_nla_afi) {
926
pgm_inet_ntop ( AF_INET, &nak->nak_src_nla, s, sizeof(s) );
927
nak_grp_nla_afi = g_ntohs (nak->nak_grp_nla_afi);
931
pgm_inet_ntop ( AF_INET6, &nak6->nak6_src_nla, s, sizeof(s) );
932
nak_grp_nla_afi = g_ntohs (nak6->nak6_grp_nla_afi);
933
opt_offset += sizeof(struct in6_addr) - sizeof(struct in_addr);
937
printf ("\t\t\"%sSourceNla\": \"%s\",\n", name, s);
938
printf ("\t\t\"%sGroupNlaAfi\": %i,\n", name, nak_grp_nla_afi);
940
switch (nak_grp_nla_afi) {
942
switch (nak_src_nla_afi) {
943
/* IPv4 + IPv6 NLA */
945
pgm_inet_ntop ( AF_INET6, &nak->nak_grp_nla, s, sizeof(s) );
948
/* IPv6 + IPv6 NLA */
950
pgm_inet_ntop ( AF_INET6, &nak6->nak6_grp_nla, s, sizeof(s) );
953
opt_offset += sizeof(struct in6_addr) - sizeof(struct in_addr);
957
switch (nak_src_nla_afi) {
958
/* IPv4 + IPv4 NLA */
960
pgm_inet_ntop ( AF_INET, &nak->nak_grp_nla, s, sizeof(s) );
963
/* IPv6 + IPv4 NLA */
965
pgm_inet_ntop ( AF_INET, &nak6->nak6_grp_nla, s, sizeof(s) );
971
printf ("\t\t\"%sGroupNla\": \"%s\"", name, s);
973
/* option extensions */
974
if (header->pgm_options & PGM_OPT_PRESENT)
977
print_options (opt_offset);
987
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
988
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
989
* | Option Extensions when present ...
990
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ...
995
struct pgm_header* header,
1002
char* opt_offset = data;
1003
guint opt_len = len;
1005
/* option extensions */
1006
if (header->pgm_options & PGM_OPT_PRESENT)
1008
retval = verify_options (opt_offset, opt_len);
1016
struct pgm_header* header,
1020
char* opt_offset = data;
1022
/* option extensions */
1023
if (header->pgm_options & PGM_OPT_PRESENT)
1025
print_options (opt_offset);
1032
/* Parse PGM options fields:
1034
* assume at least two options, one the mandatory OPT_LENGTH
1037
#define PGM_MIN_OPT_SIZE ( sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_length) )
1047
if (len < PGM_MIN_OPT_SIZE) {
1048
printf ("\t\"message\": \"PGM options: packet size too small for options.\",\n");
1053
/* OPT_LENGTH first */
1054
struct pgm_opt_length* opt_len = (struct pgm_opt_length*)data;
1055
if ((opt_len->opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) {
1056
printf ("\t\"message\": \"PGM options: first option not OPT_LENGTH.\",\n");
1061
if (opt_len->opt_length != sizeof(struct pgm_opt_length)) {
1062
printf ("\t\"message\": \"PGM options: OPT_LENGTH incorrect option length: %i, expecting %" G_GSIZE_FORMAT " bytes.\",\n", opt_len->opt_length, sizeof(struct pgm_opt_length));
1067
if (g_ntohs(opt_len->opt_total_length) < PGM_MIN_OPT_SIZE) {
1068
printf ("\t\"message\": \"PGM options: OPT_LENGTH total length too short: %i bytes.\",\n", g_ntohs(opt_len->opt_total_length));
1073
if (g_ntohs(opt_len->opt_total_length) > len) {
1074
printf ("\t\"message\": \"PGM options: OPT_LENGTH total length longer than packet allows: %i bytes.\",\n", g_ntohs(opt_len->opt_total_length));
1079
/* iterate through options (max 16) */
1081
guint total_length = g_ntohs(opt_len->opt_total_length);
1083
guint opt_counters[256];
1084
memset (&opt_counters, 0, sizeof(opt_counters));
1086
struct pgm_opt_header* opt_header = (struct pgm_opt_header*)data;
1088
total_length -= opt_header->opt_length;
1089
if (total_length < sizeof(struct pgm_opt_header)) {
1090
printf ("\t\"message\": \"PGM options: option #%i shorter than minimum option size.\",\n", count + 1);
1094
opt_header = (struct pgm_opt_header*)( ((char*)opt_header) + opt_header->opt_length );
1095
if (((int)total_length - (int)opt_header->opt_length) < 0) {
1096
printf ("\t\"message\": \"PGM options: option #%i shorter than embedded size.\",\n", count + 1);
1101
if (opt_counters[opt_header->opt_type]++) {
1102
printf ("\t\"message\": \"PGM options: duplicate option %i.\",\n", opt_header->opt_type);
1107
/* check option types */
1108
switch (opt_header->opt_type & PGM_OPT_MASK) {
1109
case PGM_OPT_FRAGMENT:
1111
if (opt_header->opt_length != sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_fragment)) {
1112
printf ("\t\"message\": \"PGM options: OPT_FRAGMENT incorrect size: %i bytes.\",\n", opt_header->opt_length);
1117
struct pgm_opt_fragment* opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1);
1118
if (g_ntohl(opt_fragment->opt_frag_off) > g_ntohl(opt_fragment->opt_frag_len)) {
1119
printf ("\t\"message\": \"PGM options: fragment offset longer than original packet.\",\n");
1126
case PGM_OPT_NAK_LIST:
1128
guint list_len = opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(guint8);
1130
printf ("\t\"message\": \"PGM options: OPT_NAK_LIST invalid odd length: %i bytes.\",\n", opt_header->opt_length);
1136
if (list_len == 0) {
1137
printf ("\t\"message\": \"PGM options: OPT_NAK_LIST empty.\",\n");
1142
if (list_len > 62) {
1143
printf ("\t\"message\": \"PGM options: OPT_NAK_LIST too long: %i sqns.\",\n", list_len);
1150
case PGM_OPT_PARITY_PRM:
1152
struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1);
1153
if ((opt_parity_prm->opt_reserved & PGM_PARITY_PRM_MASK) == 0) {
1154
printf ("\t\"message\": \"PGM options: neither pro-active or on-demand parity set in OPT_PARITY_PRM.\",\n");
1158
guint32 parity_prm_tgs = g_ntohl (opt_parity_prm->parity_prm_tgs);
1159
if (parity_prm_tgs < 2 || parity_prm_tgs > 128) {
1160
printf ("\t\"message\": \"PGM options: transmission group size out of bounds: %i.\",\n", parity_prm_tgs);
1168
/* unknown option, skip */
1171
/* end option types */
1173
if (opt_header->opt_type & PGM_OPT_END) {
1177
if (count++ == 16) {
1178
printf ("\t\"message\": \"PGM options: more than 16 options found.\",\n");
1188
static const char *opx_text[4] = {
1200
struct pgm_opt_length* opt_len = (struct pgm_opt_length*)data;
1202
puts ("\t\t\"pgmOptions\": [");
1204
printf ("\t\t\t\t\"length\": \"%#x\",\n", opt_len->opt_length);
1205
puts ("\t\t\t\t\"type\": \"OPT_LENGTH\",");
1206
printf ("\t\t\t\t\"totalLength\": %i\n", g_ntohs (opt_len->opt_total_length));
1209
/* iterate through options */
1210
struct pgm_opt_header* opt_header = (struct pgm_opt_header*)data;
1212
opt_header = (struct pgm_opt_header*)( ((char*)opt_header) + opt_header->opt_length );
1216
printf ("\t\t\t\t\"length\": \"%#x\",\n", opt_header->opt_length);
1218
switch (opt_header->opt_type & PGM_OPT_MASK) {
1219
case PGM_OPT_FRAGMENT:
1221
struct pgm_opt_fragment* opt_fragment = (struct pgm_opt_fragment*)(opt_header + 1);
1222
printf ("\t\t\t\t\"type\": \"OPT_FRAGMENT%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : "");
1223
printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false");
1224
printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]);
1225
printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_fragment->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false");
1226
printf ("\t\t\t\t\"firstSqn\": %i,\n", g_ntohl(opt_fragment->opt_sqn));
1227
printf ("\t\t\t\t\"fragmentOffset\": %i,\n", g_ntohl(opt_fragment->opt_frag_off));
1228
printf ("\t\t\t\t\"originalLength\": %i\n", g_ntohl(opt_fragment->opt_frag_len));
1232
case PGM_OPT_NAK_LIST:
1234
struct pgm_opt_nak_list* opt_nak_list = (struct pgm_opt_nak_list*)(opt_header + 1);
1235
char* end = (char*)opt_header + opt_header->opt_length;
1236
printf ("\t\t\t\t\"type\": \"OPT_NAK_LIST%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : "");
1237
printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false");
1238
printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]);
1239
printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_nak_list->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false");
1240
char sqns[1024] = "";
1244
sprintf (sqn, "%s%i", (i>0)?", ":"", g_ntohl(opt_nak_list->opt_sqn[i]));
1247
} while ((char*)&opt_nak_list->opt_sqn[i] < end);
1248
printf ("\t\t\t\t\"sqn\": [%s]\n", sqns);
1252
case PGM_OPT_PARITY_PRM:
1254
struct pgm_opt_parity_prm* opt_parity_prm = (struct pgm_opt_parity_prm*)(opt_header + 1);
1255
printf ("\t\t\t\t\"type\": \"OPT_PARITY_PRM%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : "");
1256
printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false");
1257
printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]);
1258
printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_parity_prm->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false");
1259
printf ("\t\t\t\t\"P-bit\": %s,\n", (opt_parity_prm->opt_reserved & PGM_PARITY_PRM_PRO) ? "true" : "false");
1260
printf ("\t\t\t\t\"O-bit\": %s,\n", (opt_parity_prm->opt_reserved & PGM_PARITY_PRM_OND) ? "true" : "false");
1261
printf ("\t\t\t\t\"transmissionGroupSize\": %i\n", g_ntohl(opt_parity_prm->parity_prm_tgs));
1265
case PGM_OPT_CURR_TGSIZE:
1267
struct pgm_opt_curr_tgsize* opt_curr_tgsize = (struct pgm_opt_curr_tgsize*)(opt_header + 1);
1268
printf ("\t\t\t\t\"type\": \"OPT_CURR_TGSIZE%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : "");
1269
printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false");
1270
printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]);
1271
printf ("\t\t\t\t\"U-bit\": %s,\n", (opt_curr_tgsize->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false");
1272
printf ("\t\t\t\t\"actualTransmissionGroupSize\": %i\n", g_ntohl(opt_curr_tgsize->prm_atgsize));
1278
struct pgm_opt_syn* opt_syn = (struct pgm_opt_syn*)(opt_header + 1);
1279
printf ("\t\t\t\t\"type\": \"OPT_SYN%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : "");
1280
printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false");
1281
printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]);
1282
printf ("\t\t\t\t\"U-bit\": %s\n", (opt_syn->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false");
1288
struct pgm_opt_fin* opt_fin = (struct pgm_opt_fin*)(opt_header + 1);
1289
printf ("\t\t\t\t\"type\": \"OPT_FIN%s\",\n", (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : "");
1290
printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false");
1291
printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]);
1292
printf ("\t\t\t\t\"U-bit\": %s\n", (opt_fin->opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false");
1298
guint8 opt_reserved = *(guint8*)(opt_header + 1);
1299
printf ("\t\t\t\t\"type\": \"%#x%s\",\n", opt_header->opt_type & PGM_OPT_MASK, (opt_header->opt_type & PGM_OPT_END) ? "|OPT_END" : "");
1300
printf ("\t\t\t\t\"F-bit\": %s,\n", (opt_header->opt_reserved & PGM_OP_ENCODED) ? "true" : "false");
1301
printf ("\t\t\t\t\"OPX\": \"%s\",\n", opx_text[opt_header->opt_reserved & PGM_OPX_MASK]);
1302
printf ("\t\t\t\t\"U-bit\": %s\n", (opt_reserved & PGM_OP_ENCODED_NULL) ? "true" : "false");
1308
} while (!(opt_header->opt_type & PGM_OPT_END));