~ubuntu-branches/ubuntu/precise/libpgm/precise

« back to all changes in this revision

Viewing changes to openpgm/pgm/test/.svn/text-base/dump-json.c.svn-base

  • Committer: Bazaar Package Importer
  • Author(s): Gabriel de Perthuis
  • Date: 2011-04-07 16:48:52 UTC
  • Revision ID: james.westby@ubuntu.com-20110407164852-8uamem42ojeptj6l
Tags: upstream-5.1.116~dfsg
ImportĀ upstreamĀ versionĀ 5.1.116~dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
 
2
 *
 
3
 * JSON packet dump.
 
4
 *
 
5
 * Copyright (c) 2006-2008 Miru Limited.
 
6
 *
 
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.
 
11
 *
 
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.
 
16
 *
 
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
 
20
 */
 
21
 
 
22
#include <ctype.h>
 
23
#include <errno.h>
 
24
#include <stdio.h>
 
25
#include <string.h>
 
26
#ifndef _WIN32
 
27
#       include <netdb.h>
 
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>
 
33
#else
 
34
#       include <ws2tcpip.h>
 
35
#       include <mswsock.h>
 
36
#endif
 
37
#include <glib.h>
 
38
#include <impl/framework.h>
 
39
#include <impl/packet_test.h>
 
40
#include "dump-json.h"
 
41
 
 
42
 
 
43
/* globals */
 
44
 
 
45
#define OPTIONS_TOTAL_LEN(x)    *(guint16*)( ((char*)(x)) + sizeof(guint16) )
 
46
 
 
47
 
 
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*);
 
74
 
 
75
 
 
76
int
 
77
monitor_packet (
 
78
        char*   data,
 
79
        guint   len
 
80
        )
 
81
{
 
82
        static int count = 0;
 
83
 
 
84
        puts ("{");
 
85
        printf ("\t\"id\": %i,\n", ++count);
 
86
 
 
87
        int retval = 0;
 
88
 
 
89
        struct pgm_ip* ip = (struct pgm_ip*)data;
 
90
        if (verify_ip_header (ip, len) < 0) {
 
91
                puts ("\t\"valid\": false");
 
92
                retval = -1;
 
93
                goto out;
 
94
        }
 
95
 
 
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");
 
100
                retval = -1;
 
101
                goto out;
 
102
        }
 
103
 
 
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;
 
116
        }
 
117
 
 
118
        if (retval < 0) {
 
119
                puts ("\t\"valid\": false");
 
120
                goto out;
 
121
        }
 
122
 
 
123
/* packet verified correct */
 
124
        puts ("\t\"valid\": true,");
 
125
 
 
126
        print_ip_header (ip);
 
127
        print_pgm_header (pgm);
 
128
 
 
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;
 
139
        }
 
140
 
 
141
out:
 
142
        puts ("}");
 
143
        return retval;
 
144
}
 
145
 
 
146
        
 
147
int
 
148
verify_ip_header (
 
149
        struct pgm_ip*  ip,
 
150
        guint           len
 
151
        )
 
152
{
 
153
/* minimum size should be IP header plus PGM header */
 
154
        if (len < (sizeof(struct pgm_ip) + sizeof(struct pgm_header))) 
 
155
        {
 
156
                printf ("\t\"message\": \"IP: packet size too small: %i bytes, expecting at least %" G_GSIZE_FORMAT " bytes.\",\n", len, sizeof(struct pgm_header));
 
157
                return -1;
 
158
        }
 
159
 
 
160
/* IP packet header: IPv4
 
161
 *
 
162
 *  0                   1                   2                   3
 
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
 * +-+-+-+-+-+-+-+-+-+-+-+-+ ...
 
177
 * | Data ...
 
178
 * +-+-+- ...
 
179
 *
 
180
 * IPv6: n/a
 
181
 */
 
182
 
 
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);
 
186
                return -1;
 
187
        }
 
188
 
 
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));
 
192
                return -1;
 
193
        }
 
194
 
 
195
/* ip_len can equal packet_length - ip_header_length in FreeBSD/NetBSD
 
196
 * Stevens/Fenner/Rudolph, Unix Network Programming Vol.1, p.739 
 
197
 * 
 
198
 * RFC3828 allows partial packets such that len < packet_length with UDP lite
 
199
 */
 
200
#ifndef CONFIG_HOST_ORDER_IP_LEN
 
201
        guint packet_length = g_ntohs(ip->ip_len);      /* total packet length */
 
202
#else
 
203
        guint packet_length = ip->ip_len;
 
204
#endif
 
205
        if (len == packet_length + ip_header_length) {
 
206
                packet_length += ip_header_length;
 
207
        }
 
208
 
 
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);
 
211
                return -1;
 
212
        }
 
213
 
 
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);
 
217
                return -1;
 
218
        }
 
219
 
 
220
/* packets that fail checksum will generally not be passed upstream except with rfc3828
 
221
 */
 
222
#ifdef PGM_CHECK_IN_CKSUM
 
223
        int sum = in_cksum((char*)ip, ip_header_length, 0);
 
224
        if (sum != 0) {
 
225
                const int ip_sum = g_ntohs(ip->ip_sum);
 
226
                printf ("\t\"message\": \"IP: IP header checksum incorrect: %#x.\",\n", ip_sum);
 
227
                return -2;
 
228
        }
 
229
#endif
 
230
 
 
231
        if (ip->ip_p != IPPROTO_PGM) {
 
232
                printf ("\t\"message\": \"IP: packet IP protocol not PGM: %i.\",\n", ip->ip_p);
 
233
                return -1;
 
234
        }
 
235
 
 
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);
 
239
#else
 
240
        int offset = ip->ip_off;
 
241
#endif
 
242
        if ((offset & 0x1fff) != 0) {
 
243
                printf ("\t\"message\": \"IP: fragmented IP packet, ignoring.\",\n");
 
244
                return -1;
 
245
        }
 
246
 
 
247
        return 0;
 
248
}
 
249
 
 
250
void
 
251
print_ip_header (
 
252
        struct pgm_ip*  ip
 
253
        )
 
254
{
 
255
        puts ("\t\"IP\": {");
 
256
        printf ("\t\t\"version\": %i,\n",
 
257
                ip->ip_v
 
258
                );
 
259
        printf ("\t\t\"headerLength\": %i,\n",
 
260
                ip->ip_hl
 
261
                );
 
262
        printf ("\t\t\"ToS\": %i,\n",
 
263
                ip->ip_tos & 0x3
 
264
                );
 
265
        printf ("\t\t\"length\": %i,\n",
 
266
#ifndef CONFIG_HOST_ORDER_IP_LEN
 
267
                g_ntohs(ip->ip_len)
 
268
#else
 
269
                ip->ip_len
 
270
#endif
 
271
                );
 
272
        printf ("\t\t\"fragmentId\": %i,\n",
 
273
                g_ntohs(ip->ip_id)
 
274
                );
 
275
        printf ("\t\t\"DF\": %s,\n",
 
276
                (g_ntohs(ip->ip_off) & 0x4000) ? "true" : "false"
 
277
                );
 
278
        printf ("\t\t\"MF\": %s,\n",
 
279
                (g_ntohs(ip->ip_off) & 0x2000) ? "true" : "false"
 
280
                );
 
281
        printf ("\t\t\"fragmentOffset\": %i,\n",
 
282
                g_ntohs(ip->ip_off) & 0x1fff
 
283
                );
 
284
        printf ("\t\t\"TTL\": %i,\n",
 
285
                ip->ip_ttl
 
286
                );
 
287
        printf ("\t\t\"protocol\": %i,\n",
 
288
                ip->ip_p
 
289
                );
 
290
        printf ("\t\t\"sourceIp\": \"%s\",\n",
 
291
                inet_ntoa(*(struct in_addr*)&ip->ip_src)
 
292
                );
 
293
        printf ("\t\t\"destinationIp\": \"%s\",\n",
 
294
                inet_ntoa(*(struct in_addr*)&ip->ip_dst)
 
295
                );
 
296
        puts ("\t\t\"IpOptions\": {");
 
297
        puts ("\t\t}");
 
298
        puts ("\t},");
 
299
}
 
300
 
 
301
int
 
302
verify_pgm_header (
 
303
        struct pgm_header*      pgm,
 
304
        guint           pgm_len
 
305
        )
 
306
{
 
307
 
 
308
/* PGM payload, header looks as follows:
 
309
 *
 
310
 *  0                   1                   2                   3
 
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
 * +-+-+-+-+-+-+-+-+-+- ...
 
323
 */
 
324
        if (pgm_len < sizeof(pgm)) {
 
325
                printf ("\t\"message\": \"PGM: packet size less than PGM header: %i bytes.\",\n", pgm_len);
 
326
                return -1;
 
327
        }
 
328
 
 
329
        if (pgm->pgm_checksum)
 
330
        {
 
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);
 
337
                        return -2;
 
338
                }
 
339
        } else {
 
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");
 
342
                        return -1;
 
343
                }
 
344
        }
 
345
 
 
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       )
 
355
        {
 
356
                printf ("\t\"message\": \"PGM: Not a valid PGM packet type: %i.\",\n", pgm->pgm_type);
 
357
                return -1;
 
358
        }
 
359
 
 
360
        return 0;
 
361
}
 
362
 
 
363
/* note: output trails tsdu length line to allow for comma
 
364
 */
 
365
 
 
366
void
 
367
print_pgm_header (
 
368
        struct pgm_header*      pgm
 
369
        )
 
370
{
 
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");
 
380
        puts ("\t\t},");
 
381
        printf ("\t\t\"checksum\": %i,\n", pgm->pgm_checksum);
 
382
        printf ("\t\t\"gsi\": \"%i.%i.%i.%i.%i.%i\",\n",
 
383
                pgm->pgm_gsi[0],
 
384
                pgm->pgm_gsi[1],
 
385
                pgm->pgm_gsi[2],
 
386
                pgm->pgm_gsi[3],
 
387
                pgm->pgm_gsi[4],
 
388
                pgm->pgm_gsi[5]);
 
389
        printf ("\t\t\"tsduLength\": %i", g_ntohs(pgm->pgm_tsdu_length));
 
390
}
 
391
 
 
392
/* 8.1.  Source Path Messages (SPM)
 
393
 *
 
394
 *  0                   1                   2                   3
 
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
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
405
 * |                            Path NLA                     ...   |
 
406
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+
 
407
 * | Option Extensions when present ...                            |
 
408
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
409
 *
 
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
 
413
 */
 
414
 
 
415
int
 
416
verify_spm (
 
417
        struct pgm_header*      header,
 
418
        char*                   data,
 
419
        guint                   len
 
420
        )
 
421
{
 
422
        int retval = 0;
 
423
 
 
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));
 
427
                retval = -1;
 
428
                goto out;
 
429
        }
 
430
 
 
431
        struct pgm_spm* spm = (struct pgm_spm*)data;
 
432
        char* opt_offset = (char*)(spm + 1);
 
433
        guint opt_len = len - sizeof(spm);
 
434
 
 
435
        switch (g_ntohs(spm->spm_nla_afi)) {
 
436
        case AFI_IP6:
 
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));
 
439
                        retval = -1;
 
440
                        goto out;
 
441
                }
 
442
                opt_offset += sizeof(struct pgm_spm6) - sizeof(struct pgm_spm);
 
443
                opt_len -= sizeof(struct pgm_spm6) - sizeof(struct pgm_spm);
 
444
 
 
445
        case AFI_IP:
 
446
                break;
 
447
 
 
448
        default:
 
449
                printf ("\t\"message\": \"SPM: invalid AFI of source NLA: %i.\",\n", g_ntohs(spm->spm_nla_afi));
 
450
                retval = -1;
 
451
                goto out;
 
452
        }
 
453
 
 
454
/* option extensions */
 
455
        if (header->pgm_options & PGM_OPT_PRESENT)
 
456
        {
 
457
                retval = verify_options (opt_offset, opt_len);
 
458
        }
 
459
 
 
460
out:
 
461
        return retval;
 
462
}
 
463
 
 
464
void
 
465
print_spm (
 
466
        struct pgm_header*      header,
 
467
        char*                   data
 
468
        )
 
469
{
 
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);
 
473
 
 
474
        puts (",");
 
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));
 
479
 
 
480
        char s[INET6_ADDRSTRLEN];
 
481
        switch (g_ntohs(spm->spm_nla_afi)) {
 
482
        case AFI_IP:
 
483
                pgm_inet_ntop ( AF_INET, &spm->spm_nla, s, sizeof (s) );
 
484
                break;
 
485
 
 
486
        case AFI_IP6:
 
487
                pgm_inet_ntop ( AF_INET6, &spm6->spm6_nla, s, sizeof (s) );
 
488
                opt_offset += sizeof(struct pgm_spm6) - sizeof(struct pgm_spm);
 
489
                break;
 
490
        }
 
491
 
 
492
        printf ("\t\t\"spmNla\": \"%s\"", s);
 
493
 
 
494
/* option extensions */
 
495
        if (header->pgm_options & PGM_OPT_PRESENT)
 
496
        {
 
497
                puts (",");
 
498
                print_options (opt_offset);
 
499
        }
 
500
 
 
501
        puts ("\n\t}");
 
502
}
 
503
 
 
504
/* 14.7.1.  Poll Request
 
505
 *
 
506
 *  0                   1                   2                   3
 
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
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
515
 * |                            Path NLA                     ...   |
 
516
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+
 
517
 * |                  POLL's  Back-off Interval                    |
 
518
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
519
 * |                        Random String                          |
 
520
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
521
 * |                      Matching Bit-Mask                        |
 
522
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
523
 * | Option Extensions when present ...                            |
 
524
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
525
 *
 
526
 * Sent to ODATA multicast group with IP Router Alert option.
 
527
 */
 
528
 
 
529
#define PGM_MIN_POLL_SIZE       ( sizeof(struct pgm_poll) )
 
530
 
 
531
int
 
532
verify_poll (
 
533
        G_GNUC_UNUSED struct pgm_header*        header,
 
534
        G_GNUC_UNUSED char*                     data,
 
535
        G_GNUC_UNUSED guint                     len
 
536
        )
 
537
{
 
538
        return -1;
 
539
}
 
540
 
 
541
void
 
542
print_poll (
 
543
        G_GNUC_UNUSED struct pgm_header*        header,
 
544
        G_GNUC_UNUSED char*                     data
 
545
        )
 
546
{
 
547
}
 
548
 
 
549
/* 14.7.2.  Poll Response
 
550
 *
 
551
 *  0                   1                   2                   3
 
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
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
560
 */
 
561
 
 
562
int
 
563
verify_polr (
 
564
        G_GNUC_UNUSED struct pgm_header*        header,
 
565
        G_GNUC_UNUSED char*                     data,
 
566
        G_GNUC_UNUSED guint                     len
 
567
        )
 
568
{
 
569
        return -1;
 
570
}
 
571
 
 
572
void
 
573
print_polr (
 
574
        G_GNUC_UNUSED struct pgm_header*        header,
 
575
        G_GNUC_UNUSED char*                     data
 
576
        )
 
577
{
 
578
}
 
579
 
 
580
/* 8.2.  Data Packet
 
581
 *
 
582
 *  0                   1                   2                   3
 
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
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ... -+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
591
 * | Data ...
 
592
 * +-+-+- ...
 
593
 */
 
594
 
 
595
int
 
596
verify_odata (
 
597
        struct pgm_header*      header,
 
598
        char*                   data,
 
599
        guint                   len
 
600
        )
 
601
{
 
602
        int retval = 0;
 
603
 
 
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));
 
606
                retval = -1;
 
607
                goto out;
 
608
        }
 
609
 
 
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)
 
613
        {
 
614
                retval = verify_options (tsdu, tsdu_len);
 
615
 
 
616
                guint opt_total_len = g_ntohs( OPTIONS_TOTAL_LEN(tsdu) );
 
617
                tsdu     += opt_total_len;
 
618
                tsdu_len -= opt_total_len;
 
619
        }
 
620
 
 
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);
 
623
                retval = -1;
 
624
        }
 
625
out:
 
626
        return retval;
 
627
}
 
628
 
 
629
void
 
630
print_odata (
 
631
        struct pgm_header*      header,
 
632
        char*                   data
 
633
        )
 
634
{
 
635
        struct pgm_data* odata = (struct pgm_data*)data;
 
636
        char* tsdu = data + sizeof(struct pgm_data);
 
637
 
 
638
        puts (",");
 
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));
 
641
 
 
642
/* option extensions */
 
643
        if (header->pgm_options & PGM_OPT_PRESENT)
 
644
        {
 
645
                print_options (tsdu);
 
646
                tsdu += g_ntohs( OPTIONS_TOTAL_LEN(tsdu) );
 
647
                puts (",");
 
648
        }
 
649
 
 
650
/* data */
 
651
        printf ("\t\t\"data\": \"");
 
652
        char* end = tsdu + g_ntohs (header->pgm_tsdu_length);
 
653
        while (tsdu < end) {
 
654
                if (isprint(*tsdu))
 
655
                        putchar(*tsdu);
 
656
                else
 
657
                        putchar('.');
 
658
                tsdu++;
 
659
        }
 
660
 
 
661
        puts ("\"");
 
662
        puts ("\t}");
 
663
}
 
664
 
 
665
/* 8.2.  Repair Data
 
666
 */
 
667
 
 
668
int
 
669
verify_rdata (
 
670
        struct pgm_header*      header,
 
671
        char*                   data,
 
672
        guint                   len
 
673
        )
 
674
{
 
675
        int retval = 0;
 
676
 
 
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));
 
679
                retval = -1;
 
680
                goto out;
 
681
        }
 
682
 
 
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)
 
686
        {
 
687
                retval = verify_options (tsdu, tsdu_len);
 
688
 
 
689
                guint opt_total_len = g_ntohs( OPTIONS_TOTAL_LEN(tsdu) );
 
690
                tsdu     += opt_total_len;
 
691
                tsdu_len -= opt_total_len;
 
692
        }
 
693
 
 
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);
 
696
                retval = -1;
 
697
        }
 
698
out:
 
699
        return retval;
 
700
}
 
701
 
 
702
void
 
703
print_rdata (
 
704
        struct pgm_header*      header,
 
705
        char*                   data
 
706
        )
 
707
{
 
708
        struct pgm_data* rdata = (struct pgm_data*)data;
 
709
        char* tsdu = data + sizeof(struct pgm_data);
 
710
 
 
711
        puts (",");
 
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));
 
714
 
 
715
/* option extensions */
 
716
        if (header->pgm_options & PGM_OPT_PRESENT)
 
717
        {
 
718
                print_options (tsdu);
 
719
                tsdu += g_ntohs( OPTIONS_TOTAL_LEN(tsdu) );
 
720
                puts (",");
 
721
        }
 
722
 
 
723
/* data */
 
724
        printf ("\t\t\"data\": \"");
 
725
        char* end = tsdu + g_ntohs (header->pgm_tsdu_length);
 
726
        while (tsdu < end) {
 
727
                if (isprint(*tsdu))
 
728
                        putchar(*tsdu);
 
729
                else
 
730
                        putchar('.');
 
731
                tsdu++;
 
732
        }
 
733
 
 
734
        puts ("\"");
 
735
        puts ("\t}");
 
736
}
 
737
 
 
738
/* 8.3.  NAK
 
739
 *
 
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
 
743
 * distribution.
 
744
 *
 
745
 *  0                   1                   2                   3
 
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
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
752
 * |                           Source NLA                    ...   |
 
753
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+
 
754
 * |            NLA AFI            |          Reserved             |
 
755
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 
756
 * |                      Multicast Group NLA                ...   |
 
757
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+
 
758
 * | Option Extensions when present ...
 
759
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ...
 
760
 */
 
761
 
 
762
int
 
763
verify_nak (
 
764
        struct pgm_header*      header,
 
765
        char*                   data,
 
766
        guint                   len
 
767
        )
 
768
{
 
769
        return generic_verify_nak ("NAK", header, data, len);
 
770
}
 
771
 
 
772
int
 
773
verify_ncf (
 
774
        struct pgm_header*      header,
 
775
        char*                   data,
 
776
        guint                   len
 
777
        )
 
778
{
 
779
        return generic_verify_nak ("NCF", header, data, len);
 
780
}
 
781
 
 
782
int
 
783
verify_nnak (
 
784
        struct pgm_header*      header,
 
785
        char*                   data,
 
786
        guint                   len
 
787
        )
 
788
{
 
789
        return generic_verify_nak ("NNAK", header, data, len);
 
790
}
 
791
 
 
792
static int
 
793
generic_verify_nak (
 
794
        const char*             name,           /* upper case */
 
795
        G_GNUC_UNUSED struct pgm_header*        header,
 
796
        char*                   data,
 
797
        guint                   len
 
798
        )
 
799
{
 
800
        int retval = 0;
 
801
 
 
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));
 
806
                retval = -1;
 
807
                goto out;
 
808
        }
 
809
 
 
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;
 
813
 
 
814
/* check source NLA: unicast address of the ODATA sender */
 
815
        switch (nak_src_nla_afi) {
 
816
        case AFI_IP:
 
817
                nak_grp_nla_afi = g_ntohs (nak->nak_grp_nla_afi);
 
818
                break;
 
819
 
 
820
        case AFI_IP6:
 
821
                nak_grp_nla_afi = g_ntohs (((struct pgm_nak6*)nak)->nak6_grp_nla_afi);
 
822
                break;
 
823
 
 
824
        default:
 
825
                printf ("\t\"message\": \"%s: invalid AFI of source NLA: %i.\",\n",
 
826
                        name, nak_src_nla_afi);
 
827
                retval = -1;
 
828
                goto out;
 
829
        }
 
830
 
 
831
/* check multicast group NLA */
 
832
        switch (nak_grp_nla_afi) {
 
833
        case AFI_IP6:
 
834
                switch (nak_src_nla_afi) {
 
835
/* IPv4 + IPv6 NLA */
 
836
                case AFI_IP:
 
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) ));
 
840
                                retval = -1;
 
841
                        }
 
842
                        break;
 
843
 
 
844
/* IPv6 + IPv6 NLA */
 
845
                case AFI_IP6:
 
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));
 
849
                                retval = -1;
 
850
                        }
 
851
                        break;
 
852
                }
 
853
                break;
 
854
 
 
855
        case AFI_IP:
 
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) ));
 
860
                                retval = -1;
 
861
                        }
 
862
                }
 
863
                break;
 
864
 
 
865
        default:
 
866
                printf ("\t\"message\": \"%s: invalid AFI of group NLA: %i.\",\n",
 
867
                        name, nak_grp_nla_afi);
 
868
                retval = -1;
 
869
                break;
 
870
        }
 
871
 
 
872
out:
 
873
        return retval;
 
874
}
 
875
 
 
876
void
 
877
print_nak (
 
878
        struct pgm_header*      header,
 
879
        char*                   data
 
880
        )
 
881
{
 
882
        generic_print_nak ("nak", header, data);
 
883
}
 
884
 
 
885
void
 
886
print_ncf (
 
887
        struct pgm_header*      header,
 
888
        char*                   data
 
889
        )
 
890
{
 
891
        generic_print_nak ("ncf", header, data);
 
892
}
 
893
 
 
894
void
 
895
print_nnak (
 
896
        struct pgm_header*      header,
 
897
        char*                   data
 
898
        )
 
899
{
 
900
        generic_print_nak ("nnak", header, data);
 
901
}
 
902
 
 
903
static void
 
904
generic_print_nak (
 
905
        const char*             name,           /* lower case */
 
906
        struct pgm_header*      header,
 
907
        char*                   data
 
908
        )
 
909
{
 
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);
 
913
 
 
914
        puts (",");
 
915
        printf ("\t\t\"%sSqn\": %lu,\n", name, (gulong)g_ntohl(nak->nak_sqn));
 
916
 
 
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];
 
920
 
 
921
        printf ("\t\t\"%sSourceNlaAfi\": %i,\n", name, nak_src_nla_afi);
 
922
 
 
923
/* source nla */
 
924
        switch (nak_src_nla_afi) {
 
925
        case AFI_IP:
 
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);
 
928
                break;
 
929
 
 
930
        case AFI_IP6:
 
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);
 
934
                break;
 
935
        }
 
936
 
 
937
        printf ("\t\t\"%sSourceNla\": \"%s\",\n", name, s);
 
938
        printf ("\t\t\"%sGroupNlaAfi\": %i,\n", name, nak_grp_nla_afi);
 
939
 
 
940
        switch (nak_grp_nla_afi) {
 
941
        case AFI_IP6:
 
942
                switch (nak_src_nla_afi) {
 
943
/* IPv4 + IPv6 NLA */
 
944
                case AFI_IP:
 
945
                        pgm_inet_ntop ( AF_INET6, &nak->nak_grp_nla, s, sizeof(s) );
 
946
                        break;
 
947
 
 
948
/* IPv6 + IPv6 NLA */
 
949
                case AFI_IP6:
 
950
                        pgm_inet_ntop ( AF_INET6, &nak6->nak6_grp_nla, s, sizeof(s) );
 
951
                        break;
 
952
                }
 
953
                opt_offset += sizeof(struct in6_addr) - sizeof(struct in_addr);
 
954
                break;
 
955
 
 
956
        case AFI_IP:
 
957
                switch (nak_src_nla_afi) {
 
958
/* IPv4 + IPv4 NLA */
 
959
                case AFI_IP:
 
960
                        pgm_inet_ntop ( AF_INET, &nak->nak_grp_nla, s, sizeof(s) );
 
961
                        break;
 
962
 
 
963
/* IPv6 + IPv4 NLA */
 
964
                case AFI_IP6:
 
965
                        pgm_inet_ntop ( AF_INET, &nak6->nak6_grp_nla, s, sizeof(s) );
 
966
                        break;
 
967
                }
 
968
                break;
 
969
        }
 
970
 
 
971
        printf ("\t\t\"%sGroupNla\": \"%s\"", name, s);
 
972
 
 
973
/* option extensions */
 
974
        if (header->pgm_options & PGM_OPT_PRESENT)
 
975
        {
 
976
                puts (",");
 
977
                print_options (opt_offset);
 
978
        }
 
979
 
 
980
        puts ("\n\t}");
 
981
}
 
982
 
 
983
 
 
984
/* 13.6.  SPM Request
 
985
 *
 
986
 *  0                   1                   2                   3
 
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
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- ...
 
991
 */
 
992
 
 
993
int
 
994
verify_spmr (
 
995
        struct pgm_header*      header,
 
996
        char*                   data,
 
997
        guint                   len
 
998
        )
 
999
{
 
1000
        int retval = 0;
 
1001
 
 
1002
        char* opt_offset = data;
 
1003
        guint opt_len = len;
 
1004
 
 
1005
/* option extensions */
 
1006
        if (header->pgm_options & PGM_OPT_PRESENT)
 
1007
        {
 
1008
                retval = verify_options (opt_offset, opt_len);
 
1009
        }
 
1010
 
 
1011
        return retval;
 
1012
}
 
1013
 
 
1014
void
 
1015
print_spmr (
 
1016
        struct pgm_header*      header,
 
1017
        char*                   data
 
1018
        )
 
1019
{
 
1020
        char* opt_offset = data;
 
1021
 
 
1022
/* option extensions */
 
1023
        if (header->pgm_options & PGM_OPT_PRESENT)
 
1024
        {
 
1025
                print_options (opt_offset);
 
1026
                puts ("");
 
1027
        }
 
1028
 
 
1029
        puts ("\t}");
 
1030
}
 
1031
 
 
1032
/* Parse PGM options fields:
 
1033
 *
 
1034
 * assume at least two options, one the mandatory OPT_LENGTH
 
1035
 */
 
1036
 
 
1037
#define PGM_MIN_OPT_SIZE        ( sizeof(struct pgm_opt_header) + sizeof(struct pgm_opt_length) )
 
1038
 
 
1039
int
 
1040
verify_options (
 
1041
        char*           data,
 
1042
        guint           len
 
1043
        )
 
1044
{
 
1045
        int retval = 0;
 
1046
 
 
1047
        if (len < PGM_MIN_OPT_SIZE) {
 
1048
                printf ("\t\"message\": \"PGM options: packet size too small for options.\",\n");
 
1049
                retval = -1;
 
1050
                goto out;
 
1051
        }
 
1052
 
 
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");
 
1057
                retval = -1;
 
1058
                goto out;
 
1059
        }
 
1060
 
 
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));
 
1063
                retval = -1;
 
1064
                goto out;
 
1065
        }
 
1066
 
 
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));
 
1069
                retval = -1;
 
1070
                goto out;
 
1071
        }
 
1072
 
 
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));
 
1075
                retval = -1;
 
1076
                goto out;
 
1077
        }
 
1078
 
 
1079
/* iterate through options (max 16) */
 
1080
        guint count = 0;
 
1081
        guint total_length = g_ntohs(opt_len->opt_total_length);
 
1082
 
 
1083
        guint opt_counters[256];
 
1084
        memset (&opt_counters, 0, sizeof(opt_counters));
 
1085
 
 
1086
        struct pgm_opt_header* opt_header = (struct pgm_opt_header*)data;
 
1087
        for (;;) {
 
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);
 
1091
                        retval = -1;
 
1092
                        goto out;
 
1093
                }
 
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);
 
1097
                        retval = -1;
 
1098
                        goto out;
 
1099
                }
 
1100
 
 
1101
                if (opt_counters[opt_header->opt_type]++) {
 
1102
                        printf ("\t\"message\": \"PGM options: duplicate option %i.\",\n", opt_header->opt_type);
 
1103
                        retval = -1;
 
1104
                        goto out;
 
1105
                }
 
1106
 
 
1107
/* check option types */
 
1108
                switch (opt_header->opt_type & PGM_OPT_MASK) {
 
1109
                case PGM_OPT_FRAGMENT:
 
1110
                {
 
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);
 
1113
                                retval = -1;
 
1114
                                goto out;
 
1115
                        }
 
1116
                        
 
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");
 
1120
                                retval = -1;
 
1121
                                goto out;
 
1122
                        }
 
1123
                        break;
 
1124
                }
 
1125
 
 
1126
                case PGM_OPT_NAK_LIST:
 
1127
                {
 
1128
                        guint list_len = opt_header->opt_length - sizeof(struct pgm_opt_header) - sizeof(guint8);
 
1129
                        if (list_len & 1) {
 
1130
                                printf ("\t\"message\": \"PGM options: OPT_NAK_LIST invalid odd length: %i bytes.\",\n", opt_header->opt_length);
 
1131
                                retval = -1;
 
1132
                                goto out;
 
1133
                        }
 
1134
 
 
1135
                        list_len /= 2;
 
1136
                        if (list_len == 0) {
 
1137
                                printf ("\t\"message\": \"PGM options: OPT_NAK_LIST empty.\",\n");
 
1138
                                retval = -1;
 
1139
                                goto out;
 
1140
                        }
 
1141
 
 
1142
                        if (list_len > 62) {
 
1143
                                printf ("\t\"message\": \"PGM options: OPT_NAK_LIST too long: %i sqns.\",\n", list_len);
 
1144
                                retval = -1;
 
1145
                                goto out;
 
1146
                        }
 
1147
                        break;
 
1148
                }
 
1149
 
 
1150
                case PGM_OPT_PARITY_PRM:
 
1151
                {
 
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");
 
1155
                                retval = -1;
 
1156
                                goto out;
 
1157
                        }
 
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);
 
1161
                                retval = -1;
 
1162
                                goto out;
 
1163
                        }
 
1164
                        break;
 
1165
                }
 
1166
 
 
1167
                default:
 
1168
/* unknown option, skip */
 
1169
                        break;
 
1170
                }
 
1171
/* end option types */
 
1172
 
 
1173
                if (opt_header->opt_type & PGM_OPT_END) {
 
1174
                        break;
 
1175
                }
 
1176
 
 
1177
                if (count++ == 16) {
 
1178
                        printf ("\t\"message\": \"PGM options: more than 16 options found.\",\n");
 
1179
                        retval = -1;
 
1180
                        goto out;
 
1181
                }
 
1182
        }
 
1183
 
 
1184
out:
 
1185
        return retval;
 
1186
}
 
1187
 
 
1188
static const char *opx_text[4] = {
 
1189
        "OPX_IGNORE",
 
1190
        "OPX_INVALIDATE",
 
1191
        "OPX_DISCARD",
 
1192
        "OPX_UNKNOWN"
 
1193
};
 
1194
 
 
1195
void
 
1196
print_options (
 
1197
        char*           data
 
1198
        )
 
1199
{
 
1200
        struct pgm_opt_length* opt_len = (struct pgm_opt_length*)data;
 
1201
 
 
1202
        puts ("\t\t\"pgmOptions\": [");
 
1203
        puts ("\t\t\t{");
 
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));
 
1207
        printf ("\t\t\t}");
 
1208
 
 
1209
/* iterate through options */
 
1210
        struct pgm_opt_header* opt_header = (struct pgm_opt_header*)data;
 
1211
        do {
 
1212
                opt_header = (struct pgm_opt_header*)( ((char*)opt_header) + opt_header->opt_length );
 
1213
 
 
1214
                puts (",");
 
1215
                puts ("\t\t\t{");
 
1216
                printf ("\t\t\t\t\"length\": \"%#x\",\n", opt_header->opt_length);
 
1217
 
 
1218
                switch (opt_header->opt_type & PGM_OPT_MASK) {
 
1219
                case PGM_OPT_FRAGMENT:
 
1220
                {
 
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));
 
1229
                        break;
 
1230
                }
 
1231
 
 
1232
                case PGM_OPT_NAK_LIST:
 
1233
                {
 
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] = "";
 
1241
                        guint i = 0;
 
1242
                        do {
 
1243
                                char sqn[1024];
 
1244
                                sprintf (sqn, "%s%i", (i>0)?", ":"", g_ntohl(opt_nak_list->opt_sqn[i]));
 
1245
                                strcat (sqns, sqn);
 
1246
                                i++;
 
1247
                        } while ((char*)&opt_nak_list->opt_sqn[i] < end);
 
1248
                        printf ("\t\t\t\t\"sqn\": [%s]\n", sqns);
 
1249
                        break;
 
1250
                }
 
1251
 
 
1252
                case PGM_OPT_PARITY_PRM:
 
1253
                {
 
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));
 
1262
                        break;
 
1263
                }
 
1264
 
 
1265
                case PGM_OPT_CURR_TGSIZE:
 
1266
                {
 
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));
 
1273
                        break;
 
1274
                }
 
1275
 
 
1276
                case PGM_OPT_SYN:
 
1277
                {
 
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");
 
1283
                        break;
 
1284
                }
 
1285
 
 
1286
                case PGM_OPT_FIN:
 
1287
                {
 
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");
 
1293
                        break;
 
1294
                }
 
1295
 
 
1296
                default:
 
1297
                {
 
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");
 
1303
                        break;
 
1304
                }
 
1305
                }
 
1306
                printf ("\t\t\t}");
 
1307
 
 
1308
        } while (!(opt_header->opt_type & PGM_OPT_END));
 
1309
 
 
1310
        printf ("\n\t\t]");
 
1311
}
 
1312
 
 
1313
/* eof */