aboutsummaryrefslogtreecommitdiff
path: root/sys/linux/vnet.txt
blob: b0038ff9272d7740758568b809a183a37b9c3ec5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
# Copyright 2017 syzkaller project authors. All rights reserved.
# Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

include <linux/types.h>
include <linux/byteorder/generic.h>

syz_emit_ethernet(len len[packet], packet ptr[in, eth_packet], frags ptr[in, vnet_fragmentation, opt])

vnet_fragmentation {
# If set and we have remaining data after fragmentation, it is written in an additional fragment.
# If not set, data remaining after fragmentation is discarded.
	full	int32[0:1]
	count	int32[1:4]
	frags	array[int32[0:4096], 4]
}

resource tcp_seq_num[int32]: 0x41424344

tcp_resources {
	seq	tcp_seq_num
	ack	tcp_seq_num
}

# These pseudo syscalls read a packet from /dev/net/tun and extract tcp sequence and acknowledgement numbers from it.
# They also adds the inc arguments to the returned values, this way sequence numbers get incremented.
syz_extract_tcp_res(res ptr[out, tcp_resources], seq_inc int32, ack_inc int32)
syz_extract_tcp_res$synack(res ptr[out, tcp_resources], seq_inc const[1], ack_inc const[0])

################################################################################
################################### Ethernet ###################################
################################################################################

# https://en.wikipedia.org/wiki/Ethernet_frame#Structure
# https://en.wikipedia.org/wiki/IEEE_802.1Q

include <uapi/linux/if.h>
include <uapi/linux/if_ether.h>

type mac_addr_t[LAST] {
	a0	array[const[0xaa, int8], 5]
	a1	LAST
} [packed]

mac_addr_link_local {
	a0	const[0x1, int8]
	a1	const[0x80, int8]
	a2	const[0xc2, int8]
	a3	const[0x0, int8]
	a4	const[0x0, int8]
	a5	flags[mac_addr_link_local_values, int8]
} [packed]

mac_addr_link_local_values = 0x0, 0x1, 0x2, 0x3, 0xe

# This corresponds to the last digit in DEV_MAC/DEV_IPV4/DEV_IPV6 in executor/common_linux.h
type netdev_addr_id int8[10:43]

mac_addr [
	empty		array[const[0x0, int8], 6]
# These correspond to LOCAL_MAC/REMOTE_MAC/DEV_MAC in executor/common_linux.h
	local		mac_addr_t[const[0xaa, int8]]
	remote		mac_addr_t[const[0xbb, int8]]
	dev		mac_addr_t[netdev_addr_id]
	broadcast	array[const[0xff, int8], 6]
	link_local	mac_addr_link_local
	random		array[int8, 6]
]

type mac_addr_mask array[flags[mac_addr_mask_vals, int8], 6]
mac_addr_mask_vals = 0, 0xff

vlan_tag_ad {
	tpid	const[ETH_P_QINQ1, int16be]
	pcp	int16:3
	dei	int16:1
	vid	int16:12[0:4]
} [packed]

vlan_tag_q {
	tpid	const[ETH_P_8021Q, int16be]
	pcp	int16:3
	dei	int16:1
	vid	int16:12[0:4]
} [packed]

vlan_tag {
	tag_ad	array[vlan_tag_ad, 0:1]
	tag_q	vlan_tag_q
} [packed]

eth_packet {
	dst_mac	mac_addr
	src_mac	mac_addr
	vtag	array[vlan_tag, 0:1]
	payload	eth_payload
} [packed]

eth_payload {
	eth2	eth2_packet
} [packed]

################################################################################
################################## Ethernet 2 ##################################
################################################################################

# https://en.wikipedia.org/wiki/Ethernet_frame#Ethernet_II

ether_types = ETH_P_LOOP, ETH_P_PUP, ETH_P_PUPAT, ETH_P_TSN, ETH_P_IP, ETH_P_X25, ETH_P_ARP, ETH_P_IEEEPUP, ETH_P_IEEEPUPAT, ETH_P_BATMAN, ETH_P_DEC, ETH_P_DNA_DL, ETH_P_DNA_RC, ETH_P_DNA_RT, ETH_P_LAT, ETH_P_DIAG, ETH_P_CUST, ETH_P_SCA, ETH_P_TEB, ETH_P_RARP, ETH_P_ATALK, ETH_P_AARP, ETH_P_8021Q, ETH_P_ERSPAN, ETH_P_ERSPAN2, ETH_P_IPX, ETH_P_IPV6, ETH_P_PAUSE, ETH_P_SLOW, ETH_P_WCCP, ETH_P_MPLS_UC, ETH_P_MPLS_MC, ETH_P_ATMMPOA, ETH_P_PPP_DISC, ETH_P_PPP_SES, ETH_P_LINK_CTL, ETH_P_ATMFATE, ETH_P_PAE, ETH_P_AOE, ETH_P_8021AD, ETH_P_802_EX1, ETH_P_TIPC, ETH_P_MACSEC, ETH_P_8021AH, ETH_P_MVRP, ETH_P_1588, ETH_P_NCSI, ETH_P_PRP, ETH_P_FCOE, ETH_P_TDLS, ETH_P_FIP, ETH_P_80221, ETH_P_HSR, ETH_P_LOOPBACK, ETH_P_QINQ1, ETH_P_QINQ2, ETH_P_QINQ3, ETH_P_EDSA, ETH_P_AF_IUCV, ETH_P_802_3_MIN, ETH_P_802_3, ETH_P_AX25, ETH_P_ALL, ETH_P_802_2, ETH_P_SNAP, ETH_P_DDCMP, ETH_P_WAN_PPP, ETH_P_PPP_MP, ETH_P_LOCALTALK, ETH_P_CAN, ETH_P_CANFD, ETH_P_PPPTALK, ETH_P_TR_802_2, ETH_P_MOBITEX, ETH_P_CONTROL, ETH_P_IRDA, ETH_P_ECONET, ETH_P_HDLC, ETH_P_ARCNET, ETH_P_DSA, ETH_P_TRAILER, ETH_P_PHONET, ETH_P_IEEE802154, ETH_P_CAIF, ETH_P_XDSA, ETH_P_MAP

eth2_packet [
	generic	eth2_packet_generic
	arp	eth2_packet_t[ETH_P_ARP, arp_packet]
	ipv4	eth2_packet_t[ETH_P_IP, ipv4_packet]
	ipv6	eth2_packet_t[ETH_P_IPV6, ipv6_packet]
	llc	eth2_packet_t[ETH_P_802_2, llc_packet]
	llc_tr	eth2_packet_t[ETH_P_TR_802_2, llc_packet]
	ipx	eth2_packet_t[ETH_P_IPX, ipx_packet]
	x25	eth2_packet_t[ETH_P_X25, x25_packet]
	mpls_uc	eth2_packet_t[ETH_P_MPLS_UC, mpls_packet]
	mpls_mc	eth2_packet_t[ETH_P_MPLS_MC, mpls_packet]
	can	eth2_packet_t[ETH_P_CAN, can_frame]
	canfd	eth2_packet_t[ETH_P_CANFD, canfd_frame]
] [varlen]

eth2_packet_generic {
	etype	flags[ether_types, int16be]
	payload	array[int8]
} [packed]

type eth2_packet_t[TYPE, PAYLOAD] {
	etype	const[TYPE, int16be]
	payload	PAYLOAD
} [packed]

################################################################################
###################################### ARP #####################################
################################################################################

# https://en.wikipedia.org/wiki/Address_Resolution_Protocol#Packet_structure

include <uapi/linux/if_arp.h>

arp_htypes = ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_EETHER, ARPHRD_AX25, ARPHRD_PRONET, ARPHRD_CHAOS, ARPHRD_IEEE802, ARPHRD_ARCNET, ARPHRD_APPLETLK, ARPHRD_DLCI, ARPHRD_ATM, ARPHRD_METRICOM, ARPHRD_IEEE1394, ARPHRD_EUI64, ARPHRD_INFINIBAND, ARPHRD_SLIP, ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6, ARPHRD_RSRVD, ARPHRD_ADAPT, ARPHRD_ROSE, ARPHRD_X25, ARPHRD_HWX25, ARPHRD_CAN, ARPHRD_PPP, ARPHRD_CISCO, ARPHRD_HDLC, ARPHRD_LAPB, ARPHRD_DDCMP, ARPHRD_RAWHDLC, ARPHRD_TUNNEL, ARPHRD_TUNNEL6, ARPHRD_FRAD, ARPHRD_SKIP, ARPHRD_LOOPBACK, ARPHRD_LOCALTLK, ARPHRD_FDDI, ARPHRD_BIF, ARPHRD_SIT, ARPHRD_IPDDP, ARPHRD_IPGRE, ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET, ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_IEEE802154, ARPHRD_IEEE802154_MONITOR, ARPHRD_PHONET, ARPHRD_PHONET_PIPE, ARPHRD_CAIF, ARPHRD_IP6GRE, ARPHRD_NETLINK, ARPHRD_6LOWPAN, ARPHRD_VOID, ARPHRD_NONE

arp_ops = ARPOP_REQUEST, ARPOP_REPLY, ARPOP_RREQUEST, ARPOP_RREPLY, ARPOP_InREQUEST, ARPOP_InREPLY, ARPOP_NAK

arp_generic_packet {
	htype	flags[arp_htypes, int16be]
	ptype	flags[ether_types, int16be]
	hlen	const[6, int8]
	plen	len[spa, int8]
	op	flags[arp_ops, int16be]
	sha	mac_addr
	spa	array[int8, 0:16]
	tha	mac_addr
	tpa	array[int8, 16]
} [packed]

arp_ether_ipv4_packet {
	htype	const[ARPHRD_ETHER, int16be]
	ptype	const[ETH_P_IP, int16be]
	hlen	const[6, int8]
	plen	const[4, int8]
	op	flags[arp_ops, int16be]
	sha	mac_addr
	spa	ipv4_addr
	tha	mac_addr
	tpa	ipv4_addr
} [packed]

arp_ether_ipv6_packet {
	htype	const[ARPHRD_ETHER, int16be]
	ptype	const[ETH_P_IPV6, int16be]
	hlen	const[6, int8]
	plen	const[16, int8]
	op	flags[arp_ops, int16be]
	sha	mac_addr
	spa	ipv6_addr
	tha	mac_addr
	tpa	ipv6_addr
} [packed]

arp_packet [
	generic		arp_generic_packet
	ether_ipv4	arp_ether_ipv4_packet
	ether_ipv6	arp_ether_ipv6_packet
] [varlen]

################################################################################
################################## 802.2 (LLC) #################################
################################################################################

# https://en.wikipedia.org/wiki/IEEE_802.2
# https://en.wikipedia.org/wiki/Subnetwork_Access_Protocol

include <uapi/linux/llc.h>

# Adding '1' as a SAP value since the lower bit in SAP has a special meaning.
sap_values = 1, LLC_SAP_NULL, LLC_SAP_LLC, LLC_SAP_SNA, LLC_SAP_PNM, LLC_SAP_IP, LLC_SAP_BSPAN, LLC_SAP_MMS, LLC_SAP_8208, LLC_SAP_3COM, LLC_SAP_PRO, LLC_SAP_SNAP, LLC_SAP_BANYAN, LLC_SAP_IPX, LLC_SAP_NETBEUI, LLC_SAP_LANMGR, LLC_SAP_IMPL, LLC_SAP_DISC, LLC_SAP_OSI, LLC_SAP_LAR, LLC_SAP_RM, LLC_SAP_GLOBAL

llc_generic_packet {
	dsap	flags[sap_values, int8]
	ssap	flags[sap_values, int8]
	ctrl	array[int8, 1:2]
	payload	array[int8]
} [packed]

sap_snap_values = 1, LLC_SAP_SNAP

llc_snap_packet {
	dsap		flags[sap_snap_values, int8]
	ssap		flags[sap_snap_values, int8]
	control		array[int8, 1:2]
	oui		array[int8, 3]
	protocol_id	flags[ether_types, int16be]
	payload		array[int8]
} [packed]

llc_payload [
	llc	llc_generic_packet
	snap	llc_snap_packet
] [varlen]

llc_packet {
# TODO: is there length or not? I don't see it in packet format...
#	length	len[payload, int16be]
	payload	llc_payload
} [packed]

################################################################################
###################################### IPX #####################################
################################################################################

# http://www.networksorcery.com/enp/protocol/ipx.htm
# https://en.wikipedia.org/wiki/Internetwork_Packet_Exchange#IPX_packet_structure

include <net/ipx.h>

ipx_network [
	random		int32be
	current		const[0x0, int32be]
	broadcast	const[0xffffffff, int32be]
]

ipx_node [
	random		array[int8, 6]
	current		array[const[0x0, int8], 6]
	broadcast	array[const[0xff, int8], 6]
]

ipx_addr {
	network	ipx_network
	node	ipx_node
	socket	int16be
} [packed]

ipx_packet_types = IPX_TYPE_UNKNOWN, IPX_TYPE_RIP, IPX_TYPE_SAP, IPX_TYPE_SPX, IPX_TYPE_NCP, IPX_TYPE_PPROP

ipx_packet {
	csum		const[0xffff, int16be]
	length		len[parent, int16be]
	control		int8
	type		flags[ipx_packet_types, int8]
	dst_addr	ipx_addr
	src_addr	ipx_addr
	payload		array[int8]
} [packed]

# TODO: setup ipx on virtual interfaces in executor
# TODO: describe particular ipx types
# TODO: open ipx sockets from userspace

################################################################################
###################################### x25 #####################################
################################################################################

# Documentation/networking/x25.txt
# Documentation/networking/x25-iface.txt
# http://www.dafuer.com/kleinehelferlein/x25layer.htm

include <uapi/linux/if_x25.h>
include <net/x25.h>

x25_iface_types = X25_IFACE_DATA, X25_IFACE_CONNECT, X25_IFACE_DISCONNECT, X25_IFACE_PARAMS

x25_frame_types = X25_CALL_REQUEST, X25_CALL_ACCEPTED, X25_CLEAR_REQUEST, X25_CLEAR_CONFIRMATION, X25_DATA, X25_INTERRUPT, X25_INTERRUPT_CONFIRMATION, X25_RR, X25_RNR, X25_REJ, X25_RESET_REQUEST, X25_RESET_CONFIRMATION, X25_REGISTRATION_REQUEST, X25_REGISTRATION_CONFIRMATION, X25_RESTART_REQUEST, X25_RESTART_CONFIRMATION, X25_DIAGNOSTIC, X25_ILLEGAL

x25_packet {
	iface	flags[x25_iface_types, int8]
	wtf	int8
	frame	flags[x25_frame_types, int8]
	payload	array[int8]
} [packed]

################################################################################
##################################### IPv4 #####################################
################################################################################

# https://tools.ietf.org/html/rfc791#section-3.1
# https://en.wikipedia.org/wiki/IPv4#Header

# TODO: https://en.wikipedia.org/wiki/IPsec#Authentication_Header
# TODO: https://en.wikipedia.org/wiki/IPsec#Encapsulating_Security_Payload

include <uapi/linux/in.h>
include <uapi/linux/ip.h>
include <uapi/linux/l2tp.h>
include <net/cipso_ipv4.h>

type ipv4_addr_t[LAST] {
	a0	const[0xac, int8]
	a1	const[0x14, int8]
	a2	const[0x14, int8]
	a3	LAST
} [packed]

ipv4_addr_initdev {
	a0	const[0xac, int8]
	a1	const[0x1e, int8]
	a2	int8[0:1]
	a3	proc[1, 1, int8]
}

ipv4_addr [
# random
	rand_addr	int32be
# 0.0.0.0
	empty		const[0x0, int32be]
# These correspond to LOCAL_IPV4/REMOTE_IPV4/DEV_IPV4 in executor/common_linux.h
	local		ipv4_addr_t[const[170, int8]]
	remote		ipv4_addr_t[const[187, int8]]
	dev		ipv4_addr_t[netdev_addr_id]
	initdev		ipv4_addr_initdev
# 127.0.0.1
	loopback	const[0x7f000001, int32be]
# 224.0.0.1
	multicast1	const[0xe0000001, int32be]
# 224.0.0.2
	multicast2	const[0xe0000002, int32be]
# 255.255.255.255
	broadcast	const[0xffffffff, int32be]
] [size[4]]

type ipv4_addr_mask flags[ipv4_addr_mask_vals, int32be]
ipv4_addr_mask_vals = 0, 0xff000000, 0xffffff00, 0xffffffff, 0xff

# http://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml#ip-parameters-1
ipv4_option [
	generic		ipv4_option_generic
	end		ipv4_option_end
	noop		ipv4_option_noop
	lsrr		ipv4_option_lsrr
	ssrr		ipv4_option_ssrr
	rr		ipv4_option_rr
	timestamp	ipv4_option_timestamp
	cipso		ipv4_option_cipso
	ra		ipv4_option_ra
# IPOPT_SEC and IPOPT_SID are not supported by Linux kernel
] [varlen]

ipv4_option_types = IPOPT_END, IPOPT_NOOP, IPOPT_SEC, IPOPT_LSRR, IPOPT_TIMESTAMP, IPOPT_CIPSO, IPOPT_RR, IPOPT_SID, IPOPT_SSRR, IPOPT_RA

ipv4_option_generic {
	type	flags[ipv4_option_types, int8]
	length	len[parent, int8]
	data	array[int8, 0:16]
} [packed]

# https://tools.ietf.org/html/rfc791#section-3.1
ipv4_option_end {
	type	const[IPOPT_END, int8]
} [packed]

# https://tools.ietf.org/html/rfc791#section-3.1
ipv4_option_noop {
	type	const[IPOPT_NOOP, int8]
} [packed]

# https://tools.ietf.org/html/rfc791#section-3.1
ipv4_option_lsrr {
	type	const[IPOPT_LSRR, int8]
	length	len[parent, int8]
	pointer	int8
	data	array[ipv4_addr]
} [packed]

# https://tools.ietf.org/html/rfc791#section-3.1
ipv4_option_ssrr {
	type	const[IPOPT_SSRR, int8]
	length	len[parent, int8]
	pointer	int8
	data	array[ipv4_addr]
} [packed]

# https://tools.ietf.org/html/rfc791#section-3.1
ipv4_option_rr {
	type	const[IPOPT_RR, int8]
	length	len[parent, int8]
	pointer	int8
	data	array[ipv4_addr]
} [packed]

ipv4_option_timestamp_flags = IPOPT_TS_TSONLY, IPOPT_TS_TSANDADDR, IPOPT_TS_PRESPEC

ipv4_option_timestamp_timestamp {
	addr		array[ipv4_addr, 0:1]
	timestamp	int32be
} [packed]

# https://tools.ietf.org/html/rfc791#section-3.1
# http://www.networksorcery.com/enp/protocol/ip/option004.htm
ipv4_option_timestamp {
	type		const[IPOPT_TIMESTAMP, int8]
	length		len[parent, int8]
	pointer		int8
	flg		flags[ipv4_option_timestamp_flags, int8:4]
	oflw		int8:4
	timestamps	array[ipv4_option_timestamp_timestamp]
} [packed]

ipv4_option_cipso_tag_types = CIPSO_V4_TAG_INVALID, CIPSO_V4_TAG_RBITMAP, CIPSO_V4_TAG_ENUM, CIPSO_V4_TAG_RANGE, CIPSO_V4_TAG_PBITMAP, CIPSO_V4_TAG_FREEFORM

# TODO: describe particular tag types
ipv4_option_cipso_tag {
	type	flags[ipv4_option_cipso_tag_types, int8]
	length	len[parent, int8]
	data	array[int8, 0:16]
} [packed]

# https://www.ietf.org/archive/id/draft-ietf-cipso-ipsecurity-01.txt
ipv4_option_cipso {
	type	const[IPOPT_CIPSO, int8]
	length	len[parent, int8]
	doi	int32be
	tags	array[ipv4_option_cipso_tag]
} [packed]

# https://tools.ietf.org/html/rfc2113
ipv4_option_ra {
	type	const[IPOPT_RA, int8]
	length	len[parent, int8]
	value	int32be
} [packed]

ipv4_options {
	options	array[ipv4_option]
} [packed, align_4]

ipv4_types = IPPROTO_IP, IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_TCP, IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_TP, IPPROTO_DCCP, IPPROTO_IPV6, IPPROTO_RSVP, IPPROTO_GRE, IPPROTO_ESP, IPPROTO_AH, IPPROTO_MTP, IPPROTO_BEETPH, IPPROTO_ENCAP, IPPROTO_PIM, IPPROTO_COMP, IPPROTO_SCTP, IPPROTO_UDPLITE, IPPROTO_MPLS, IPPROTO_RAW, IPPROTO_L2TP

ipv4_header {
	ihl		bytesize4[parent, int8:4]
	version		const[4, int8:4]
	ecn		int8:2
	dscp		int8:6
	total_len	len[ipv4_packet, int16be]
	id		int16be[100:104]
	frag_off	int16be
# TODO: frag_off is actually 13 bits, 3 bits are flags
	ttl		int8
	protocol	flags[ipv4_types, int8]
	csum		csum[parent, inet, int16be]
	src_ip		ipv4_addr
	dst_ip		ipv4_addr
	options		ipv4_options
} [packed]

ipv4_packet {
	header	ipv4_header
	payload	ipv4_payload
} [packed]

################################################################################
##################################### IPv6 #####################################
################################################################################

# https://tools.ietf.org/html/rfc2460#section-3
# https://en.wikipedia.org/wiki/IPv6_packet#Fixed_header

include <uapi/linux/in6.h>
include <uapi/linux/ipv6.h>
include <uapi/linux/seg6.h>
include <uapi/linux/ip6_tunnel.h>
include <net/ipv6.h>

ipv6_types = IPPROTO_IP, IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_TCP, IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_TP, IPPROTO_DCCP, IPPROTO_IPV6, IPPROTO_RSVP, IPPROTO_GRE, IPPROTO_ESP, IPPROTO_AH, IPPROTO_MTP, IPPROTO_BEETPH, IPPROTO_ENCAP, IPPROTO_PIM, IPPROTO_COMP, IPPROTO_SCTP, IPPROTO_UDPLITE, IPPROTO_MPLS, IPPROTO_RAW, IPPROTO_HOPOPTS, IPPROTO_ROUTING, IPPROTO_FRAGMENT, IPPROTO_ICMPV6, IPPROTO_NONE, IPPROTO_DSTOPTS, IPPROTO_MH, NEXTHDR_HOP, NEXTHDR_ROUTING, NEXTHDR_FRAGMENT, NEXTHDR_GRE, NEXTHDR_ESP, NEXTHDR_AUTH, NEXTHDR_ICMP, NEXTHDR_NONE, NEXTHDR_DEST, NEXTHDR_MOBILITY, IPPROTO_L2TP

ipv6_addr_empty {
	a0	array[const[0x0, int8], 16]
}

type ipv6_addr_t[LAST] {
	a0	const[0xfe, int8]
	a1	const[0x80, int8]
	a2	array[const[0x0, int8], 13]
	a3	LAST
} [packed]

ipv6_addr_initdev {
	a0	const[0xfe, int8]
	a1	const[0x88, int8]
	a2	array[const[0x0, int8], 12]
	a3	int8[0:1]
	a4	proc[1, 1, int8]
}

ipv6_addr_loopback {
	a0	const[0, int64be]
	a1	const[1, int64be]
} [packed, align_4]

ipv6_addr_ipv4 {
	a0	array[const[0x0, int8], 10]
	a1	array[const[0xff, int8], 2]
	a3	ipv4_addr
} [packed]

ipv6_addr_multicast1 {
	a0	const[0xff, int8]
	a1	const[0x1, int8]
	a2	array[const[0x0, int8], 13]
	a3	const[0x1, int8]
} [packed]

ipv6_addr_multicast2 {
	a0	const[0xff, int8]
	a1	const[0x2, int8]
	a2	array[const[0x0, int8], 13]
	a3	const[0x1, int8]
} [packed]

ipv6_addr [
	rand_addr	array[int8, 16]
	empty		ipv6_addr_empty
# These correspond to LOCAL_IPV6/REMOTE_IPV6/DEV_IPV6 in executor/common_linux.h
	local		ipv6_addr_t[const[0xaa, int8]]
	remote		ipv6_addr_t[const[0xbb, int8]]
	dev		ipv6_addr_t[netdev_addr_id]
	initdev		ipv6_addr_initdev
	loopback	ipv6_addr_loopback
	ipv4		ipv6_addr_ipv4
	mcast1		ipv6_addr_multicast1
	mcast2		ipv6_addr_multicast2
] [size[16]]

type ipv6_addr_mask array[flags[ipv4_addr_mask_vals, int32be], 4]

# TODO: Describe more types of headers
# NEXTHDR_HOP, NEXTHDR_TCP, NEXTHDR_UDP, NEXTHDR_IPV6, NEXTHDR_FRAGMENT, NEXTHDR_GRE, NEXTHDR_ESP, NEXTHDR_AUTH, NEXTHDR_ICMP, NEXTHDR_NONE, NEXTHDR_DEST, NEXTHDR_SCTP, NEXTHDR_MOBILITY
# https://tools.ietf.org/html/rfc2402
# https://tools.ietf.org/html/rfc2406
# https://tools.ietf.org/html/rfc3775

# https://tools.ietf.org/html/rfc2460#section-4
# The length field in each of the extension headers specifies the
# length of the header in 8-octet units not including the first 8 octets.
ipv6_ext_header [
	hopopts		ipv6_hopots_ext_header
	routing		ipv6_rt_hdr
	srh		ipv6_sr_hdr
	fragment	ipv6_fragment_ext_header
	dstopts		ipv6_dstopts_ext_header
] [varlen]

ipv6_hopots_ext_header {
	next_header	flags[ipv6_types, int8]
	length		bytesize8[options, int8]
	pad		array[const[0, int8], 6]
	options		array[ipv6_tlv_option]
} [packed, align_8]

ipv6_routing_types = IPV6_SRCRT_STRICT, IPV6_SRCRT_TYPE_0, IPV6_SRCRT_TYPE_2

ipv6_rt_hdr {
	next_header	flags[ipv6_types, int8]
	length		bytesize8[data, int8]
	routing_type	flags[ipv6_routing_types, int8]
	segments_left	int8
	reserved	const[0, int32]
	data		array[ipv6_addr]
} [packed, align_8]

ipv6_sr_hdr {
	nexthdr		flags[ipv6_types, int8]
	hdrlen		bytesize8[segments, int8]
	type		const[IPV6_SRCRT_TYPE_4, int8]
	segments_left	len[segments, int8]
	first_segment	int8
	flags		flags[ipv6_sr_flags, int8]
	tag		int16
	segments	array[ipv6_addr]
# TODO: this may be followed by sr6_tlv_hmac if SR6_FLAG1_HMAC is set.
# However, if we place it here, we won't be able to calculate hdrlen (len of 2 fields),
# and if we move segments and sr6_tlv_hmac into a separate struct,
# we won't be able to calculate segments_left because it will need to
# refer to a field of a subobject. What may help is allowing specifying
# subfields as len/bytesize targets, e.g. "len[payload.segments]", or "bytesize[parent_struct.foo]".
} [packed, align_8]

ipv6_sr_flags = SR6_FLAG1_PROTECTED, SR6_FLAG1_OAM, SR6_FLAG1_ALERT, SR6_FLAG1_HMAC

ipv6_fragment_ext_header {
	next_header	flags[ipv6_types, int8]
	reserved1	const[0, int8]
	fragment_off_hi	int8
	m_flag		int8:1
	reserved2	const[0, int8:2]
	fragment_off_lo	int8:5
	identification	int32[100:104]
} [packed, align_8]

ipv6_dstopts_ext_header {
	next_header	flags[ipv6_types, int8]
	length		bytesize8[options, int8]
	pad		array[const[0, int8], 6]
	options		array[ipv6_tlv_option]
} [packed, align_8]

ipv6_tlv_option [
	generic	ipv6_tlv_generic
	pad1	ipv6_tlv_pad1
	padn	ipv6_tlv_padn
	ra	ipv6_tlv_ra
	jumbo	ipv6_tlv_jumbo
	calipso	ipv6_tlv_calipso
	hao	ipv6_tlv_hao
	enc_lim	ipv6_tlv_enc_lim
] [varlen]

ipv6_tlv_generic {
	type	int8
	length	len[data, int8]
	data	array[int8]
} [packed]

ipv6_tlv_pad1 {
	type	const[IPV6_TLV_PAD1, int8]
	len	const[1, int8]
	pad	const[0, int8]
} [packed]

ipv6_tlv_padn {
	type	const[IPV6_TLV_PADN, int8]
	len	len[pad, int8]
	pad	array[const[0, int8]]
} [packed]

ipv6_tlv_ra {
	type	const[IPV6_TLV_ROUTERALERT, int8]
	len	const[2, int8]
	ra	int16be
} [packed]

ipv6_tlv_jumbo {
	type	const[IPV6_TLV_JUMBO, int8]
	len	const[4, int8]
	pkt_len	int32be
} [packed]

# https://tools.ietf.org/html/rfc5570#section-5.1
ipv6_tlv_calipso {
	type	const[IPV6_TLV_CALIPSO, int8]
	len	bytesize[payload, int8]
	payload	ipv6_tlv_calipso_payload
} [packed]

# TODO: checksum is generally incorrect.
# TODO: domain should be flags, but it's unclear if we have any domains registered by default.
ipv6_tlv_calipso_payload {
	domain			int32be
	compartment_length	bytesize4[compartment_bitmap, int8]
	sensitivity_level	int8
	checksum		int16
	compartment_bitmap	array[int64]
} [packed]

ipv6_tlv_hao {
	type	const[IPV6_TLV_HAO, int8]
	len	bytesize[addr, int8]
	addr	ipv6_addr
} [packed]

ipv6_tlv_enc_lim {
	type		const[IPV6_TLV_TNL_ENCAP_LIMIT, int8]
	len		const[1, int8]
	encap_limit	int8
} [packed]

ipv6_packet {
	priority	int8:4
	version		const[6, int8:4]
	flow_label	array[int8, 3]
# TODO: flow_label is actually 20 bits, 4 bits are part of priority
	length		len[payload, int16be]
	next_header	flags[ipv6_types, int8]
	hop_limit	int8
	src_ip		ipv6_addr
	dst_ip		ipv6_addr
	payload		ipv6_packet_payload
} [packed]

ipv6_packet_payload {
	ext_headers	array[ipv6_ext_header]
	payload		ipv6_payload
} [packed]

################################################################################
###################################### IP ######################################
################################################################################

ipv4_payload [
	tcp	tcp_packet
	udp	udp_packet
	icmp	icmp_packet
	dccp	dccp_packet
	igmp	igmp_packet
	gre	gre_packet
	tipc	tipc_packet
] [varlen]

ipv6_payload [
	tcp	tcp_packet
	udp	udp_packet
	icmpv6	icmpv6_packet
	dccp	dccp_packet
	gre	gre_packet
	tipc	tipc_packet
] [varlen]

################################################################################
###################################### TCP #####################################
################################################################################

# https://tools.ietf.org/html/rfc793#section-3.1
# https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure
# http://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml

include <net/tcp.h>
include <uapi/linux/tcp.h>

tcp_option [
	generic		tcp_generic_option
	nop		tcp_nop_option
	eol		tcp_eol_option
	mss		tcp_mss_option
	window		tcp_window_option
	sack_perm	tcp_sack_perm_option
	sack		tcp_sack_option
	timestamp	tcp_timestamp_option
	md5sig		tcp_md5sig_option
	fastopen	tcp_fastopen_option
	exp_fastopen	tcp_exp_fastopen_option
	exp_smc		tcp_exp_smc_option
	mptcp		tcp_mptcp_option
] [varlen]

tcp_option_types = TCPOPT_NOP, TCPOPT_EOL, TCPOPT_MSS, TCPOPT_WINDOW, TCPOPT_SACK_PERM, TCPOPT_SACK, TCPOPT_TIMESTAMP, TCPOPT_MD5SIG, TCPOPT_FASTOPEN, TCPOPT_EXP

tcp_generic_option {
	type	flags[tcp_option_types, int8]
	length	len[parent, int8]
	data	array[int8, 0:16]
} [packed]

# https://tools.ietf.org/html/rfc793#section-3.1
tcp_nop_option {
	type	const[TCPOPT_NOP, int8]
} [packed]

# https://tools.ietf.org/html/rfc793#section-3.1
tcp_eol_option {
	type	const[TCPOPT_EOL, int8]
} [packed]

# https://tools.ietf.org/html/rfc793#section-3.1
tcp_mss_option {
	type		const[TCPOPT_MSS, int8]
	length		len[parent, int8]
	seg_size	int16
} [packed]

# https://tools.ietf.org/html/rfc7323#section-2
tcp_window_option {
	type	const[TCPOPT_WINDOW, int8]
	length	len[parent, int8]
	shift	int8
} [packed]

# https://tools.ietf.org/html/rfc2018#section-2
tcp_sack_perm_option {
	type	const[TCPOPT_SACK_PERM, int8]
	length	len[parent, int8]
} [packed]

# https://tools.ietf.org/html/rfc2018#section-3
tcp_sack_option {
	type	const[TCPOPT_SACK, int8]
	length	len[parent, int8]
	data	array[int32be]
} [packed]

# https://tools.ietf.org/html/rfc7323#section-3
tcp_timestamp_option {
	type	const[TCPOPT_TIMESTAMP, int8]
	length	len[parent, int8]
	tsval	int32be
	tsecr	int32be
} [packed]

# https://tools.ietf.org/html/rfc2385#section-3.0
tcp_md5sig_option {
	type	const[TCPOPT_MD5SIG, int8]
	length	len[parent, int8]
	md5	array[int8, 16]
} [packed]

# https://tools.ietf.org/html/rfc7413#section-4.1.1
tcp_fastopen_option {
	type	const[TCPOPT_FASTOPEN, int8]
	length	len[parent, int8]
	data	array[int8, 0:16]
} [packed]

tcp_exp_fastopen_option {
	type	const[TCPOPT_EXP, int8]
	length	len[parent, int8]
	subtype	const[TCPOPT_FASTOPEN_MAGIC, int16be]
	data	array[int8, 0:16]
} [packed]

tcp_exp_smc_option {
	type	const[TCPOPT_EXP, int8]
	length	len[parent, int8]
	subtype	const[TCPOPT_SMC_MAGIC, int32be]
} [packed]

tcp_options {
	options	array[tcp_option]
} [packed, align_4]

tcp_flags = 0, TCPHDR_FIN, TCPHDR_SYN, TCPHDR_RST, TCPHDR_PSH, TCPHDR_ACK, TCPHDR_URG, TCPHDR_ECE, TCPHDR_CWR, TCPHDR_SYN_ECN

tcp_header {
	src_port	sock_port
	dst_port	sock_port
	seq_num		tcp_seq_num
	ack_num		tcp_seq_num
	ns		int8:1
	reserved	const[0, int8:3]
	data_off	bytesize4[parent, int8:4]
	flags		flags[tcp_flags, int8]
	window_size	int16be
	csum		csum[tcp_packet, pseudo, IPPROTO_TCP, int16be]
	urg_ptr		int16be
	options		tcp_options
} [packed]

tcp_packet {
	header	tcp_header
	payload	tcp_payload
} [packed]

tcp_payload {
	payload	array[int8]
} [packed]

################################################################################
###################################### UDP #####################################
################################################################################

# https://tools.ietf.org/html/rfc768
# https://en.wikipedia.org/wiki/User_Datagram_Protocol#Packet_structure

include <net/gue.h>

udp_packet {
	src_port	sock_port
	dst_port	sock_port
	length		len[parent, int16be]
	csum		csum[parent, pseudo, IPPROTO_UDP, int16be]
	extensions	array[udp_extensions]
	data		array[int8]
} [packed]

udp_extensions [
	guehdr	guehdr
] [varlen]

guehdr {
	hlen		bytesize4[parent, int8:5]
	control		int8:1
	version		int8:2
	proto_ctype	int8
	flags		flags[guehdr_flags, int16]
	priv		array[flags[guehdr_prov_flags, int32], 0:1]
} [packed]

guehdr_flags = GUE_FLAG_PRIV
guehdr_prov_flags = GUE_PFLAG_REMCSUM

################################################################################
###################################### GRE #####################################
################################################################################

# https://en.wikipedia.org/wiki/Generic_Routing_Encapsulation

include <net/gre.h>

gre_packet {
	pptp		gre_packet_pptp
# TODO: add more packets
# TODO: the payload should be ipv4_packet/ipv6_packet, but this creates recursion
# ipv4 -> gre -> ipv4 -> ...
	cisco_ipv4	gre_packet_cisco[ETH_P_IP, array[int8]]
	cisco_ipv6	gre_packet_cisco[ETH_P_IPV6, array[int8]]
	erspan1		gre_packet_erspan[ETH_P_ERSPAN, erspan_md1]
	erspan2		gre_packet_erspan[ETH_P_ERSPAN2, erspan_md2]
	teb		gre_packet_erspan[ETH_P_TEB, array[int8]]
} [packed]

type gre_packet_cisco[PROTO, PAYLOAD] {
	C		int16:1
	R		const[0, int16:1]
	K		int16:1
	S		int16:1
	reserved	const[0, int16:9]
	version		const[0, int16:3]
	protocol	const[PROTO, int16be]
# checksum, key, sequence number
	add		array[int16be, 0:3]
	payload		PAYLOAD
} [packed]

gre_packet_pptp {
	C		const[0, int16:1]
	R		const[0, int16:1]
	K		const[1, int16:1]
	S		int16:1
	reserved	const[0, int16:4]
	A		int16:1
	flags		const[0, int16:4]
	version		const[1, int16:3]
	protocol	const[0x880b, int16be]
	payload_len	bytesize[payload, int16be]
	key_call_id	pptp_call_id
# sequence/ack number
	add		array[int16be, 0:2]
	payload		ppp_packet
} [packed]

type ppp_packet array[int8]

type gre_packet_erspan[PROTO, PAYLOAD] {
	H		const[8, int16]
	protocol	const[PROTO, int16be]
	seq		int32be[0:4]
	payload		PAYLOAD
} [packed]

################################################################################
##################################### ERSPAN ###################################
################################################################################

include <net/erspan.h>
include <uapi/linux/erspan.h>

type erspan_base_hdr[VER] {
	vlan_upper		int8:4
	ver			const[VER, int8:4]
	vlan			int8
	session_id_upper	int8:2
	t			int8:1
	en			int8:2
	cos			int8:3
	session_id		int8
} [packed]

erspan_md1 {
	base	erspan_base_hdr[1]
	version	const[1, int32]
	index	int32be
} [packed]

erspan_md2 {
	base		erspan_base_hdr[2]
	version		const[2, int32]
	timestamp	int32be
	sgt		int16be
	hwid_upper	int8:2
	ft		int8:5
	p		int8:1
	o		int8:1
	gra		int8:2
	dir		int8:1
	hwid		int8:1
} [packed]

################################################################################
###################################### ICMP ####################################
################################################################################

# https://en.wikipedia.org/wiki/Internet_Control_Message_Protocol#ICMP_datagram_structure
# https://tools.ietf.org/html/rfc792
# https://tools.ietf.org/html/rfc4884#section-4.1
# http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml

include <uapi/linux/icmp.h>

icmp_ipv4_header {
	ihl		bytesize4[parent, int8:4]
	version		const[4, int8:4]
	ecn		int8:2
	dscp		int8:6
	total_len	int16be
	id		icmp_id
	frag_off	int16be
	ttl		int8
	protocol	flags[ipv4_types, int8]
	csum		int16be
	src_ip		ipv4_addr
	dst_ip		ipv4_addr
	options		ipv4_options
} [packed]

icmp_echo_reply_packet {
	type	const[ICMP_ECHOREPLY, int8]
	code	const[0, int8]
	csum	csum[parent, inet, int16be]
	id	icmp_id
	seq_num	int16be
	data	array[int8]
} [packed]

type icmp_id int16be[100:104]

icmp_dest_unreach_codes = ICMP_NET_UNREACH, ICMP_HOST_UNREACH, ICMP_PROT_UNREACH, ICMP_PORT_UNREACH, ICMP_FRAG_NEEDED, ICMP_SR_FAILED, ICMP_NET_UNKNOWN, ICMP_HOST_UNKNOWN, ICMP_HOST_ISOLATED, ICMP_NET_ANO, ICMP_HOST_ANO, ICMP_NET_UNR_TOS, ICMP_HOST_UNR_TOS, ICMP_PKT_FILTERED, ICMP_PREC_VIOLATION, ICMP_PREC_CUTOFF

icmp_dest_unreach_packet {
	type	const[ICMP_DEST_UNREACH, int8]
	code	flags[icmp_dest_unreach_codes, int8]
	csum	csum[parent, inet, int16be]
	unused	const[0, int8]
	length	int8
	mtu	int16be
	iph	icmp_ipv4_header
	data	array[int8, 0:8]
} [packed]

icmp_source_quench_packet {
	type	const[ICMP_SOURCE_QUENCH, int8]
	code	const[0, int8]
	csum	csum[parent, inet, int16be]
	unused	const[0, int32]
	iph	icmp_ipv4_header
	data	array[int8, 0:8]
} [packed]

icmp_redirect_codes = ICMP_REDIR_NET, ICMP_REDIR_HOST, ICMP_REDIR_NETTOS, ICMP_REDIR_HOSTTOS

icmp_redirect_packet {
	type	const[ICMP_REDIRECT, int8]
	code	flags[icmp_redirect_codes, int8]
	csum	csum[parent, inet, int16be]
	ip	ipv4_addr
	iph	icmp_ipv4_header
	data	array[int8, 0:8]
} [packed]

icmp_echo_packet {
	type	const[ICMP_ECHO, int8]
	code	const[0, int8]
	csum	csum[parent, inet, int16be]
	id	int16be
	seq_num	int16be
	data	array[int8]
} [packed]

icmp_time_exceeded_codes = ICMP_EXC_TTL, ICMP_EXC_FRAGTIME

icmp_time_exceeded_packet {
	type	const[ICMP_TIME_EXCEEDED, int8]
	code	flags[icmp_time_exceeded_codes, int8]
	csum	csum[parent, inet, int16be]
	unused1	const[0, int8]
	length	int8
	unused2	const[0, int16]
	iph	icmp_ipv4_header
	data	array[int8, 0:8]
} [packed]

icmp_parameter_prob_packet {
	type	const[ICMP_PARAMETERPROB, int8]
	code	const[0, int8]
	csum	csum[parent, inet, int16be]
	pointer	int8
	length	int8
	unused	const[0, int16]
	iph	icmp_ipv4_header
	data	array[int8, 0:8]
} [packed]

icmp_timestamp_packet {
	type		const[ICMP_TIMESTAMP, int8]
	code		const[0, int8]
	csum		csum[parent, inet, int16be]
	id		int16be
	seq_num		int16be
	orig_ts		int32be
	recv_ts		int32be
	trans_ts	int32be
} [packed]

icmp_timestamp_reply_packet {
	type		const[ICMP_TIMESTAMPREPLY, int8]
	code		const[0, int8]
	csum		csum[parent, inet, int16be]
	id		int16be
	seq_num		int16be
	orig_ts		int32be
	recv_ts		int32be
	trans_ts	int32be
} [packed]

icmp_info_request_packet {
	type	const[ICMP_INFO_REQUEST, int8]
	code	const[0, int8]
	csum	csum[parent, inet, int16be]
	id	int16be
	seq_num	int16be
} [packed]

icmp_info_reply_packet {
	type	const[ICMP_INFO_REPLY, int8]
	code	const[0, int8]
	csum	csum[parent, inet, int16be]
	id	int16be
	seq_num	int16be
} [packed]

icmp_address_request_packet {
	type	const[ICMP_ADDRESS, int8]
	code	const[0, int8]
	csum	csum[parent, inet, int16be]
	mask	int32be
} [packed]

icmp_address_reply_packet {
	type	const[ICMP_ADDRESSREPLY, int8]
	code	const[0, int8]
	csum	csum[parent, inet, int16be]
	mask	int32be
} [packed]

icmp_types = ICMP_ECHOREPLY, ICMP_DEST_UNREACH, ICMP_SOURCE_QUENCH, ICMP_REDIRECT, ICMP_ECHO, ICMP_TIME_EXCEEDED, ICMP_PARAMETERPROB, ICMP_TIMESTAMP, ICMP_TIMESTAMPREPLY, ICMP_INFO_REQUEST, ICMP_INFO_REPLY, ICMP_ADDRESS, ICMP_ADDRESSREPLY

icmp_packet [
	echo_reply	icmp_echo_reply_packet
	dest_unreach	icmp_dest_unreach_packet
	source_quench	icmp_source_quench_packet
	redirect	icmp_redirect_packet
	echo		icmp_echo_packet
	time_exceeded	icmp_time_exceeded_packet
	parameter_prob	icmp_parameter_prob_packet
	timestamp	icmp_timestamp_packet
	timestamp_reply	icmp_timestamp_reply_packet
	info_request	icmp_info_request_packet
	info_reply	icmp_info_reply_packet
	address_request	icmp_address_request_packet
	address_reply	icmp_address_reply_packet
] [varlen]

################################################################################
##################################### ICMPv6 ###################################
################################################################################

# https://tools.ietf.org/html/rfc4443
# http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml

include <uapi/linux/icmpv6.h>

icmpv6_ipv6_packet {
	priority	int8:4
	version		const[6, int8:4]
	flow_label	array[int8, 3]
	length		int16be
	next_header	flags[ipv6_types, int8]
	hop_limit	int8
	src_ip		ipv6_addr
	dst_ip		ipv6_addr
	ext_headers	array[ipv6_ext_header]
	data		array[int8]
} [packed]

icmpv6_dest_unreach_codes = ICMPV6_NOROUTE, ICMPV6_ADM_PROHIBITED, ICMPV6_NOT_NEIGHBOUR, ICMPV6_ADDR_UNREACH, ICMPV6_PORT_UNREACH, ICMPV6_POLICY_FAIL, ICMPV6_REJECT_ROUTE

icmpv6_dest_unreach_packet {
	type	const[ICMPV6_DEST_UNREACH, int8]
	code	flags[icmpv6_dest_unreach_codes, int8]
	csum	csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	length	int8
	unused	array[const[0, int8], 3]
	packet	icmpv6_ipv6_packet
} [packed]

icmpv6_pkt_toobig_packet {
	type	const[ICMPV6_PKT_TOOBIG, int8]
	code	const[0, int8]
	csum	csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	mtu	int32be
	packet	icmpv6_ipv6_packet
} [packed]

icmpv6_time_exceed_codes = ICMPV6_EXC_HOPLIMIT, ICMPV6_EXC_FRAGTIME

icmpv6_time_exceed_packet {
	type	const[ICMPV6_TIME_EXCEED, int8]
	code	flags[icmpv6_time_exceed_codes, int8]
	csum	csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	length	int8
	unused	array[const[0, int8], 3]
	packet	icmpv6_ipv6_packet
} [packed]

icmpv6_param_prob_codes = ICMPV6_HDR_FIELD, ICMPV6_UNK_NEXTHDR, ICMPV6_UNK_OPTION

icmpv6_param_prob_packet {
	type	const[ICMPV6_PARAMPROB, int8]
	code	flags[icmpv6_param_prob_codes, int8]
	csum	csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	pointer	int32be
	packet	icmpv6_ipv6_packet
} [packed]

icmpv6_echo_request_packet {
	type	const[ICMPV6_ECHO_REQUEST, int8]
	code	const[0, int8]
	csum	csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	id	int16be
	seq_num	int16be
	data	array[int8]
} [packed]

icmpv6_echo_reply_packet {
	type	const[ICMPV6_ECHO_REPLY, int8]
	code	const[0, int8]
	csum	csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	id	int16be
	seq_num	int16be
	data	array[int8]
} [packed]

icmpv6_mld_types = ICMPV6_MGM_QUERY, ICMPV6_MGM_REPORT, ICMPV6_MGM_REDUCTION

# https://tools.ietf.org/html/rfc2710#section-3
icmpv6_mld_packet {
	type	flags[icmpv6_mld_types, int8]
	code	const[0, int8]
	csum	csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	mrd	int16be
	unused	int16
	addr	ipv6_addr
} [packed]

icmpv6_ni_types = ICMPV6_NI_QUERY, ICMPV6_NI_REPLY

# https://tools.ietf.org/html/rfc4620#section-4
icmpv6_ni_packet {
	type	flags[icmpv6_ni_types, int8]
	code	const[0, int8]
	csum	csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	qtype	int16be
	flags	int16be
	nonce	int64be
	data	array[int8]
} [packed]

icmpv6_ndisc_option_types = ND_OPT_SOURCE_LL_ADDR, ND_OPT_TARGET_LL_ADDR, ND_OPT_PREFIX_INFO, ND_OPT_REDIRECT_HDR, ND_OPT_MTU, ND_OPT_NONCE, ND_OPT_ROUTE_INFO, ND_OPT_RDNSS, ND_OPT_DNSSL, ND_OPT_6CO

# https://tools.ietf.org/html/rfc4861#section-4.6
icmpv6_ndisc_option {
	option_type	flags[icmpv6_ndisc_option_types, int8]
	length		bytesize8[parent, int8]
# TODO: define the option formats
	data		array[int8]
} [packed]

# https://tools.ietf.org/html/rfc4861#section-4.1
icmpv6_ndisc_router_solicit_packet {
	type	const[NDISC_ROUTER_SOLICITATION, int8]
	code	const[0, int8]
	csum	csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	unused	array[const[0, int8], 4]
	options	array[icmpv6_ndisc_option]
} [packed]

# https://tools.ietf.org/html/rfc4861#section-4.2
icmpv6_ndisc_router_advert_packet {
	type		const[NDISC_ROUTER_ADVERTISEMENT, int8]
	code		const[0, int8]
	csum		csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	cur_hop_limit	int8
# TODO: Implement bitflags for the router advert flags
	router_flags	int8
	router_lifetime	int16
	reachable_time	int32
	retrans_time	int32
	options		array[icmpv6_ndisc_option]
} [packed]

# https://tools.ietf.org/html/rfc4861#section-4.3
icmpv6_ndisc_neigh_solicit_packet {
	type		const[NDISC_NEIGHBOUR_SOLICITATION, int8]
	code		const[0, int8]
	csum		csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	target_addr	ipv6_addr
	options		array[icmpv6_ndisc_option]
} [packed]

# https://tools.ietf.org/html/rfc4861#section-4.4
icmpv6_ndisc_neigh_advert_packet {
	type		const[NDISC_NEIGHBOUR_ADVERTISEMENT, int8]
	code		const[0, int8]
	csum		csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
# TODO: Implement bitflags for the neighbor advert flags
	neighbor_flags	int8
	unused		array[const[0, int8], 3]
	target_addr	ipv6_addr
	options		array[icmpv6_ndisc_option]
} [packed]

# https://tools.ietf.org/html/rfc4861#section-4.5
icmpv6_ndisc_redir_packet {
	type		const[NDISC_REDIRECT, int8]
	code		const[0, int8]
	csum		csum[parent, pseudo, IPPROTO_ICMPV6, int16be]
	unused		array[const[0, int8], 4]
	target_addr	ipv6_addr
	dst_addr	ipv6_addr
	options		array[icmpv6_ndisc_option]
} [packed]

icmpv6_packet [
	dest_unreach	icmpv6_dest_unreach_packet
	pkt_toobig	icmpv6_pkt_toobig_packet
	time_exceed	icmpv6_time_exceed_packet
	param_prob	icmpv6_param_prob_packet
	echo_request	icmpv6_echo_request_packet
	echo_reply	icmpv6_echo_reply_packet
	mld		icmpv6_mld_packet
	ni		icmpv6_ni_packet
	ndisc_rs	icmpv6_ndisc_router_solicit_packet
	ndisc_ra	icmpv6_ndisc_router_advert_packet
	ndisc_na	icmpv6_ndisc_neigh_advert_packet
	ndisc_ns	icmpv6_ndisc_neigh_solicit_packet
	ndisc_redir	icmpv6_ndisc_redir_packet
# TODO: ICMPV6_MLD2_REPORT
# TODO: ICMPV6_DHAAD_REQUEST, ICMPV6_DHAAD_REPLY, ICMPV6_MOBILE_PREFIX_SOL, ICMPV6_MOBILE_PREFIX_ADV (with ipv6 ext headers)
] [varlen]

################################################################################
###################################### DCCP ####################################
################################################################################

# https://tools.ietf.org/html/rfc4340#section-5

include <uapi/linux/dccp.h>

# TODO: describe each type
dccp_types = DCCP_PKT_REQUEST, DCCP_PKT_RESPONSE, DCCP_PKT_DATA, DCCP_PKT_ACK, DCCP_PKT_DATAACK, DCCP_PKT_CLOSEREQ, DCCP_PKT_CLOSE, DCCP_PKT_RESET, DCCP_PKT_SYNC, DCCP_PKT_SYNCACK, DCCP_PKT_INVALID

dccp_header {
	src_port	sock_port
	dst_port	sock_port
	offset		bytesize4[parent, int8]
	cscov		const[1, int8:4]
# TODO: cscov might have other values, affects checksummed data
	ccval		int8:4
	csum		csum[parent, pseudo, IPPROTO_DCCP, int16be]
	x		const[0, int8:1]
	type		flags[dccp_types, int8:4]
	reserved1	int8:3
	seq_num		array[int8, 3]
	reserved2	int8
	ack_num		array[int8, 3]
# TODO: seq_num and ack_num might have different size depending on x
# TODO: options
} [packed]

dccp_packet {
	header	dccp_header
	payload	array[int8]
} [packed]

################################################################################
###################################### IGMP ####################################
################################################################################

# https://tools.ietf.org/html/rfc2236
# https://tools.ietf.org/html/rfc3376#section-4

include <uapi/linux/igmp.h>

igmp_types = IGMP_HOST_MEMBERSHIP_QUERY, IGMP_HOST_MEMBERSHIP_REPORT, IGMP_DVMRP, IGMP_PIM, IGMP_TRACE, IGMPV2_HOST_MEMBERSHIP_REPORT, IGMP_HOST_LEAVE_MESSAGE, IGMPV3_HOST_MEMBERSHIP_REPORT, IGMP_MTRACE_RESP, IGMP_MTRACE

igmp_packet {
	type	flags[igmp_types, int8]
	mrtime	int8
	csum	csum[parent, inet, int16be]
	addr	ipv4_addr
	data	array[int8]
} [packed]

# TODO: describe particular IGMP packets
# TODO: open IGMP sockets from userspace

################################################################################
###################################### MPLS ####################################
################################################################################

# https://en.wikipedia.org/wiki/Multiprotocol_Label_Switching

mpls_packet {
	labels	array[mpls_label]
	payload	mpls_payload
} [packed]

mpls_label {
	label	int32be:20
	tc	const[0, int32be:3]
	s	int32be:1
	ttl	const[0, int32be:8]
}

mpls_payload [
	generic	array[int8]
	ipv4	ipv4_packet
	ipv6	ipv6_packet
	llc	llc_packet
] [varlen]

################################################################################
###################################### TIPC ####################################
################################################################################

# http://tipc.sourceforge.net/protocol.html
# http://tipc.sourceforge.net/protocol.html#anchor50

# TODO: describe more TIPC packets, the current description is far from being complete.
# But first we need to ensure that syzkaller manages to enable TIPC receiving,
# because currently it always crashes kernel earlier.
# Also, do we need to nest TIPC packets in UDP for UDP media?

include <uapi/linux/tipc.h>
include <net/tipc/msg.h>

tipc_packet [
	payload_conn		tipc_payload_msg[tipc_payload_hdr6[TIPC_CONN_MSG]]
	payload_mcast		tipc_payload_msg[tipc_payload_hdr11[TIPC_MCAST_MSG]]
	payload_named		tipc_payload_msg[tipc_payload_hdr10[TIPC_NAMED_MSG]]
	payload_direct		tipc_payload_msg[tipc_payload_hdr8[TIPC_DIRECT_MSG]]
	name_distributor	tipc_name_distributor_msg
] [varlen]

type tipc_payload_msg[HDR] {
	hdr	tipc_payload_hdr[HDR]
	data	array[const[0, int8]]
}

type tipc_payload_hdr[HDR] {
	hdr	HDR
}

type tipc_payload_hdr6[TYP] {
# w0
	message_size		bytesize[tipc_payload_msg, int32be:17]
	y			const[0, int32be:1]
	s			int32be:1
	d			int32be:1
	n			int32be:1
	hsize			bytesize4[tipc_payload_hdr, int32be:4]
	user			flags[tipc_importance, int32be:4]
	ver			const[TIPC_VERSION, int32be:3]
# w1
	broadcast_acknowledge	int32be:16
	res			const[0, int32be:3]
	lcs			flags[tipc_scope, int32be:2]
	reroute			int32be:4
	error			flags[tipc_error, int32be:4]
	mtype			const[TYP, int32be:3]
# w2
	link_sequence		int32be:16
	link_acknowledge	int32be:16
# w3
	previous_node		int32be[0:4]
# w4
	originating_port	int32be[20000:20004]
# w5
	destination_port	int32be[20000:20004]
} [size[24]]

type tipc_payload_hdr8[TYP] {
	hdr6			tipc_payload_hdr6[TYP]
# w6
	originating_node	int32be[0:4]
# w7
	destination_node	int32be[0:4]
} [size[32]]

type tipc_payload_hdr10[TYP] {
	hdr8		tipc_payload_hdr8[TYP]
# w8
	name_type	int32be[0:4]
# w9
	name_instance	int32be[0:4]
} [size[40]]

type tipc_payload_hdr11[TYP] {
	hdr10			tipc_payload_hdr10[TYP]
# w10
	name_sequence_upper	int32be[0:4]
} [size[44]]

tipc_name_distributor_msg {
	hdr	tipc_name_distributor_hdr
	data	array[tipc_name_publication]
}

tipc_name_distributor_hdr {
# w0
	message_size		bytesize[tipc_name_distributor_msg, int32be:17]
	y			const[0, int32be:1]
	s			const[0, int32be:1]
	d			const[0, int32be:1]
	n			int32be:1
	hsize			bytesize4[parent, int32be:4]
	user			const[NAME_DISTRIBUTOR, int32be:4]
	ver			const[TIPC_VERSION, int32be:3]
# w1
	broadcast_acknowledge	int32be:16
	res			const[0, int32be:13]
	mtype			int32be:3[0:1]
# w2
	link_sequence		int32be:16
	link_acknowledge	int32be:16
# w3
	previous_node		int32be[0:4]
# w4
	originating_port	int32be[20000:20004]
# w5
	destination_port	int32be[20000:20004]
# w6
	originating_node	int32be[0:4]
# w7
	destination_node	int32be[0:4]
# w8
	res1			const[0, int32be]
# w9
	res2			const[0, int32be:23]
	m			int32be:1
	item_size		const[7, int32be:8]
}

tipc_name_publication {
	type		int32be
	lower_bound	int32be
	upper_bound	int32be
	reference	int32be
	key		int32be
	node		int32be
	scope		int32be:4
	res		int32be:28
} [size[28]]

tipc_importance = TIPC_LOW_IMPORTANCE, TIPC_MEDIUM_IMPORTANCE, TIPC_HIGH_IMPORTANCE, TIPC_CRITICAL_IMPORTANCE
tipc_error = TIPC_OK, TIPC_ERR_NO_NAME, TIPC_ERR_NO_PORT, TIPC_ERR_NO_NODE, TIPC_ERR_OVERLOAD, TIPC_CONN_SHUTDOWN
tipc_scope = TIPC_CFG_SRV, TIPC_ZONE_SCOPE, TIPC_CLUSTER_SCOPE, TIPC_NODE_SCOPE