pypcapkit 1.3.3.post1__cp313-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (466) hide show
  1. pcapkit/__init__.py +126 -0
  2. pcapkit/__main__.py +138 -0
  3. pcapkit/all.py +136 -0
  4. pcapkit/const/__init__.py +81 -0
  5. pcapkit/const/arp/__init__.py +25 -0
  6. pcapkit/const/arp/hardware.py +181 -0
  7. pcapkit/const/arp/operation.py +131 -0
  8. pcapkit/const/ftp/__init__.py +25 -0
  9. pcapkit/const/ftp/command.py +309 -0
  10. pcapkit/const/ftp/return_code.py +304 -0
  11. pcapkit/const/hip/__init__.py +94 -0
  12. pcapkit/const/hip/certificate.py +77 -0
  13. pcapkit/const/hip/cipher.py +65 -0
  14. pcapkit/const/hip/di.py +59 -0
  15. pcapkit/const/hip/ecdsa_curve.py +59 -0
  16. pcapkit/const/hip/ecdsa_low_curve.py +56 -0
  17. pcapkit/const/hip/eddsa_curve.py +65 -0
  18. pcapkit/const/hip/esp_transform_suite.py +98 -0
  19. pcapkit/const/hip/group.py +86 -0
  20. pcapkit/const/hip/hi_algorithm.py +86 -0
  21. pcapkit/const/hip/hit_suite.py +68 -0
  22. pcapkit/const/hip/nat_traversal.py +62 -0
  23. pcapkit/const/hip/notify_message.py +200 -0
  24. pcapkit/const/hip/packet.py +89 -0
  25. pcapkit/const/hip/parameter.py +377 -0
  26. pcapkit/const/hip/registration.py +68 -0
  27. pcapkit/const/hip/registration_failure.py +84 -0
  28. pcapkit/const/hip/suite.py +71 -0
  29. pcapkit/const/hip/transport.py +59 -0
  30. pcapkit/const/http/__init__.py +39 -0
  31. pcapkit/const/http/error_code.py +95 -0
  32. pcapkit/const/http/frame.py +95 -0
  33. pcapkit/const/http/method.py +184 -0
  34. pcapkit/const/http/setting.py +96 -0
  35. pcapkit/const/http/status_code.py +294 -0
  36. pcapkit/const/ipv4/__init__.py +57 -0
  37. pcapkit/const/ipv4/classification_level.py +64 -0
  38. pcapkit/const/ipv4/option_class.py +55 -0
  39. pcapkit/const/ipv4/option_number.py +137 -0
  40. pcapkit/const/ipv4/protection_authority.py +63 -0
  41. pcapkit/const/ipv4/qs_function.py +51 -0
  42. pcapkit/const/ipv4/router_alert.py +251 -0
  43. pcapkit/const/ipv4/tos_del.py +51 -0
  44. pcapkit/const/ipv4/tos_ecn.py +55 -0
  45. pcapkit/const/ipv4/tos_pre.py +63 -0
  46. pcapkit/const/ipv4/tos_rel.py +51 -0
  47. pcapkit/const/ipv4/tos_thr.py +51 -0
  48. pcapkit/const/ipv4/ts_flag.py +53 -0
  49. pcapkit/const/ipv6/__init__.py +53 -0
  50. pcapkit/const/ipv6/extension_header.py +66 -0
  51. pcapkit/const/ipv6/option.py +137 -0
  52. pcapkit/const/ipv6/option_action.py +55 -0
  53. pcapkit/const/ipv6/qs_function.py +51 -0
  54. pcapkit/const/ipv6/router_alert.py +266 -0
  55. pcapkit/const/ipv6/routing.py +80 -0
  56. pcapkit/const/ipv6/seed_id.py +55 -0
  57. pcapkit/const/ipv6/smf_dpd_mode.py +51 -0
  58. pcapkit/const/ipv6/tagger_id.py +62 -0
  59. pcapkit/const/ipx/__init__.py +27 -0
  60. pcapkit/const/ipx/packet.py +72 -0
  61. pcapkit/const/ipx/socket.py +104 -0
  62. pcapkit/const/l2tp/__init__.py +21 -0
  63. pcapkit/const/l2tp/type.py +51 -0
  64. pcapkit/const/mh/__init__.py +204 -0
  65. pcapkit/const/mh/access_type.py +92 -0
  66. pcapkit/const/mh/ack_status_code.py +71 -0
  67. pcapkit/const/mh/ani_suboption.py +74 -0
  68. pcapkit/const/mh/auth_subtype.py +53 -0
  69. pcapkit/const/mh/binding_ack_flag.py +66 -0
  70. pcapkit/const/mh/binding_error.py +51 -0
  71. pcapkit/const/mh/binding_revocation.py +59 -0
  72. pcapkit/const/mh/binding_update_flag.py +81 -0
  73. pcapkit/const/mh/cga_extension.py +66 -0
  74. pcapkit/const/mh/cga_sec.py +57 -0
  75. pcapkit/const/mh/cga_type.py +68 -0
  76. pcapkit/const/mh/dhcp_support_mode.py +53 -0
  77. pcapkit/const/mh/dns_status_code.py +65 -0
  78. pcapkit/const/mh/dsmip6_tls_packet.py +62 -0
  79. pcapkit/const/mh/dsmipv6_home_address.py +74 -0
  80. pcapkit/const/mh/enumerating_algorithm.py +56 -0
  81. pcapkit/const/mh/fb_ack_status.py +62 -0
  82. pcapkit/const/mh/fb_action.py +71 -0
  83. pcapkit/const/mh/fb_indication_trigger.py +65 -0
  84. pcapkit/const/mh/fb_type.py +59 -0
  85. pcapkit/const/mh/flow_id_status.py +77 -0
  86. pcapkit/const/mh/flow_id_suboption.py +71 -0
  87. pcapkit/const/mh/handoff_type.py +71 -0
  88. pcapkit/const/mh/handover_ack_flag.py +54 -0
  89. pcapkit/const/mh/handover_ack_status.py +92 -0
  90. pcapkit/const/mh/handover_initiate_flag.py +57 -0
  91. pcapkit/const/mh/handover_initiate_status.py +62 -0
  92. pcapkit/const/mh/home_address_reply.py +71 -0
  93. pcapkit/const/mh/lla_code.py +63 -0
  94. pcapkit/const/mh/lma_mag_suboption.py +59 -0
  95. pcapkit/const/mh/mn_group_id.py +59 -0
  96. pcapkit/const/mh/mn_id_subtype.py +77 -0
  97. pcapkit/const/mh/operator_id.py +63 -0
  98. pcapkit/const/mh/option.py +260 -0
  99. pcapkit/const/mh/packet.py +119 -0
  100. pcapkit/const/mh/qos_attribute.py +89 -0
  101. pcapkit/const/mh/revocation_status_code.py +83 -0
  102. pcapkit/const/mh/revocation_trigger.py +86 -0
  103. pcapkit/const/mh/status_code.py +232 -0
  104. pcapkit/const/mh/traffic_selector.py +62 -0
  105. pcapkit/const/mh/upa_status.py +71 -0
  106. pcapkit/const/mh/upn_reason.py +80 -0
  107. pcapkit/const/ospf/__init__.py +27 -0
  108. pcapkit/const/ospf/authentication.py +65 -0
  109. pcapkit/const/ospf/packet.py +71 -0
  110. pcapkit/const/pcapng/__init__.py +51 -0
  111. pcapkit/const/pcapng/block_type.py +152 -0
  112. pcapkit/const/pcapng/filter_type.py +48 -0
  113. pcapkit/const/pcapng/hash_algorithm.py +59 -0
  114. pcapkit/const/pcapng/option_type.py +233 -0
  115. pcapkit/const/pcapng/record_type.py +57 -0
  116. pcapkit/const/pcapng/secrets_type.py +56 -0
  117. pcapkit/const/pcapng/verdict_type.py +53 -0
  118. pcapkit/const/reg/__init__.py +34 -0
  119. pcapkit/const/reg/apptype.py +32702 -0
  120. pcapkit/const/reg/ethertype.py +714 -0
  121. pcapkit/const/reg/linktype.py +902 -0
  122. pcapkit/const/reg/transtype.py +523 -0
  123. pcapkit/const/tcp/__init__.py +35 -0
  124. pcapkit/const/tcp/checksum.py +55 -0
  125. pcapkit/const/tcp/flags.py +73 -0
  126. pcapkit/const/tcp/mp_tcp_option.py +80 -0
  127. pcapkit/const/tcp/option.py +198 -0
  128. pcapkit/const/vlan/__init__.py +23 -0
  129. pcapkit/const/vlan/priority_level.py +71 -0
  130. pcapkit/corekit/__init__.py +59 -0
  131. pcapkit/corekit/fields/__init__.py +45 -0
  132. pcapkit/corekit/fields/collections.py +282 -0
  133. pcapkit/corekit/fields/field.py +269 -0
  134. pcapkit/corekit/fields/ipaddress.py +274 -0
  135. pcapkit/corekit/fields/misc.py +722 -0
  136. pcapkit/corekit/fields/numbers.py +375 -0
  137. pcapkit/corekit/fields/strings.py +245 -0
  138. pcapkit/corekit/infoclass.py +394 -0
  139. pcapkit/corekit/io.py +506 -0
  140. pcapkit/corekit/module.py +39 -0
  141. pcapkit/corekit/multidict.py +626 -0
  142. pcapkit/corekit/protochain.py +263 -0
  143. pcapkit/corekit/version.py +33 -0
  144. pcapkit/dumpkit/__init__.py +15 -0
  145. pcapkit/dumpkit/common.py +199 -0
  146. pcapkit/dumpkit/null.py +77 -0
  147. pcapkit/dumpkit/pcap.py +144 -0
  148. pcapkit/foundation/__init__.py +45 -0
  149. pcapkit/foundation/engines/__init__.py +36 -0
  150. pcapkit/foundation/engines/dpkt.py +230 -0
  151. pcapkit/foundation/engines/engine.py +194 -0
  152. pcapkit/foundation/engines/pcap.py +188 -0
  153. pcapkit/foundation/engines/pcapng.py +310 -0
  154. pcapkit/foundation/engines/pyshark.py +166 -0
  155. pcapkit/foundation/engines/scapy.py +161 -0
  156. pcapkit/foundation/extraction.py +915 -0
  157. pcapkit/foundation/reassembly/__init__.py +49 -0
  158. pcapkit/foundation/reassembly/data/__init__.py +48 -0
  159. pcapkit/foundation/reassembly/data/ip.py +117 -0
  160. pcapkit/foundation/reassembly/data/tcp.py +145 -0
  161. pcapkit/foundation/reassembly/ip.py +192 -0
  162. pcapkit/foundation/reassembly/ipv4.py +50 -0
  163. pcapkit/foundation/reassembly/ipv6.py +50 -0
  164. pcapkit/foundation/reassembly/reassembly.py +389 -0
  165. pcapkit/foundation/reassembly/tcp.py +249 -0
  166. pcapkit/foundation/registry/__init__.py +41 -0
  167. pcapkit/foundation/registry/foundation.py +327 -0
  168. pcapkit/foundation/registry/protocols.py +885 -0
  169. pcapkit/foundation/traceflow/__init__.py +44 -0
  170. pcapkit/foundation/traceflow/data/__init__.py +30 -0
  171. pcapkit/foundation/traceflow/data/tcp.py +105 -0
  172. pcapkit/foundation/traceflow/tcp.py +159 -0
  173. pcapkit/foundation/traceflow/traceflow.py +390 -0
  174. pcapkit/interface/__init__.py +22 -0
  175. pcapkit/interface/core.py +185 -0
  176. pcapkit/interface/misc.py +120 -0
  177. pcapkit/protocols/__init__.py +85 -0
  178. pcapkit/protocols/application/NotImplemented/bgp.py +0 -0
  179. pcapkit/protocols/application/NotImplemented/dhcp.py +0 -0
  180. pcapkit/protocols/application/NotImplemented/dhcpv6.py +0 -0
  181. pcapkit/protocols/application/NotImplemented/dns.py +0 -0
  182. pcapkit/protocols/application/NotImplemented/imap.py +0 -0
  183. pcapkit/protocols/application/NotImplemented/ldap.py +0 -0
  184. pcapkit/protocols/application/NotImplemented/mqtt.py +0 -0
  185. pcapkit/protocols/application/NotImplemented/nntp.py +0 -0
  186. pcapkit/protocols/application/NotImplemented/ntp.py +0 -0
  187. pcapkit/protocols/application/NotImplemented/onc_rpc.py +0 -0
  188. pcapkit/protocols/application/NotImplemented/pop.py +0 -0
  189. pcapkit/protocols/application/NotImplemented/rip.py +0 -0
  190. pcapkit/protocols/application/NotImplemented/rtp.py +0 -0
  191. pcapkit/protocols/application/NotImplemented/sip.py +0 -0
  192. pcapkit/protocols/application/NotImplemented/smtp.py +0 -0
  193. pcapkit/protocols/application/NotImplemented/snmp.py +0 -0
  194. pcapkit/protocols/application/NotImplemented/ssh.py +0 -0
  195. pcapkit/protocols/application/NotImplemented/telnet.py +0 -0
  196. pcapkit/protocols/application/NotImplemented/tls.py +0 -0
  197. pcapkit/protocols/application/NotImplemented/xmpp.py +0 -0
  198. pcapkit/protocols/application/__init__.py +34 -0
  199. pcapkit/protocols/application/application.py +114 -0
  200. pcapkit/protocols/application/ftp.py +206 -0
  201. pcapkit/protocols/application/http.py +176 -0
  202. pcapkit/protocols/application/httpv1.py +320 -0
  203. pcapkit/protocols/application/httpv2.py +1255 -0
  204. pcapkit/protocols/data/__init__.py +192 -0
  205. pcapkit/protocols/data/application/__init__.py +57 -0
  206. pcapkit/protocols/data/application/ftp.py +59 -0
  207. pcapkit/protocols/data/application/httpv1.py +79 -0
  208. pcapkit/protocols/data/application/httpv2.py +293 -0
  209. pcapkit/protocols/data/data.py +25 -0
  210. pcapkit/protocols/data/internet/__init__.py +298 -0
  211. pcapkit/protocols/data/internet/ah.py +31 -0
  212. pcapkit/protocols/data/internet/hip.py +804 -0
  213. pcapkit/protocols/data/internet/hopopt.py +351 -0
  214. pcapkit/protocols/data/internet/ipv4.py +369 -0
  215. pcapkit/protocols/data/internet/ipv6.py +67 -0
  216. pcapkit/protocols/data/internet/ipv6_frag.py +29 -0
  217. pcapkit/protocols/data/internet/ipv6_opts.py +368 -0
  218. pcapkit/protocols/data/internet/ipv6_route.py +86 -0
  219. pcapkit/protocols/data/internet/ipx.py +56 -0
  220. pcapkit/protocols/data/internet/mh.py +509 -0
  221. pcapkit/protocols/data/link/__init__.py +33 -0
  222. pcapkit/protocols/data/link/arp.py +74 -0
  223. pcapkit/protocols/data/link/ethernet.py +28 -0
  224. pcapkit/protocols/data/link/l2tp.py +63 -0
  225. pcapkit/protocols/data/link/ospf.py +58 -0
  226. pcapkit/protocols/data/link/vlan.py +42 -0
  227. pcapkit/protocols/data/misc/__init__.py +109 -0
  228. pcapkit/protocols/data/misc/null.py +18 -0
  229. pcapkit/protocols/data/misc/pcap/__init__.py +18 -0
  230. pcapkit/protocols/data/misc/pcap/frame.py +56 -0
  231. pcapkit/protocols/data/misc/pcap/header.py +53 -0
  232. pcapkit/protocols/data/misc/pcapng.py +925 -0
  233. pcapkit/protocols/data/misc/raw.py +25 -0
  234. pcapkit/protocols/data/protocol.py +32 -0
  235. pcapkit/protocols/data/transport/__init__.py +71 -0
  236. pcapkit/protocols/data/transport/tcp.py +555 -0
  237. pcapkit/protocols/data/transport/udp.py +29 -0
  238. pcapkit/protocols/internet/NotImplemented/ecn.py +0 -0
  239. pcapkit/protocols/internet/NotImplemented/esp.py +97 -0
  240. pcapkit/protocols/internet/NotImplemented/icmp.py +0 -0
  241. pcapkit/protocols/internet/NotImplemented/icmpv6.py +0 -0
  242. pcapkit/protocols/internet/NotImplemented/igmp.py +0 -0
  243. pcapkit/protocols/internet/NotImplemented/shim6.py +0 -0
  244. pcapkit/protocols/internet/__init__.py +43 -0
  245. pcapkit/protocols/internet/ah.py +275 -0
  246. pcapkit/protocols/internet/hip.py +4727 -0
  247. pcapkit/protocols/internet/hopopt.py +1879 -0
  248. pcapkit/protocols/internet/internet.py +240 -0
  249. pcapkit/protocols/internet/ip.py +51 -0
  250. pcapkit/protocols/internet/ipsec.py +50 -0
  251. pcapkit/protocols/internet/ipv4.py +1782 -0
  252. pcapkit/protocols/internet/ipv6.py +361 -0
  253. pcapkit/protocols/internet/ipv6_frag.py +258 -0
  254. pcapkit/protocols/internet/ipv6_opts.py +1890 -0
  255. pcapkit/protocols/internet/ipv6_route.py +710 -0
  256. pcapkit/protocols/internet/ipx.py +230 -0
  257. pcapkit/protocols/internet/mh.py +2764 -0
  258. pcapkit/protocols/link/NotImplemented/dsl.py +0 -0
  259. pcapkit/protocols/link/NotImplemented/eapol.py +1 -0
  260. pcapkit/protocols/link/NotImplemented/fddi.py +0 -0
  261. pcapkit/protocols/link/NotImplemented/isdn.py +0 -0
  262. pcapkit/protocols/link/NotImplemented/ndp.py +0 -0
  263. pcapkit/protocols/link/NotImplemented/ppp.py +0 -0
  264. pcapkit/protocols/link/__init__.py +35 -0
  265. pcapkit/protocols/link/arp.py +421 -0
  266. pcapkit/protocols/link/ethernet.py +248 -0
  267. pcapkit/protocols/link/l2tp.py +267 -0
  268. pcapkit/protocols/link/link.py +140 -0
  269. pcapkit/protocols/link/ospf.py +342 -0
  270. pcapkit/protocols/link/rarp.py +82 -0
  271. pcapkit/protocols/link/vlan.py +225 -0
  272. pcapkit/protocols/misc/__init__.py +37 -0
  273. pcapkit/protocols/misc/null.py +129 -0
  274. pcapkit/protocols/misc/pcap/__init__.py +17 -0
  275. pcapkit/protocols/misc/pcap/frame.py +478 -0
  276. pcapkit/protocols/misc/pcap/header.py +358 -0
  277. pcapkit/protocols/misc/pcapng.py +5520 -0
  278. pcapkit/protocols/misc/raw.py +180 -0
  279. pcapkit/protocols/protocol.py +1216 -0
  280. pcapkit/protocols/schema/__init__.py +140 -0
  281. pcapkit/protocols/schema/application/__init__.py +40 -0
  282. pcapkit/protocols/schema/application/ftp.py +21 -0
  283. pcapkit/protocols/schema/application/httpv1.py +21 -0
  284. pcapkit/protocols/schema/application/httpv2.py +384 -0
  285. pcapkit/protocols/schema/internet/__init__.py +294 -0
  286. pcapkit/protocols/schema/internet/ah.py +40 -0
  287. pcapkit/protocols/schema/internet/hip.py +1184 -0
  288. pcapkit/protocols/schema/internet/hopopt.py +679 -0
  289. pcapkit/protocols/schema/internet/ipv4.py +576 -0
  290. pcapkit/protocols/schema/internet/ipv6.py +63 -0
  291. pcapkit/protocols/schema/internet/ipv6_frag.py +48 -0
  292. pcapkit/protocols/schema/internet/ipv6_opts.py +680 -0
  293. pcapkit/protocols/schema/internet/ipv6_route.py +198 -0
  294. pcapkit/protocols/schema/internet/ipx.py +40 -0
  295. pcapkit/protocols/schema/internet/mh.py +718 -0
  296. pcapkit/protocols/schema/link/__init__.py +19 -0
  297. pcapkit/protocols/schema/link/arp.py +39 -0
  298. pcapkit/protocols/schema/link/ethernet.py +51 -0
  299. pcapkit/protocols/schema/link/l2tp.py +88 -0
  300. pcapkit/protocols/schema/link/ospf.py +90 -0
  301. pcapkit/protocols/schema/link/vlan.py +69 -0
  302. pcapkit/protocols/schema/misc/__init__.py +108 -0
  303. pcapkit/protocols/schema/misc/null.py +18 -0
  304. pcapkit/protocols/schema/misc/pcap/__init__.py +10 -0
  305. pcapkit/protocols/schema/misc/pcap/frame.py +51 -0
  306. pcapkit/protocols/schema/misc/pcap/header.py +63 -0
  307. pcapkit/protocols/schema/misc/pcapng.py +1689 -0
  308. pcapkit/protocols/schema/misc/raw.py +24 -0
  309. pcapkit/protocols/schema/schema.py +809 -0
  310. pcapkit/protocols/schema/transport/__init__.py +69 -0
  311. pcapkit/protocols/schema/transport/tcp.py +928 -0
  312. pcapkit/protocols/schema/transport/udp.py +90 -0
  313. pcapkit/protocols/transport/NotImplemented/dccp.py +0 -0
  314. pcapkit/protocols/transport/NotImplemented/rsvp.py +0 -0
  315. pcapkit/protocols/transport/NotImplemented/sctp.py +0 -0
  316. pcapkit/protocols/transport/__init__.py +27 -0
  317. pcapkit/protocols/transport/tcp.py +3025 -0
  318. pcapkit/protocols/transport/transport.py +158 -0
  319. pcapkit/protocols/transport/udp.py +214 -0
  320. pcapkit/py.typed +0 -0
  321. pcapkit/toolkit/__init__.py +57 -0
  322. pcapkit/toolkit/dpkt.py +306 -0
  323. pcapkit/toolkit/pcap.py +212 -0
  324. pcapkit/toolkit/pcapng.py +251 -0
  325. pcapkit/toolkit/pyshark.py +99 -0
  326. pcapkit/toolkit/scapy.py +297 -0
  327. pcapkit/utilities/__init__.py +20 -0
  328. pcapkit/utilities/compat.py +196 -0
  329. pcapkit/utilities/decorators.py +192 -0
  330. pcapkit/utilities/exceptions.py +365 -0
  331. pcapkit/utilities/logging.py +55 -0
  332. pcapkit/utilities/warnings.py +185 -0
  333. pcapkit/vendor/__init__.py +105 -0
  334. pcapkit/vendor/__main__.py +92 -0
  335. pcapkit/vendor/arp/__init__.py +27 -0
  336. pcapkit/vendor/arp/hardware.py +29 -0
  337. pcapkit/vendor/arp/operation.py +29 -0
  338. pcapkit/vendor/default.py +474 -0
  339. pcapkit/vendor/ftp/__init__.py +27 -0
  340. pcapkit/vendor/ftp/command.py +244 -0
  341. pcapkit/vendor/ftp/return_code.py +256 -0
  342. pcapkit/vendor/hip/__init__.py +94 -0
  343. pcapkit/vendor/hip/certificate.py +29 -0
  344. pcapkit/vendor/hip/cipher.py +29 -0
  345. pcapkit/vendor/hip/di.py +29 -0
  346. pcapkit/vendor/hip/ecdsa_curve.py +29 -0
  347. pcapkit/vendor/hip/ecdsa_low_curve.py +29 -0
  348. pcapkit/vendor/hip/eddsa_curve.py +85 -0
  349. pcapkit/vendor/hip/esp_transform_suite.py +29 -0
  350. pcapkit/vendor/hip/group.py +87 -0
  351. pcapkit/vendor/hip/hi_algorithm.py +29 -0
  352. pcapkit/vendor/hip/hit_suite.py +29 -0
  353. pcapkit/vendor/hip/nat_traversal.py +29 -0
  354. pcapkit/vendor/hip/notify_message.py +29 -0
  355. pcapkit/vendor/hip/packet.py +88 -0
  356. pcapkit/vendor/hip/parameter.py +88 -0
  357. pcapkit/vendor/hip/registration.py +29 -0
  358. pcapkit/vendor/hip/registration_failure.py +29 -0
  359. pcapkit/vendor/hip/suite.py +29 -0
  360. pcapkit/vendor/hip/transport.py +29 -0
  361. pcapkit/vendor/http/__init__.py +39 -0
  362. pcapkit/vendor/http/error_code.py +95 -0
  363. pcapkit/vendor/http/frame.py +91 -0
  364. pcapkit/vendor/http/method.py +167 -0
  365. pcapkit/vendor/http/setting.py +93 -0
  366. pcapkit/vendor/http/status_code.py +185 -0
  367. pcapkit/vendor/ipv4/__init__.py +57 -0
  368. pcapkit/vendor/ipv4/classification_level.py +91 -0
  369. pcapkit/vendor/ipv4/option_class.py +80 -0
  370. pcapkit/vendor/ipv4/option_number.py +105 -0
  371. pcapkit/vendor/ipv4/protection_authority.py +84 -0
  372. pcapkit/vendor/ipv4/qs_function.py +78 -0
  373. pcapkit/vendor/ipv4/router_alert.py +93 -0
  374. pcapkit/vendor/ipv4/tos_del.py +78 -0
  375. pcapkit/vendor/ipv4/tos_ecn.py +95 -0
  376. pcapkit/vendor/ipv4/tos_pre.py +84 -0
  377. pcapkit/vendor/ipv4/tos_rel.py +78 -0
  378. pcapkit/vendor/ipv4/tos_thr.py +77 -0
  379. pcapkit/vendor/ipv4/ts_flag.py +79 -0
  380. pcapkit/vendor/ipv6/__init__.py +53 -0
  381. pcapkit/vendor/ipv6/extension_header.py +171 -0
  382. pcapkit/vendor/ipv6/option.py +104 -0
  383. pcapkit/vendor/ipv6/option_action.py +90 -0
  384. pcapkit/vendor/ipv6/qs_function.py +78 -0
  385. pcapkit/vendor/ipv6/router_alert.py +93 -0
  386. pcapkit/vendor/ipv6/routing.py +87 -0
  387. pcapkit/vendor/ipv6/seed_id.py +81 -0
  388. pcapkit/vendor/ipv6/smf_dpd_mode.py +78 -0
  389. pcapkit/vendor/ipv6/tagger_id.py +81 -0
  390. pcapkit/vendor/ipx/__init__.py +37 -0
  391. pcapkit/vendor/ipx/packet.py +123 -0
  392. pcapkit/vendor/ipx/socket.py +125 -0
  393. pcapkit/vendor/l2tp/__init__.py +21 -0
  394. pcapkit/vendor/l2tp/type.py +78 -0
  395. pcapkit/vendor/mh/__init__.py +204 -0
  396. pcapkit/vendor/mh/access_type.py +87 -0
  397. pcapkit/vendor/mh/ack_status_code.py +88 -0
  398. pcapkit/vendor/mh/ani_suboption.py +88 -0
  399. pcapkit/vendor/mh/auth_subtype.py +83 -0
  400. pcapkit/vendor/mh/binding_ack_flag.py +148 -0
  401. pcapkit/vendor/mh/binding_error.py +78 -0
  402. pcapkit/vendor/mh/binding_revocation.py +87 -0
  403. pcapkit/vendor/mh/binding_update_flag.py +147 -0
  404. pcapkit/vendor/mh/cga_extension.py +91 -0
  405. pcapkit/vendor/mh/cga_sec.py +91 -0
  406. pcapkit/vendor/mh/cga_type.py +74 -0
  407. pcapkit/vendor/mh/dhcp_support_mode.py +77 -0
  408. pcapkit/vendor/mh/dns_status_code.py +87 -0
  409. pcapkit/vendor/mh/dsmip6_tls_packet.py +87 -0
  410. pcapkit/vendor/mh/dsmipv6_home_address.py +87 -0
  411. pcapkit/vendor/mh/enumerating_algorithm.py +82 -0
  412. pcapkit/vendor/mh/fb_ack_status.py +87 -0
  413. pcapkit/vendor/mh/fb_action.py +88 -0
  414. pcapkit/vendor/mh/fb_indication_trigger.py +87 -0
  415. pcapkit/vendor/mh/fb_type.py +88 -0
  416. pcapkit/vendor/mh/flow_id_status.py +87 -0
  417. pcapkit/vendor/mh/flow_id_suboption.py +87 -0
  418. pcapkit/vendor/mh/handoff_type.py +87 -0
  419. pcapkit/vendor/mh/handover_ack_flag.py +143 -0
  420. pcapkit/vendor/mh/handover_ack_status.py +87 -0
  421. pcapkit/vendor/mh/handover_initiate_flag.py +143 -0
  422. pcapkit/vendor/mh/handover_initiate_status.py +87 -0
  423. pcapkit/vendor/mh/home_address_reply.py +87 -0
  424. pcapkit/vendor/mh/lla_code.py +97 -0
  425. pcapkit/vendor/mh/lma_mag_suboption.py +88 -0
  426. pcapkit/vendor/mh/mn_group_id.py +87 -0
  427. pcapkit/vendor/mh/mn_id_subtype.py +87 -0
  428. pcapkit/vendor/mh/operator_id.py +87 -0
  429. pcapkit/vendor/mh/option.py +83 -0
  430. pcapkit/vendor/mh/packet.py +82 -0
  431. pcapkit/vendor/mh/qos_attribute.py +87 -0
  432. pcapkit/vendor/mh/revocation_status_code.py +87 -0
  433. pcapkit/vendor/mh/revocation_trigger.py +87 -0
  434. pcapkit/vendor/mh/status_code.py +91 -0
  435. pcapkit/vendor/mh/traffic_selector.py +87 -0
  436. pcapkit/vendor/mh/upa_status.py +87 -0
  437. pcapkit/vendor/mh/upn_reason.py +87 -0
  438. pcapkit/vendor/ospf/__init__.py +27 -0
  439. pcapkit/vendor/ospf/authentication.py +29 -0
  440. pcapkit/vendor/ospf/packet.py +29 -0
  441. pcapkit/vendor/pcapng/__init__.py +51 -0
  442. pcapkit/vendor/pcapng/block_type.py +94 -0
  443. pcapkit/vendor/pcapng/filter_type.py +77 -0
  444. pcapkit/vendor/pcapng/hash_algorithm.py +82 -0
  445. pcapkit/vendor/pcapng/option_type.py +287 -0
  446. pcapkit/vendor/pcapng/record_type.py +81 -0
  447. pcapkit/vendor/pcapng/secrets_type.py +81 -0
  448. pcapkit/vendor/pcapng/verdict_type.py +79 -0
  449. pcapkit/vendor/reg/__init__.py +34 -0
  450. pcapkit/vendor/reg/apptype.py +338 -0
  451. pcapkit/vendor/reg/ethertype.py +121 -0
  452. pcapkit/vendor/reg/linktype.py +110 -0
  453. pcapkit/vendor/reg/transtype.py +111 -0
  454. pcapkit/vendor/tcp/__init__.py +35 -0
  455. pcapkit/vendor/tcp/checksum.py +80 -0
  456. pcapkit/vendor/tcp/flags.py +149 -0
  457. pcapkit/vendor/tcp/mp_tcp_option.py +90 -0
  458. pcapkit/vendor/tcp/option.py +103 -0
  459. pcapkit/vendor/vlan/__init__.py +23 -0
  460. pcapkit/vendor/vlan/priority_level.py +97 -0
  461. pypcapkit-1.3.3.post1.dist-info/LICENSE +29 -0
  462. pypcapkit-1.3.3.post1.dist-info/METADATA +236 -0
  463. pypcapkit-1.3.3.post1.dist-info/RECORD +466 -0
  464. pypcapkit-1.3.3.post1.dist-info/WHEEL +5 -0
  465. pypcapkit-1.3.3.post1.dist-info/entry_points.txt +3 -0
  466. pypcapkit-1.3.3.post1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1890 @@
1
+ # -*- coding: utf-8 -*-
2
+ """IPv6-Opts - Destination Options for IPv6
3
+ ==============================================
4
+
5
+ .. module:: pcapkit.protocols.internet.hopopt
6
+
7
+ :mod:`pcapkit.protocols.internet.ipv6_opts` contains
8
+ :class:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts`
9
+ only, which implements extractor for Destination Options
10
+ for IPv6 (IPv6-Opts) [*]_, whose structure is described
11
+ as below:
12
+
13
+ ======= ========= =================== =================================
14
+ Octets Bits Name Description
15
+ ======= ========= =================== =================================
16
+ 0 0 ``opt.next`` Next Header
17
+ 1 8 ``opt.length`` Header Extensive Length
18
+ 2 16 ``opt.options`` Options
19
+ ======= ========= =================== =================================
20
+
21
+ .. [*] https://en.wikipedia.org/wiki/IPv6_packet#Hop-by-hop_options_and_destination_options
22
+
23
+ """
24
+ import collections
25
+ import datetime
26
+ import ipaddress
27
+ import math
28
+ from typing import TYPE_CHECKING, cast, overload
29
+
30
+ from pcapkit.const.ipv6.option import Option as Enum_Option
31
+ from pcapkit.const.ipv6.option_action import OptionAction as Enum_OptionAction
32
+ from pcapkit.const.ipv6.qs_function import QSFunction as Enum_QSFunction
33
+ from pcapkit.const.ipv6.router_alert import RouterAlert as Enum_RouterAlert
34
+ from pcapkit.const.ipv6.seed_id import SeedID as Enum_SeedID
35
+ from pcapkit.const.ipv6.smf_dpd_mode import SMFDPDMode as Enum_SMFDPDMode
36
+ from pcapkit.const.ipv6.tagger_id import TaggerID as Enum_TaggerID
37
+ from pcapkit.const.reg.transtype import TransType as Enum_TransType
38
+ from pcapkit.corekit.fields.field import NoValue
39
+ from pcapkit.corekit.multidict import OrderedMultiDict
40
+ from pcapkit.protocols.data.internet.ipv6_opts import CALIPSOOption as Data_CALIPSOOption
41
+ from pcapkit.protocols.data.internet.ipv6_opts import DFFFlags as Data_DFFFlags
42
+ from pcapkit.protocols.data.internet.ipv6_opts import HomeAddressOption as Data_HomeAddressOption
43
+ from pcapkit.protocols.data.internet.ipv6_opts import ILNPOption as Data_ILNPOption
44
+ from pcapkit.protocols.data.internet.ipv6_opts import IPDFFOption as Data_IPDFFOption
45
+ from pcapkit.protocols.data.internet.ipv6_opts import IPv6_Opts as Data_IPv6_Opts
46
+ from pcapkit.protocols.data.internet.ipv6_opts import JumboPayloadOption as Data_JumboPayloadOption
47
+ from pcapkit.protocols.data.internet.ipv6_opts import \
48
+ LineIdentificationOption as Data_LineIdentificationOption
49
+ from pcapkit.protocols.data.internet.ipv6_opts import MPLFlags as Data_MPLFlags
50
+ from pcapkit.protocols.data.internet.ipv6_opts import MPLOption as Data_MPLOption
51
+ from pcapkit.protocols.data.internet.ipv6_opts import PadOption as Data_PadOption
52
+ from pcapkit.protocols.data.internet.ipv6_opts import PDMOption as Data_PDMOption
53
+ from pcapkit.protocols.data.internet.ipv6_opts import \
54
+ QuickStartReportOption as Data_QuickStartReportOption
55
+ from pcapkit.protocols.data.internet.ipv6_opts import \
56
+ QuickStartRequestOption as Data_QuickStartRequestOption
57
+ from pcapkit.protocols.data.internet.ipv6_opts import RouterAlertOption as Data_RouterAlertOption
58
+ from pcapkit.protocols.data.internet.ipv6_opts import RPLFlags as Data_RPLFlags
59
+ from pcapkit.protocols.data.internet.ipv6_opts import RPLOption as Data_RPLOption
60
+ from pcapkit.protocols.data.internet.ipv6_opts import \
61
+ SMFHashBasedDPDOption as Data_SMFHashBasedDPDOption
62
+ from pcapkit.protocols.data.internet.ipv6_opts import \
63
+ SMFIdentificationBasedDPDOption as Data_SMFIdentificationBasedDPDOption
64
+ from pcapkit.protocols.data.internet.ipv6_opts import \
65
+ TunnelEncapsulationLimitOption as Data_TunnelEncapsulationLimitOption
66
+ from pcapkit.protocols.data.internet.ipv6_opts import UnassignedOption as Data_UnassignedOption
67
+ from pcapkit.protocols.internet.internet import Internet
68
+ from pcapkit.protocols.schema.internet.ipv6_opts import CALIPSOOption as Schema_CALIPSOOption
69
+ from pcapkit.protocols.schema.internet.ipv6_opts import \
70
+ HomeAddressOption as Schema_HomeAddressOption
71
+ from pcapkit.protocols.schema.internet.ipv6_opts import ILNPOption as Schema_ILNPOption
72
+ from pcapkit.protocols.schema.internet.ipv6_opts import IPDFFOption as Schema_IPDFFOption
73
+ from pcapkit.protocols.schema.internet.ipv6_opts import IPv6_Opts as Schema_IPv6_Opts
74
+ from pcapkit.protocols.schema.internet.ipv6_opts import \
75
+ JumboPayloadOption as Schema_JumboPayloadOption
76
+ from pcapkit.protocols.schema.internet.ipv6_opts import \
77
+ LineIdentificationOption as Schema_LineIdentificationOption
78
+ from pcapkit.protocols.schema.internet.ipv6_opts import MPLOption as Schema_MPLOption
79
+ from pcapkit.protocols.schema.internet.ipv6_opts import PadOption as Schema_PadOption
80
+ from pcapkit.protocols.schema.internet.ipv6_opts import PDMOption as Schema_PDMOption
81
+ from pcapkit.protocols.schema.internet.ipv6_opts import \
82
+ QuickStartReportOption as Schema_QuickStartReportOption
83
+ from pcapkit.protocols.schema.internet.ipv6_opts import \
84
+ QuickStartRequestOption as Schema_QuickStartRequestOption
85
+ from pcapkit.protocols.schema.internet.ipv6_opts import \
86
+ RouterAlertOption as Schema_RouterAlertOption
87
+ from pcapkit.protocols.schema.internet.ipv6_opts import RPLOption as Schema_RPLOption
88
+ from pcapkit.protocols.schema.internet.ipv6_opts import \
89
+ SMFHashBasedDPDOption as Schema_SMFHashBasedDPDOption
90
+ from pcapkit.protocols.schema.internet.ipv6_opts import \
91
+ SMFIdentificationBasedDPDOption as Schema_SMFIdentificationBasedDPDOption
92
+ from pcapkit.protocols.schema.internet.ipv6_opts import \
93
+ TunnelEncapsulationLimitOption as Schema_TunnelEncapsulationLimitOption
94
+ from pcapkit.protocols.schema.internet.ipv6_opts import UnassignedOption as Schema_UnassignedOption
95
+ from pcapkit.protocols.schema.schema import Schema
96
+ from pcapkit.utilities.exceptions import ProtocolError, UnsupportedCall
97
+ from pcapkit.utilities.warnings import ProtocolWarning, RegistryWarning, warn
98
+
99
+ if TYPE_CHECKING:
100
+ from datetime import timedelta
101
+ from enum import IntEnum as StdlibEnum
102
+ from ipaddress import IPv4Address, IPv6Address
103
+ from typing import IO, Any, Callable, DefaultDict, NoReturn, Optional, Type
104
+
105
+ from aenum import IntEnum as AenumEnum
106
+ from mypy_extensions import DefaultArg, KwArg, NamedArg
107
+ from typing_extensions import Literal
108
+
109
+ from pcapkit.corekit.protochain import ProtoChain
110
+ from pcapkit.protocols.data.internet.ipv6_opts import Option as Data_Option
111
+ from pcapkit.protocols.data.internet.ipv6_opts import QuickStartOption as Data_QuickStartOption
112
+ from pcapkit.protocols.data.internet.ipv6_opts import SMFDPDOption as Data_SMFDPDOption
113
+ from pcapkit.protocols.protocol import ProtocolBase as Protocol
114
+ from pcapkit.protocols.schema.internet.ipv6_opts import Option as Schema_Option
115
+ from pcapkit.protocols.schema.internet.ipv6_opts import \
116
+ QuickStartOption as Schema_QuickStartOption
117
+ from pcapkit.protocols.schema.internet.ipv6_opts import SMFDPDOption as Schema_SMFDPDOption
118
+
119
+ Option = OrderedMultiDict[Enum_Option, Data_Option]
120
+ OptionParser = Callable[[Schema_Option, NamedArg(Option, 'options')], Data_Option]
121
+ OptionConstructor = Callable[[Enum_Option,
122
+ DefaultArg(Optional[Data_Option]), KwArg(Any)], Schema_Option]
123
+
124
+ __all__ = ['IPv6_Opts']
125
+
126
+
127
+ class IPv6_Opts(Internet[Data_IPv6_Opts, Schema_IPv6_Opts],
128
+ schema=Schema_IPv6_Opts, data=Data_IPv6_Opts):
129
+ """This class implements Destination Options for IPv6.
130
+
131
+ This class currently supports parsing of the following IPv6 destination
132
+ options, which are registered in the
133
+ :attr:`self.__option__ <pcapkit.protocols.internet.ipv6_opts.IPv6_Opts.__option__>`
134
+ attribute:
135
+
136
+ .. list-table::
137
+ :header-rows: 1
138
+
139
+ * - Option Code
140
+ - Option Parser
141
+ - Option Constructor
142
+ * - :attr:`~pcapkit.const.ipv6.option.Option.Pad1`
143
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_pad`
144
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_pad`
145
+ * - :attr:`~pcapkit.const.ipv6.option.Option.PadN`
146
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_pad`
147
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_pad`
148
+ * - :attr:`~pcapkit.const.ipv6.option.Option.Tunnel_Encapsulation_Limit`
149
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_tun`
150
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_tun`
151
+ * - :attr:`~pcapkit.const.ipv6.option.Option.Router_Alert`
152
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_ra`
153
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_ra`
154
+ * - :attr:`~pcapkit.const.ipv6.option.Option.CALIPSO`
155
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_calipso`
156
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_calipso`
157
+ * - :attr:`~pcapkit.const.ipv6.option.Option.SMF_DPD`
158
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_smf_dpd`
159
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_smf_dpd`
160
+ * - :attr:`~pcapkit.const.ipv6.option.Option.PDM`
161
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_pdm`
162
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_pdm`
163
+ * - :attr:`~pcapkit.const.ipv6.option.Option.Quick_Start`
164
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_qs`
165
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_qs`
166
+ * - :attr:`~pcapkit.const.ipv6.option.Option.RPL_Option_0x63`
167
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_rpl`
168
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_rpl`
169
+ * - :attr:`~pcapkit.const.ipv6.option.Option.MPL_Option`
170
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_mpl`
171
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_mpl`
172
+ * - :attr:`~pcapkit.const.ipv6.option.Option.ILNP_Nonce`
173
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_ilnp`
174
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_ilnp`
175
+ * - :attr:`~pcapkit.const.ipv6.option.Option.Line_Identification_Option`
176
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_lio`
177
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_lio`
178
+ * - :attr:`~pcapkit.const.ipv6.option.Option.Jumbo_Payload`
179
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_jumbo`
180
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_jumbo`
181
+ * - :attr:`~pcapkit.const.ipv6.option.Option.Home_Address`
182
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_home`
183
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_home`
184
+ * - :attr:`~pcapkit.const.ipv6.option.Option.IP_DFF`
185
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._read_opt_ip_dff`
186
+ - :meth:`~pcapkit.protocols.internet.ipv6_opts.IPv6_Opts._make_opt_ip_dff`
187
+
188
+ """
189
+
190
+ ##########################################################################
191
+ # Defaults.
192
+ ##########################################################################
193
+
194
+ #: DefaultDict[Enum_Option, str | tuple[OptionParser, OptionConstructor]]: Option
195
+ #: code to method mapping, c.f. :meth:`_read_ipv6_opts` and/or
196
+ #: :meth:`_make_ipv6_opts`. Method names are expected to be referred to the
197
+ #: class by ``_read_opt_${name}`` and/or ``_make_opt_${name}``, and if such
198
+ #: name not found, the value should then be a method that can parse the
199
+ #: option by itself.
200
+ __option__ = collections.defaultdict(
201
+ lambda: 'none',
202
+ {
203
+ Enum_Option.Pad1: 'pad', # [RFC 8200] 0
204
+ Enum_Option.PadN: 'pad', # [RFC 8200]
205
+ Enum_Option.Tunnel_Encapsulation_Limit: 'tun', # [RFC 2473] 1
206
+ Enum_Option.Router_Alert: 'ra', # [RFC 2711] 2
207
+ Enum_Option.CALIPSO: 'calipso', # [RFC 5570]
208
+ Enum_Option.SMF_DPD: 'smf_dpd', # [RFC 6621]
209
+ Enum_Option.PDM: 'pdm', # [RFC 8250] 10
210
+ Enum_Option.Quick_Start: 'qs', # [RFC 4782][RFC Errata 2034] 6
211
+ Enum_Option.RPL_Option_0x63: 'rpl', # [RFC 6553]
212
+ Enum_Option.MPL_Option: 'mpl', # [RFC 7731]
213
+ Enum_Option.ILNP_Nonce: 'ilnp', # [RFC 6744]
214
+ Enum_Option.Line_Identification_Option: 'lio', # [RFC 6788]
215
+ Enum_Option.Jumbo_Payload: 'jumbo', # [RFC 2675]
216
+ Enum_Option.Home_Address: 'home', # [RFC 6275]
217
+ Enum_Option.IP_DFF: 'ip_dff', # [RFC 6971]
218
+ },
219
+ ) # type: DefaultDict[Enum_Option | int, str | tuple[OptionParser, OptionConstructor]]
220
+
221
+ ##########################################################################
222
+ # Properties.
223
+ ##########################################################################
224
+
225
+ @property
226
+ def name(self) -> 'Literal["Destination Options for IPv6"]':
227
+ """Name of current protocol."""
228
+ return 'Destination Options for IPv6'
229
+
230
+ @property
231
+ def alias(self) -> 'Literal["IPv6-Opts"]':
232
+ """Acronym of corresponding protocol."""
233
+ return 'IPv6-Opts'
234
+
235
+ @property
236
+ def length(self) -> 'int':
237
+ """Header length of current protocol."""
238
+ return self._info.length
239
+
240
+ @property
241
+ def payload(self) -> 'Protocol | NoReturn':
242
+ """Payload of current instance.
243
+
244
+ Raises:
245
+ UnsupportedCall: if the protocol is used as an IPv6 extension header
246
+
247
+ :rtype: pcapkit.protocols.protocol.Protocol
248
+ """
249
+ if self._extf:
250
+ raise UnsupportedCall(f"'{self.__class__.__name__}' object has no attribute 'payload'")
251
+ return self._next
252
+
253
+ @property
254
+ def protocol(self) -> 'Optional[str] | NoReturn':
255
+ """Name of next layer protocol (if any).
256
+
257
+ Raises:
258
+ UnsupportedCall: if the protocol is used as an IPv6 extension header
259
+
260
+ """
261
+ if self._extf:
262
+ raise UnsupportedCall(f"'{self.__class__.__name__}' object has no attribute 'protocol'")
263
+ return super().protocol
264
+
265
+ @property
266
+ def protochain(self) -> 'ProtoChain | NoReturn':
267
+ """Protocol chain of current instance.
268
+
269
+ Raises:
270
+ UnsupportedCall: if the protocol is used as an IPv6 extension header
271
+
272
+ """
273
+ if self._extf:
274
+ raise UnsupportedCall(f"'{self.__class__.__name__}' object has no attribute 'protochain'")
275
+ return super().protochain
276
+
277
+ ##########################################################################
278
+ # Methods.
279
+ ##########################################################################
280
+
281
+ def read(self, length: 'Optional[int]' = None, *, extension: 'bool' = False, # pylint: disable=arguments-differ
282
+ **kwargs: 'Any') -> 'Data_IPv6_Opts': # pylint: disable=unused-argument
283
+ """Read Destination Options for IPv6.
284
+
285
+ Structure of IPv6-Opts header [:rfc:`8200`]:
286
+
287
+ .. code-block:: text
288
+
289
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
290
+ | Next Header | Hdr Ext Len | |
291
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
292
+ | |
293
+ . .
294
+ . Options .
295
+ . .
296
+ | |
297
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
298
+
299
+ Args:
300
+ length: Length of packet data.
301
+ extension: If the packet is used as an IPv6 extension header.
302
+ **kwargs: Arbitrary keyword arguments.
303
+
304
+ Returns:
305
+ Parsed packet data.
306
+
307
+ """
308
+ if length is None:
309
+ length = len(self)
310
+ schema = self.__schema__
311
+
312
+ ipv6_opts = Data_IPv6_Opts(
313
+ next=schema.next,
314
+ length=(schema.len + 1) * 8,
315
+ options=self._read_ipv6_opts(schema.len * 8 + 6),
316
+ )
317
+
318
+ if extension:
319
+ return ipv6_opts
320
+ return self._decode_next_layer(ipv6_opts, schema.next, length - ipv6_opts.length)
321
+
322
+ def make(self,
323
+ next: 'Enum_TransType | StdlibEnum | AenumEnum | str | int' = Enum_TransType.UDP,
324
+ next_default: 'Optional[int]' = None,
325
+ next_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
326
+ next_reversed: 'bool' = False,
327
+ options: 'Optional[list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes] | Option]' = None, # pylint: disable=line-too-long
328
+ payload: 'bytes | Protocol | Schema' = b'',
329
+ **kwargs: 'Any') -> 'Schema_IPv6_Opts':
330
+ """Make (construct) packet data.
331
+
332
+ Args:
333
+ next: Next header type.
334
+ next_default: Default value of next header type.
335
+ next_namespace: Namespace of next header type.
336
+ next_reversed: If the namespace of next header type is reversed.
337
+ option: Hop-by-Hop Options.
338
+ payload: Payload of current protocol.
339
+ **kwargs: Arbitrary keyword arguments.
340
+
341
+ Returns:
342
+ Constructed packet data.
343
+
344
+ """
345
+ next_value = self._make_index(next, next_default, namespace=next_namespace,
346
+ reversed=next_reversed, pack=False)
347
+
348
+ if options is not None:
349
+ options_value, total_length = self._make_ipv6_opts(options)
350
+ length = math.ceil((total_length - 6) / 8)
351
+ else:
352
+ options_value, length = [], 0
353
+
354
+ return Schema_IPv6_Opts(
355
+ next=next_value, # type: ignore[arg-type]
356
+ len=length,
357
+ options=options_value,
358
+ payload=payload,
359
+ )
360
+
361
+ @classmethod
362
+ def register_option(cls, code: 'Enum_Option', meth: 'str | tuple[OptionParser, OptionConstructor]') -> 'None':
363
+ """Register an option parser.
364
+
365
+ Args:
366
+ code: IPv6-Opts option code.
367
+ meth: Method name or callable to parse and/or construct the option.
368
+
369
+ """
370
+ if code in cls.__option__:
371
+ warn(f'option {code} already registered, overwriting', RegistryWarning)
372
+ cls.__option__[code] = meth
373
+
374
+ ##########################################################################
375
+ # Data models.
376
+ ##########################################################################
377
+
378
+ @overload
379
+ def __post_init__(self, file: 'IO[bytes] | bytes', length: 'Optional[int]' = ..., *, # pylint: disable=arguments-differ
380
+ extension: 'bool' = ..., **kwargs: 'Any') -> 'None': ...
381
+
382
+ @overload
383
+ def __post_init__(self, **kwargs: 'Any') -> 'None': ... # pylint: disable=arguments-differ
384
+
385
+ def __post_init__(self, file: 'Optional[IO[bytes] | bytes]' = None, length: 'Optional[int]' = None, *, # pylint: disable=arguments-differ
386
+ extension: 'bool' = False, **kwargs: 'Any') -> 'None':
387
+ """Post initialisation hook.
388
+
389
+ Args:
390
+ file: Source packet stream.
391
+ length: Length of packet data.
392
+ extension: If the protocol is used as an IPv6 extension header.
393
+ **kwargs: Arbitrary keyword arguments.
394
+
395
+ See Also:
396
+ For construction argument, please refer to :meth:`self.make <IPv6_Opts.make>`.
397
+
398
+ """
399
+ #: bool: If the protocol is used as an IPv6 extension header.
400
+ self._extf = extension
401
+
402
+ # call super __post_init__
403
+ super().__post_init__(file, length, extension=extension, **kwargs) # type: ignore[arg-type]
404
+
405
+ def __length_hint__(self) -> 'Literal[2]':
406
+ """Return an estimated length for the object."""
407
+ return 2
408
+
409
+ @classmethod
410
+ def __index__(cls) -> 'Enum_TransType': # pylint: disable=invalid-index-returned
411
+ """Numeral registry index of the protocol.
412
+
413
+ Returns:
414
+ Numeral registry index of the protocol in `IANA`_.
415
+
416
+ .. _IANA: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
417
+
418
+ """
419
+ return Enum_TransType.IPv6_Opts # type: ignore[return-value]
420
+
421
+ ##########################################################################
422
+ # Utilities.
423
+ ##########################################################################
424
+
425
+ @classmethod
426
+ def _make_data(cls, data: 'Data_IPv6_Opts') -> 'dict[str, Any]': # type: ignore[override]
427
+ """Create key-value pairs from ``data`` for protocol construction.
428
+
429
+ Args:
430
+ data: protocol data
431
+
432
+ Returns:
433
+ Key-value pairs for protocol construction.
434
+
435
+ """
436
+ return {
437
+ 'next': data.next,
438
+ 'options': data.options,
439
+ 'payload': cls._make_payload(data),
440
+ }
441
+
442
+ def _read_opt_type(self, kind: 'int') -> 'tuple[int, bool]':
443
+ """Read option type field.
444
+
445
+ Arguments:
446
+ kind (int): option kind value
447
+
448
+ Returns:
449
+ Extracted IPv6-Opts option type field information (unknown option
450
+ action and change flag), c.f. [:rfc:`8200#section-4.2`].
451
+
452
+ """
453
+ bin_ = bin(kind)[2:].zfill(8)
454
+ return int(bin_[:2], base=2), bool(int(bin_[2], base=2))
455
+
456
+ def _read_ipv6_opts(self, length: 'int') -> 'Option':
457
+ """Read IPv6-Opts options.
458
+
459
+ Positional arguments:
460
+ length: length of options
461
+
462
+ Returns:
463
+ Extracted IPv6-Opts options
464
+
465
+ Raises:
466
+ ProtocolError: If the threshold is **NOT** matching.
467
+
468
+ """
469
+ counter = 0 # length of read options
470
+ options = OrderedMultiDict() # type: Option
471
+
472
+ for schema in self.__header__.options:
473
+ dscp = schema.type
474
+ name = self.__option__[dscp]
475
+
476
+ if isinstance(name, str):
477
+ meth_name = f'_read_opt_{name}'
478
+ meth = cast('OptionParser',
479
+ getattr(self, meth_name, self._read_opt_none))
480
+ else:
481
+ meth = name[0]
482
+ data = meth(schema, options=options)
483
+
484
+ # record option data
485
+ options.add(dscp, data)
486
+ counter += len(schema)
487
+
488
+ # check threshold
489
+ if counter != length:
490
+ raise ProtocolError('IPv6-Opts: invalid format')
491
+ return options
492
+
493
+ def _read_opt_none(self, schema: 'Schema_UnassignedOption', option: 'Option') -> 'Data_UnassignedOption': # pylint: disable=unused-argument
494
+ """Read IPv6-Opts unassigned options.
495
+
496
+ Structure of IPv6-Opts unassigned options [:rfc:`8200`]:
497
+
498
+ .. code-block:: text
499
+
500
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
501
+ | Option Type | Opt Data Len | Option Data
502
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
503
+
504
+ Args:
505
+ schema: parsed parameter schema
506
+ option: extracted IPv6-Opts options
507
+
508
+ Returns:
509
+ Parsed option data.
510
+
511
+ """
512
+ opt = Data_UnassignedOption(
513
+ type=schema.type,
514
+ action=Enum_OptionAction.get(schema.type >> 6),
515
+ change=bool(schema.type & 0b00100000),
516
+ length=schema.len + 2,
517
+ data=schema.data,
518
+ )
519
+ return opt
520
+
521
+ def _read_opt_pad(self, schema: 'Schema_PadOption', option: 'Option') -> 'Data_PadOption': # pylint: disable=unused-argument
522
+ """Read IPv6-Opts padding options.
523
+
524
+ Structure of IPv6-Opts padding options [:rfc:`8200`]:
525
+
526
+ * ``Pad1`` option:
527
+
528
+ .. code-block:: text
529
+
530
+ +-+-+-+-+-+-+-+-+
531
+ | 0 |
532
+ +-+-+-+-+-+-+-+-+
533
+
534
+ * ``PadN`` option:
535
+
536
+ .. code-block:: text
537
+
538
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
539
+ | 1 | Opt Data Len | Option Data
540
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
541
+
542
+ Args:
543
+ schema: parsed parameter schema
544
+ option: extracted IPv6-Opts options
545
+
546
+ Returns:
547
+ Parsed option data.
548
+
549
+ Raises:
550
+ ProtocolError: If ``code`` is **NOT** ``0`` or ``1``.
551
+
552
+ """
553
+ code, clen = schema.type, schema.len
554
+
555
+ if code not in (Enum_Option.Pad1, Enum_Option.PadN):
556
+ raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
557
+ if code == Enum_Option.Pad1 and clen != 0:
558
+ raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
559
+ if code == Enum_Option.PadN and clen == 0:
560
+ raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
561
+
562
+ if code == Enum_Option.Pad1:
563
+ _size = 1
564
+ else:
565
+ _size = schema.len + 2
566
+
567
+ opt = Data_PadOption(
568
+ type=schema.type,
569
+ action=Enum_OptionAction.get(schema.type >> 6),
570
+ change=bool(schema.type & 0b00100000),
571
+ length=_size,
572
+ )
573
+ return opt
574
+
575
+ def _read_opt_tun(self, schema: 'Schema_TunnelEncapsulationLimitOption', option: 'Option') -> 'Data_TunnelEncapsulationLimitOption': # pylint: disable=unused-argument
576
+ """Read IPv6-Opts Tunnel Encapsulation Limit option.
577
+
578
+ Structure of IPv6-Opts Tunnel Encapsulation Limit option [:rfc:`2473`]:
579
+
580
+ .. code-block:: text
581
+
582
+ Option Type Opt Data Len Opt Data Len
583
+ 0 1 2 3 4 5 6 7
584
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
585
+ |0 0 0 0 0 1 0 0| 1 | Tun Encap Lim |
586
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
587
+
588
+ Args:
589
+ schema: parsed parameter schema
590
+ option: extracted IPv6-Opts options
591
+
592
+ Returns:
593
+ Parsed option data.
594
+
595
+ Raises:
596
+ ProtocolError: If ``ipv6_opts.tun.length`` is **NOT** ``1``.
597
+
598
+ """
599
+ if schema.len != 1:
600
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
601
+
602
+ opt = Data_TunnelEncapsulationLimitOption(
603
+ type=schema.type,
604
+ action=Enum_OptionAction.get(schema.type >> 6),
605
+ change=bool(schema.type & 0b00100000),
606
+ length=schema.len + 2,
607
+ limit=schema.limit,
608
+ )
609
+ return opt
610
+
611
+ def _read_opt_ra(self, schema: 'Schema_RouterAlertOption', option: 'Option') -> 'Data_RouterAlertOption': # pylint: disable=unused-argument
612
+ """Read IPv6-Opts Router Alert option.
613
+
614
+ Structure of IPv6-Opts Router Alert option [:rfc:`2711`]:
615
+
616
+ .. code-block:: text
617
+
618
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
619
+ |0 0 0|0 0 1 0 1|0 0 0 0 0 0 1 0| Value (2 octets) |
620
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
621
+
622
+ Args:
623
+ schema: parsed parameter schema
624
+ option: extracted IPv6-Opts options
625
+
626
+ Returns:
627
+ Parsed option data.
628
+
629
+ Raises:
630
+ ProtocolError: If ``ipv6_opts.tun.length`` is **NOT** ``2``.
631
+
632
+ """
633
+ if schema.len != 2:
634
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
635
+
636
+ opt = Data_RouterAlertOption(
637
+ type=schema.type,
638
+ action=Enum_OptionAction.get(schema.type >> 6),
639
+ change=bool(schema.type & 0b00100000),
640
+ length=schema.len + 2,
641
+ value=schema.alert,
642
+ )
643
+ return opt
644
+
645
+ def _read_opt_calipso(self, schema: 'Schema_CALIPSOOption', option: 'Option') -> 'Data_CALIPSOOption': # pylint: disable=unused-argument
646
+ """Read IPv6-Opts Common Architecture Label IPv6 Security Option (CALIPSO) option.
647
+
648
+ Structure of IPv6-Opts CALIPSO option [:rfc:`5570`]:
649
+
650
+ .. code-block:: text
651
+
652
+ ------------------------------------------------------------
653
+ | Next Header | Hdr Ext Len | Option Type | Option Length|
654
+ +-------------+---------------+-------------+--------------+
655
+ | CALIPSO Domain of Interpretation |
656
+ +-------------+---------------+-------------+--------------+
657
+ | Cmpt Length | Sens Level | Checksum (CRC-16) |
658
+ +-------------+---------------+-------------+--------------+
659
+ | Compartment Bitmap (Optional; variable length) |
660
+ +-------------+---------------+-------------+--------------+
661
+
662
+ Args:
663
+ schema: parsed parameter schema
664
+ option: extracted IPv6-Opts options
665
+
666
+ Returns:
667
+ Parsed option data.
668
+
669
+ Raises:
670
+ ProtocolError: If the option is malformed.
671
+
672
+ """
673
+ if schema.len < 8 and schema.len % 8 != 0:
674
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
675
+ if schema.cmpt_len % 2 != 0:
676
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
677
+
678
+ opt = Data_CALIPSOOption(
679
+ type=schema.type,
680
+ action=Enum_OptionAction.get(schema.type >> 6),
681
+ change=bool(schema.type & 0b00100000),
682
+ length=schema.len + 2,
683
+ domain=schema.domain,
684
+ cmpt_len=schema.cmpt_len * 4,
685
+ level=schema.level,
686
+ checksum=schema.checksum,
687
+ )
688
+
689
+ if schema.cmpt_len > 0:
690
+ opt.__update__([
691
+ ('cmpt_bitmap', tuple(schema.bitmap)),
692
+ ])
693
+ return opt
694
+
695
+ def _read_opt_smf_dpd(self, schema: 'Schema_SMFDPDOption', option: 'Option') -> 'Data_SMFDPDOption': # pylint: disable=unused-argument,line-too-long
696
+ """Read IPv6-Opts Simplified Multicast Forwarding Duplicate Packet Detection (``SMF_DPD``) option.
697
+
698
+ Structure of IPv6-Opts ``SMF_DPD`` option [:rfc:`6621`]:
699
+
700
+ * IPv6 ``SMF_DPD`` option header in **I-DPD** (Identification-Based DPD) mode
701
+
702
+ .. code-block:: text
703
+
704
+ 0 1 2 3
705
+ 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
706
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
707
+ ... |0|0|0| 01000 | Opt. Data Len |
708
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
709
+ |0|TidTy| TidLen| TaggerID (optional) ... |
710
+ +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
711
+ | | Identifier ...
712
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
713
+
714
+ * IPv6 ``SMF_DPD`` option header in **H-DPD** (Hash-Based) mode
715
+
716
+ .. code-block:: text
717
+
718
+ 0 1 2 3
719
+ 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
720
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
721
+ ... |0|0|0| OptType | Opt. Data Len |
722
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
723
+ |1| Hash Assist Value (HAV) ...
724
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
725
+
726
+ Args:
727
+ schema: parsed parameter schema
728
+ option: extracted IPv6-Opts options
729
+
730
+ Returns:
731
+ Parsed option data.
732
+
733
+ Raises:
734
+ ProtocolError: If the option is malformed.
735
+
736
+ """
737
+ mode = schema.mode
738
+ if mode == Enum_SMFDPDMode.I_DPD: # I-DPD mode
739
+ if TYPE_CHECKING:
740
+ schema = cast('Schema_SMFIdentificationBasedDPDOption', schema)
741
+
742
+ tid_type = Enum_TaggerID.get(schema.info['type'])
743
+ tid_len = schema.info['len']
744
+
745
+ opt = Data_SMFIdentificationBasedDPDOption(
746
+ type=schema.type,
747
+ action=Enum_OptionAction.get(schema.type >> 6),
748
+ change=bool(schema.type & 0b00100000),
749
+ length=schema.len + 2,
750
+ dpd_type=mode,
751
+ tid_type=tid_type,
752
+ tid_len=tid_len,
753
+ tid=schema.tid,
754
+ id=schema.id,
755
+ ) # type: Data_SMFDPDOption
756
+ elif mode == Enum_SMFDPDMode.H_DPD: # H-DPD mode
757
+ if TYPE_CHECKING:
758
+ schema = cast('Schema_SMFHashBasedDPDOption', schema)
759
+
760
+ opt = Data_SMFHashBasedDPDOption(
761
+ type=schema.type,
762
+ action=Enum_OptionAction.get(schema.type >> 6),
763
+ change=bool(schema.type & 0b00100000),
764
+ length=schema.len + 2,
765
+ dpd_type=mode,
766
+ hav=schema.hav,
767
+ )
768
+ else:
769
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid DPD mode: {mode}')
770
+ return opt
771
+
772
+ def _read_opt_pdm(self, schema: 'Schema_PDMOption', option: 'Option') -> 'Data_PDMOption': # pylint: disable=unused-argument
773
+ """Read IPv6-Opts Performance and Diagnostic Metrics (PDM) option.
774
+
775
+ Structure of IPv6-Opts PDM option [:rfc:`8250`]:
776
+
777
+ .. code-block:: text
778
+
779
+ 0 1 2 3
780
+ 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
781
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
782
+ | Option Type | Option Length | ScaleDTLR | ScaleDTLS |
783
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
784
+ | PSN This Packet | PSN Last Received |
785
+ |-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
786
+ | Delta Time Last Received | Delta Time Last Sent |
787
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
788
+
789
+ Args:
790
+ schema: parsed parameter schema
791
+ option: extracted IPv6-Opts options
792
+
793
+ Returns:
794
+ Parsed option data.
795
+
796
+ Raises:
797
+ ProtocolError: If ``ipv6_opts.pdm.length`` is **NOT** ``10``.
798
+
799
+ """
800
+ if schema.len != 10:
801
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
802
+
803
+ opt = Data_PDMOption(
804
+ type=schema.type,
805
+ action=Enum_OptionAction.get(schema.type >> 6),
806
+ change=bool(schema.type & 0b00100000),
807
+ length=schema.len + 2,
808
+ scaledtlr=schema.scaledtlr,
809
+ scaledtls=schema.scaledtls,
810
+ psntp=schema.psntp,
811
+ psnlr=schema.psnlr,
812
+ deltatlr=schema.deltatlr << schema.scaledtlr,
813
+ deltatls=schema.deltatls << schema.scaledtls,
814
+ )
815
+ return opt
816
+
817
+ def _read_opt_qs(self, schema: 'Schema_QuickStartOption', option: 'Option') -> 'Data_QuickStartOption': # pylint: disable=unused-argument # pylint: disable=unused-argument
818
+ """Read IPv6-Opts Quick Start option.
819
+
820
+ Structure of IPv6-Opts Quick-Start option [:rfc:`4782`]:
821
+
822
+ * A Quick-Start Request:
823
+
824
+ .. code-block:: text
825
+
826
+ 0 1 2 3
827
+ 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
828
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
829
+ | Option | Length=6 | Func. | Rate | QS TTL |
830
+ | | | 0000 |Request| |
831
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
832
+ | QS Nonce | R |
833
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
834
+
835
+ * Report of Approved Rate:
836
+
837
+ .. code-block:: text
838
+
839
+ 0 1 2 3
840
+ 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
841
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
842
+ | Option | Length=6 | Func. | Rate | Not Used |
843
+ | | | 1000 | Report| |
844
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
845
+ | QS Nonce | R |
846
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
847
+
848
+ Args:
849
+ schema: parsed parameter schema
850
+ option: extracted IPv6-Opts options
851
+
852
+ Returns:
853
+ Parsed option data.
854
+
855
+ Raises:
856
+ ProtocolError: If the option is malformed.
857
+
858
+ """
859
+ if schema.len != 6:
860
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
861
+
862
+ func = schema.func
863
+ if func == Enum_QSFunction.Quick_Start_Request:
864
+ schema_req = cast('Schema_QuickStartRequestOption', schema)
865
+
866
+ rate = schema_req.flags['rate']
867
+ opt = Data_QuickStartRequestOption(
868
+ type=schema.type,
869
+ action=Enum_OptionAction.get(schema.type >> 6),
870
+ change=bool(schema.type & 0b00100000),
871
+ length=schema_req.len + 2,
872
+ func=func,
873
+ rate=40000 * (2 ** rate) / 1000 if rate > 0 else 0,
874
+ ttl=datetime.timedelta(seconds=schema_req.ttl),
875
+ nonce=schema_req.nonce['nonce'],
876
+ ) # type: Data_QuickStartOption
877
+ elif func == Enum_QSFunction.Report_of_Approved_Rate:
878
+ schema_rep = cast('Schema_QuickStartReportOption', schema)
879
+
880
+ rate = schema_rep.flags['rate']
881
+ opt = Data_QuickStartReportOption(
882
+ type=schema.type,
883
+ action=Enum_OptionAction.get(schema.type >> 6),
884
+ change=bool(schema.type & 0b00100000),
885
+ length=schema_rep.len + 2,
886
+ func=func,
887
+ rate=40000 * (2 ** rate) / 1000 if rate > 0 else 0,
888
+ nonce=schema_rep.nonce['nonce'],
889
+ )
890
+ else:
891
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] unknown QS function: {func}')
892
+ return opt
893
+
894
+ def _read_opt_rpl(self, schema: 'Schema_RPLOption', option: 'Option') -> 'Data_RPLOption': # pylint: disable=unused-argument
895
+ """Read IPv6-Opts Routing Protocol for Low-Power and Lossy Networks (RPL) option.
896
+
897
+ Structure of IPv6-Opts RPL option [:rfc:`6553`]:
898
+
899
+ .. code-block:: text
900
+
901
+ 0 1 2 3
902
+ 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
903
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
904
+ | Option Type | Opt Data Len |
905
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
906
+ |O|R|F|0|0|0|0|0| RPLInstanceID | SenderRank |
907
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
908
+ | (sub-TLVs) |
909
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
910
+
911
+ Args:
912
+ schema: parsed parameter schema
913
+ option: extracted IPv6-Opts options
914
+
915
+ Returns:
916
+ Parsed option data.
917
+
918
+ Raises:
919
+ ProtocolError: If ``ipv6_opts.rpl.length`` is **NOT** ``4``.
920
+
921
+ """
922
+ if schema.len != 4:
923
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
924
+
925
+ opt = Data_RPLOption(
926
+ type=schema.type,
927
+ action=Enum_OptionAction.get(schema.type >> 6),
928
+ change=bool(schema.type & 0b00100000),
929
+ length=schema.len + 2,
930
+ flags=Data_RPLFlags(
931
+ down=bool(schema.flags['down']),
932
+ rank_err=bool(schema.flags['rank_err']),
933
+ fwd_err=bool(schema.flags['fwd_err']),
934
+ ),
935
+ id=schema.id,
936
+ rank=schema.rank,
937
+ )
938
+ return opt
939
+
940
+ def _read_opt_mpl(self, schema: 'Schema_MPLOption', option: 'Option') -> 'Data_MPLOption': # pylint: disable=unused-argument
941
+ """Read IPv6-Opts Multicast Protocol for Low-Power and Lossy Networks (MPL) option.
942
+
943
+ Structure of IPv6-Opts MPL option [:rfc:`7731`]:
944
+
945
+ .. code-block:: text
946
+
947
+ 0 1 2 3
948
+ 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
949
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
950
+ | Option Type | Opt Data Len |
951
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
952
+ | S |M|V| rsv | sequence | seed-id (optional) |
953
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
954
+
955
+ Args:
956
+ schema: parsed parameter schema
957
+ option: extracted IPv6-Opts options
958
+
959
+ Returns:
960
+ Parsed option data.
961
+
962
+ Raises:
963
+ ProtocolError: If the option is malformed.
964
+
965
+ """
966
+ kind = Enum_SeedID.get(schema.flags['type'])
967
+ clen = schema.len
968
+
969
+ if schema.len < 2:
970
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
971
+ if kind == kind.IPV6_SOURCE_ADDRESS:
972
+ if clen != 2:
973
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid seed-id length: {clen - 2}')
974
+ elif kind == kind.SEEDID_16_BIT_UNSIGNED_INTEGER:
975
+ if clen != 4:
976
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid seed-id length: {clen - 2}')
977
+ elif kind == kind.SEEDID_64_BIT_UNSIGNED_INTEGER:
978
+ if clen != 10:
979
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid seed-id length: {clen - 2}')
980
+ elif kind == kind.SEEDID_128_BIT_UNSIGNED_INTEGER:
981
+ if clen != 18:
982
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid seed-id length: {clen - 2}')
983
+ else:
984
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid seed-id type: {kind}')
985
+
986
+ opt = Data_MPLOption(
987
+ type=schema.type,
988
+ action=Enum_OptionAction.get(schema.type >> 6),
989
+ change=bool(schema.type & 0b00100000),
990
+ length=schema.len + 2,
991
+ seed_type=kind,
992
+ flags=Data_MPLFlags(
993
+ max=bool(schema.flags['max']),
994
+ drop=bool(schema.flags['drop']),
995
+ ),
996
+ seq=schema.seq,
997
+ seed_id=schema.seed if schema.seed is not NoValue else None, # type: ignore[comparison-overlap]
998
+ )
999
+ return opt
1000
+
1001
+ def _read_opt_ilnp(self, schema: 'Schema_ILNPOption', option: 'Option') -> 'Data_ILNPOption': # pylint: disable=unused-argument
1002
+ """Read IPv6-Opts Identifier-Locator Network Protocol (ILNP) Nonce option.
1003
+
1004
+ Structure of IPv6-Opts ILNP Nonce option [:rfc:`6744`]:
1005
+
1006
+ .. code-block:: text
1007
+
1008
+ 0 1 2 3
1009
+ 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
1010
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1011
+ | Next Header | Hdr Ext Len | Option Type | Option Length |
1012
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1013
+ / Nonce Value /
1014
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1015
+
1016
+ Args:
1017
+ schema: parsed parameter schema
1018
+ option: extracted IPv6-Opts options
1019
+
1020
+ Returns:
1021
+ Parsed option data.
1022
+
1023
+ """
1024
+ opt = Data_ILNPOption(
1025
+ type=schema.type,
1026
+ action=Enum_OptionAction.get(schema.type >> 6),
1027
+ change=bool(schema.type & 0b00100000),
1028
+ length=schema.len + 2,
1029
+ nonce=schema.nonce,
1030
+ )
1031
+ return opt
1032
+
1033
+ def _read_opt_lio(self, schema: 'Schema_LineIdentificationOption', option: 'Option') -> 'Data_LineIdentificationOption': # pylint: disable=unused-argument
1034
+ """Read IPv6-Opts Line-Identification option.
1035
+
1036
+ Structure of IPv6-Opts Line-Identification option [:rfc:`6788`]:
1037
+
1038
+ .. code-block:: text
1039
+
1040
+ 0 1 2 3
1041
+ 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
1042
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1043
+ | Option Type | Option Length |
1044
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1045
+ | LineIDLen | Line ID...
1046
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1047
+
1048
+ Args:
1049
+ schema: parsed parameter schema
1050
+ option: extracted IPv6-Opts options
1051
+
1052
+ Returns:
1053
+ Parsed option data.
1054
+
1055
+ """
1056
+ opt = Data_LineIdentificationOption(
1057
+ type=schema.type,
1058
+ action=Enum_OptionAction.get(schema.type >> 6),
1059
+ change=bool(schema.type & 0b00100000),
1060
+ length=schema.len + 2,
1061
+ line_id_len=schema.id_len,
1062
+ line_id=schema.id,
1063
+ )
1064
+ return opt
1065
+
1066
+ def _read_opt_jumbo(self, schema: 'Schema_JumboPayloadOption', option: 'Option') -> 'Data_JumboPayloadOption': # pylint: disable=unused-argument
1067
+ """Read IPv6-Opts Jumbo Payload option.
1068
+
1069
+ Structure of IPv6-Opts Jumbo Payload option [:rfc:`2675`]:
1070
+
1071
+ .. code-block:: text
1072
+
1073
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1074
+ | Option Type | Opt Data Len |
1075
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1076
+ | Jumbo Payload Length |
1077
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1078
+
1079
+ Args:
1080
+ schema: parsed parameter schema
1081
+ option: extracted IPv6-Opts options
1082
+
1083
+ Returns:
1084
+ Parsed option data.
1085
+
1086
+ Raises:
1087
+ ProtocolError: If ``ipv6_opts.jumbo.length`` is **NOT** ``4``.
1088
+
1089
+ """
1090
+ if schema.len != 4:
1091
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
1092
+
1093
+ opt = Data_JumboPayloadOption(
1094
+ type=schema.type,
1095
+ action=Enum_OptionAction.get(schema.type >> 6),
1096
+ change=bool(schema.type & 0b00100000),
1097
+ length=schema.len + 2,
1098
+ jumbo_len=schema.jumbo_len,
1099
+ )
1100
+ return opt
1101
+
1102
+ def _read_opt_home(self, schema: 'Schema_HomeAddressOption', option: 'Option') -> 'Data_HomeAddressOption': # pylint: disable=unused-argument
1103
+ """Read IPv6-Opts Home Address option.
1104
+
1105
+ Structure of IPv6-Opts Home Address option [:rfc:`6275`]:
1106
+
1107
+ .. code-block:: text
1108
+
1109
+ 0 1 2 3
1110
+ 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
1111
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1112
+ | Option Type | Option Length |
1113
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1114
+ | |
1115
+ + +
1116
+ | |
1117
+ + Home Address +
1118
+ | |
1119
+ + +
1120
+ | |
1121
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1122
+
1123
+ Args:
1124
+ schema: parsed parameter schema
1125
+ option: extracted IPv6-Opts options
1126
+
1127
+ Returns:
1128
+ Parsed option data.
1129
+
1130
+ Raises:
1131
+ ProtocolError: If ``ipv6_opts.jumbo.length`` is **NOT** ``16``.
1132
+
1133
+ """
1134
+ if schema.len != 16:
1135
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
1136
+
1137
+ opt = Data_HomeAddressOption(
1138
+ type=schema.type,
1139
+ action=Enum_OptionAction.get(schema.type >> 6),
1140
+ change=bool(schema.type & 0b00100000),
1141
+ length=schema.len + 2,
1142
+ address=schema.addr,
1143
+ )
1144
+ return opt
1145
+
1146
+ def _read_opt_ip_dff(self, schema: 'Schema_IPDFFOption', option: 'Option') -> 'Data_IPDFFOption': # pylint: disable=unused-argument
1147
+ """Read IPv6-Opts Depth-First Forwarding (``IP_DFF``) option.
1148
+
1149
+ Structure of IPv6-Opts ``IP_DFF`` option [:rfc:`6971`]:
1150
+
1151
+ .. code-block:: text
1152
+
1153
+ 1 2 3
1154
+ 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
1155
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1156
+ | Next Header | Hdr Ext Len | OptTypeDFF | OptDataLenDFF |
1157
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1158
+ |VER|D|R|0|0|0|0| Sequence Number | Pad1 |
1159
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1160
+
1161
+ Args:
1162
+ schema: parsed parameter schema
1163
+ option: extracted IPv6-Opts options
1164
+
1165
+ Returns:
1166
+ Parsed option data.
1167
+
1168
+ Raises:
1169
+ ProtocolError: If ``ipv6_opts.ip_dff.length`` is **NOT** ``2``.
1170
+
1171
+ """
1172
+ if schema.len != 2:
1173
+ raise ProtocolError(f'{self.alias}: [OptNo {schema.type}] invalid format')
1174
+
1175
+ opt = Data_IPDFFOption(
1176
+ type=schema.type,
1177
+ action=Enum_OptionAction.get(schema.type >> 6),
1178
+ change=bool(schema.type & 0b00100000),
1179
+ length=schema.len + 2,
1180
+ version=schema.flags['ver'],
1181
+ flags=Data_DFFFlags(
1182
+ dup=bool(schema.flags['dup']),
1183
+ ret=bool(schema.flags['ret']),
1184
+ ),
1185
+ seq=schema.seq,
1186
+ )
1187
+ return opt
1188
+
1189
+ def _make_ipv6_opts(self, options: 'list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes] | Option') -> 'tuple[list[Schema_Option | bytes], int]':
1190
+ """Make options for IPv6-Opts.
1191
+
1192
+ Args:
1193
+ option: IPv6-Opts options
1194
+
1195
+ Returns:
1196
+ Tuple of options and total length of options.
1197
+
1198
+ """
1199
+ total_length = 0
1200
+ if isinstance(options, list):
1201
+ options_list = [] # type: list[Schema_Option | bytes]
1202
+ for schema in options:
1203
+ if isinstance(schema, bytes):
1204
+ code = Enum_Option.get(schema[0])
1205
+ if code in (Enum_Option.Pad1, Enum_Option.PadN): # ignore padding options by default
1206
+ continue
1207
+
1208
+ opt = schema # type: bytes | Schema_Option
1209
+ opt_len = len(schema)
1210
+ elif isinstance(schema, Schema):
1211
+ code = schema.type
1212
+ if code in (Enum_Option.Pad1, Enum_Option.PadN): # ignore padding options by default
1213
+ continue
1214
+
1215
+ opt = schema
1216
+ opt_len = len(schema.pack())
1217
+ else:
1218
+ code, args = cast('tuple[Enum_Option, dict[str, Any]]', schema)
1219
+ if code in (Enum_Option.Pad1, Enum_Option.PadN): # ignore padding options by default
1220
+ continue
1221
+
1222
+ name = self.__option__[code] # type: str | tuple[OptionParser, OptionConstructor]
1223
+ if isinstance(name, str):
1224
+ meth_name = f'_make_opt_{name}'
1225
+ meth = cast('OptionConstructor',
1226
+ getattr(self, meth_name, self._make_opt_none))
1227
+ else:
1228
+ meth = name[1]
1229
+
1230
+ opt = meth(code, **args)
1231
+ opt_len = len(opt.pack())
1232
+
1233
+ options_list.append(opt)
1234
+ total_length += opt_len
1235
+
1236
+ # force alignment to 8 octets
1237
+ if opt_len % 8:
1238
+ pad_len = 8 - (opt_len % 8)
1239
+ if pad_len in (1, 2):
1240
+ pad_opt = self._make_opt_pad(Enum_Option.Pad1, length=0) # type: ignore[arg-type]
1241
+ else:
1242
+ pad_opt = self._make_opt_pad(Enum_Option.PadN, length=pad_len) # type: ignore[arg-type]
1243
+
1244
+ options_list.append(pad_opt)
1245
+ if pad_len == 2: # need 2 Pad1 options
1246
+ options_list.append(pad_opt)
1247
+ total_length += pad_len
1248
+ return options_list, total_length
1249
+
1250
+ options_list = []
1251
+ for code, option in options.items(multi=True):
1252
+ # ignore padding options by default
1253
+ if code in (Enum_Option.Pad1, Enum_Option.PadN):
1254
+ continue
1255
+
1256
+ name = self.__option__[code]
1257
+ if isinstance(name, str):
1258
+ meth_name = f'_make_opt_{name}'
1259
+ meth = cast('OptionConstructor',
1260
+ getattr(self, meth_name, self._make_opt_none))
1261
+ else:
1262
+ meth = name[1]
1263
+
1264
+ opt = meth(code, option)
1265
+ opt_len = len(opt.pack())
1266
+
1267
+ options_list.append(opt)
1268
+ total_length += opt_len
1269
+
1270
+ # force alignment to 8 octets
1271
+ if opt_len % 8:
1272
+ pad_len = 8 - (opt_len % 8)
1273
+ if pad_len in (1, 2):
1274
+ pad_opt = self._make_opt_pad(Enum_Option.Pad1, length=0) # type: ignore[arg-type]
1275
+ else:
1276
+ pad_opt = self._make_opt_pad(Enum_Option.PadN, length=pad_len) # type: ignore[arg-type]
1277
+
1278
+ options_list.append(pad_opt)
1279
+ if pad_len == 2: # need 2 Pad1 options
1280
+ options_list.append(pad_opt)
1281
+ total_length += pad_len
1282
+ return options_list, total_length
1283
+
1284
+ def _make_opt_none(self, code: 'Enum_Option', opt: 'Optional[Data_UnassignedOption]' = None, *,
1285
+ data: 'bytes' = b'',
1286
+ **kwargs: 'Any') -> 'Schema_UnassignedOption':
1287
+ """Make IPv6-Opts unassigned option.
1288
+
1289
+ Args:
1290
+ code: option type value
1291
+ opt: option data
1292
+ data: option payload in :obj:`bytes`
1293
+ **kwargs: arbitrary keyword arguments
1294
+
1295
+ Returns:
1296
+ Constructured option schema.
1297
+
1298
+ """
1299
+ if opt is not None:
1300
+ data = opt.data
1301
+
1302
+ return Schema_UnassignedOption(
1303
+ type=code,
1304
+ len=len(data),
1305
+ data=data,
1306
+ )
1307
+
1308
+ def _make_opt_pad(self, code: 'Enum_Option', opt: 'Optional[Data_PadOption]' = None, *,
1309
+ length: 'int' = 0,
1310
+ **kwargs: 'Any') -> 'Schema_PadOption':
1311
+ """Make IPv6-Opts pad option.
1312
+
1313
+ Args:
1314
+ code: option type value
1315
+ opt: option data
1316
+ length: padding length
1317
+ **kwargs: arbitrary keyword arguments
1318
+
1319
+ Returns:
1320
+ Constructured option schema.
1321
+
1322
+ """
1323
+ if code == Enum_Option.Pad1 and length != 0:
1324
+ #raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
1325
+ warn(f'{self.alias}: [OptNo {code}] invalid format', ProtocolWarning)
1326
+ code = Enum_Option.PadN # type: ignore[assignment]
1327
+ if code == Enum_Option.PadN and length == 0:
1328
+ #raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
1329
+ warn(f'{self.alias}: [OptNo {code}] invalid format', ProtocolWarning)
1330
+ code = Enum_Option.Pad1 # type: ignore[assignment]
1331
+
1332
+ return Schema_PadOption(
1333
+ type=code,
1334
+ len=length,
1335
+ )
1336
+
1337
+ def _make_opt_tun(self, code: 'Enum_Option', opt: 'Optional[Data_TunnelEncapsulationLimitOption]' = None, *,
1338
+ limit: 'int' = 0,
1339
+ **kwargs: 'Any') -> 'Schema_TunnelEncapsulationLimitOption':
1340
+ """Make IPv6-Opts tunnel encapsulation limit option.
1341
+
1342
+ Args:
1343
+ code: option type value
1344
+ opt: option data
1345
+ limit: tunnel encapsulation limit
1346
+ **kwargs: arbitrary keyword arguments
1347
+
1348
+ Returns:
1349
+ Constructured option schema.
1350
+
1351
+ """
1352
+ if opt is not None:
1353
+ limit = opt.limit
1354
+
1355
+ return Schema_TunnelEncapsulationLimitOption(
1356
+ type=code,
1357
+ len=1,
1358
+ limit=limit,
1359
+ )
1360
+
1361
+ def _make_opt_ra(self, code: 'Enum_Option', opt: 'Optional[Data_RouterAlertOption]' = None, *,
1362
+ alert: 'Enum_RouterAlert | StdlibEnum | AenumEnum | str | int' = Enum_RouterAlert.Datagram_contains_a_Multicast_Listener_Discovery_message, # pylint: disable=line-too-long
1363
+ alert_default: 'Optional[int]' = None,
1364
+ alert_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
1365
+ alert_reversed: 'bool' = False,
1366
+ **kwargs: 'Any') -> 'Schema_RouterAlertOption':
1367
+ """Make IPv6-Opts router alert option.
1368
+
1369
+ Args:
1370
+ code: option type value
1371
+ opt: option data
1372
+ alert: router alert value
1373
+ alert_default: default value of router alert
1374
+ alert_namespace: namespace of router alert
1375
+ alert_reversed: reversed flag of router alert
1376
+ **kwargs: arbitrary keyword arguments
1377
+
1378
+ Returns:
1379
+ Constructured option schema.
1380
+
1381
+ """
1382
+ if opt is not None:
1383
+ value = opt.value
1384
+ else:
1385
+ value = self._make_index(alert, alert_default, namespace=alert_namespace, # type: ignore[assignment]
1386
+ reversed=alert_reversed, pack=False)
1387
+
1388
+ return Schema_RouterAlertOption(
1389
+ type=code,
1390
+ len=2,
1391
+ alert=value,
1392
+ )
1393
+
1394
+ def _make_opt_calipso(self, code: 'Enum_Option', opt: 'Optional[Data_CALIPSOOption]' = None, *,
1395
+ domain: 'int' = 0,
1396
+ level: 'int' = 0,
1397
+ checksum: 'bytes' = b'\x00\x00',
1398
+ bitmap: 'Optional[bytes]' = None,
1399
+ **kwargs: 'Any') -> 'Schema_CALIPSOOption':
1400
+ """Make IPv6-Opts calipso option.
1401
+
1402
+ Args:
1403
+ code: option type value
1404
+ opt: option data
1405
+ domain: CALIPSO domain of interpretation
1406
+ level: sensitivity level
1407
+ checksum: checksum of the option
1408
+ bitmap: compartment bitmap
1409
+ **kwargs: arbitrary keyword arguments
1410
+
1411
+ Returns:
1412
+ Constructured option schema.
1413
+
1414
+ """
1415
+ if opt is not None:
1416
+ domain = opt.domain
1417
+ cmpt_len = len(opt.cmpt_bitmap) if hasattr(opt, 'cmpt_bitmap') else 0
1418
+ level = opt.level
1419
+ checksum = opt.checksum
1420
+ bitmap = opt.cmpt_bitmap if hasattr(opt, 'cmpt_bitmap') else None
1421
+
1422
+ return Schema_CALIPSOOption(
1423
+ type=code,
1424
+ len=8 + cmpt_len,
1425
+ domain=domain,
1426
+ cmpt_len=cmpt_len,
1427
+ level=level,
1428
+ checksum=checksum,
1429
+ bitmap=bitmap,
1430
+ )
1431
+
1432
+ def _make_opt_smf_dpd(self, code: 'Enum_Option', opt: 'Optional[Data_SMFIdentificationBasedDPDOption | Data_SMFHashBasedDPDOption]' = None, *,
1433
+ mode: 'Enum_SMFDPDMode | StdlibEnum | AenumEnum | str | int' = Enum_SMFDPDMode.I_DPD,
1434
+ mode_default: 'Optional[int]' = None,
1435
+ mode_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
1436
+ mode_reversed: 'bool' = False,
1437
+ tid: 'Optional[bytes | IPv4Address | IPv6Address]' = None,
1438
+ id: 'bytes' = b'',
1439
+ hav: 'bytes' = b'',
1440
+ **kwargs: 'Any') -> 'Schema_SMFDPDOption':
1441
+ """Make IPv6-Opts SMF DPD option.
1442
+
1443
+ Args:
1444
+ code: option type value
1445
+ opt: option data
1446
+ mode: DPD mode
1447
+ mode_default: default value of DPD mode
1448
+ mode_namespace: namespace of DPD mode
1449
+ mode_reversed: reversed flag of DPD mode
1450
+ tid: Tagger ID
1451
+ id: identifier
1452
+ hav: hash assist value (HAV)
1453
+ **kwargs: arbitrary keyword arguments
1454
+
1455
+ Returns:
1456
+ Constructured option schema.
1457
+
1458
+ """
1459
+ if opt is not None:
1460
+ dpd_type = opt.dpd_type
1461
+ tid = getattr(opt, 'tid', None)
1462
+ id = getattr(opt, 'id', b'')
1463
+ hav = getattr(opt, 'hav', b'')
1464
+
1465
+ dpd_type = self._make_index(mode, mode_default, namespace=mode_namespace, # type: ignore[assignment]
1466
+ reversed=mode_reversed, pack=False)
1467
+
1468
+ if dpd_type == Enum_SMFDPDMode.I_DPD:
1469
+ if tid is None:
1470
+ schema = Schema_SMFIdentificationBasedDPDOption(
1471
+ type=code,
1472
+ len=1 + len(id),
1473
+ info={
1474
+ 'mode': 0,
1475
+ 'type': Enum_TaggerID.NULL,
1476
+ 'len': 0,
1477
+ },
1478
+ tid=None,
1479
+ id=id,
1480
+ ) # type: Schema_SMFDPDOption
1481
+ elif isinstance(tid, bytes):
1482
+ tid_len = len(tid)
1483
+ if tid_len == 0:
1484
+ tid_type = Enum_TaggerID.NULL
1485
+ else:
1486
+ try:
1487
+ tid_ip_ver = ipaddress.ip_address(tid).version
1488
+ if tid_ip_ver == 4:
1489
+ tid_type = Enum_TaggerID.IPv4
1490
+ elif tid_ip_ver == 6:
1491
+ tid_type = Enum_TaggerID.IPv6
1492
+ else:
1493
+ tid_type = Enum_TaggerID.DEFAULT # type: ignore[unreachable]
1494
+ except ValueError:
1495
+ tid_type = Enum_TaggerID.DEFAULT
1496
+
1497
+ schema = Schema_SMFIdentificationBasedDPDOption(
1498
+ type=code,
1499
+ len=1 + tid_len + len(id),
1500
+ info={
1501
+ 'mode': 0,
1502
+ 'type': tid_type,
1503
+ 'len': tid_len - 1,
1504
+ },
1505
+ tid=tid,
1506
+ id=id,
1507
+ )
1508
+ else:
1509
+ tid_ver = tid.version
1510
+ if tid_ver == 4:
1511
+ tid_type = Enum_TaggerID.IPv4
1512
+ tid_len = 4
1513
+ elif tid_ver == 6:
1514
+ tid_type = Enum_TaggerID.IPv6
1515
+ tid_len = 16
1516
+ else:
1517
+ raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid TaggerID version: {tid_ver}')
1518
+
1519
+ schema = Schema_SMFIdentificationBasedDPDOption(
1520
+ type=code,
1521
+ len=1 + tid_len + len(id),
1522
+ info={
1523
+ 'mode': 0,
1524
+ 'type': tid_type,
1525
+ 'len': tid_len - 1,
1526
+ },
1527
+ tid=tid.packed,
1528
+ id=id,
1529
+ )
1530
+ elif dpd_type == Enum_SMFDPDMode.H_DPD:
1531
+ hav_ba = bytearray(hav)
1532
+ hav_ba[0] = hav[0] | 0x80
1533
+
1534
+ schema = Schema_SMFHashBasedDPDOption(
1535
+ type=code,
1536
+ len=len(hav),
1537
+ hav=bytes(hav_ba),
1538
+ )
1539
+ else:
1540
+ raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid DPD type: {dpd_type}')
1541
+ return schema
1542
+
1543
+ def _make_opt_pdm(self, code: 'Enum_Option', opt: 'Optional[Data_PDMOption]' = None, *,
1544
+ psntp: 'int' = 0,
1545
+ psnlr: 'int' = 0,
1546
+ deltatlr: 'int' = 0,
1547
+ deltatls: 'int' = 0,
1548
+ **kwargs: 'Any') -> 'Schema_PDMOption':
1549
+ """Make IPv6-Opts PDM option.
1550
+
1551
+ Args:
1552
+ code: option type value
1553
+ opt: option data
1554
+ psntp: packet sequence number (PSN) this packet
1555
+ psnlr: packet sequence number (PSN) last received
1556
+ deltatlr: delta time last received (in attoseconds)
1557
+ deltatls: delta time last sent (in attoseconds)
1558
+ **kwargs: arbitrary keyword arguments
1559
+
1560
+ Returns:
1561
+ Constructured option schema.
1562
+
1563
+ """
1564
+ if opt is not None:
1565
+ psntp = opt.psntp
1566
+ psnlr = opt.psnlr
1567
+ deltatlr = opt.deltatlr
1568
+ deltatls = opt.deltatls
1569
+
1570
+ dtlr_bl = deltatlr.bit_length()
1571
+ scale_dtlr = dtlr_bl - 16 if dtlr_bl > 16 else 0
1572
+ if scale_dtlr > 255:
1573
+ warn(f'{self.alias}: [OptNo {code}] too large delta time last received: {deltatlr} (scaled: {scale_dtlr})',
1574
+ ProtocolWarning)
1575
+
1576
+ dtls_bl = deltatls.bit_length()
1577
+ scale_dtls = dtls_bl - 16 if dtls_bl > 16 else 0
1578
+ if scale_dtls > 255:
1579
+ warn(f'{self.alias}: [OptNo {code}] too large delta time last sent: {deltatls} (scaled: {scale_dtls})',
1580
+ ProtocolWarning)
1581
+
1582
+ return Schema_PDMOption(
1583
+ type=code,
1584
+ len=10,
1585
+ scaledtlr=scale_dtlr,
1586
+ scaledtls=scale_dtls,
1587
+ psntp=psntp,
1588
+ psnlr=psnlr,
1589
+ deltatlr=deltatlr >> scale_dtlr,
1590
+ deltatls=deltatls >> scale_dtls,
1591
+ )
1592
+
1593
+ def _make_opt_qs(self, code: 'Enum_Option', opt: 'Optional[Data_QuickStartOption]' = None, *,
1594
+ func: 'Enum_QSFunction | StdlibEnum | AenumEnum | str | int' = Enum_QSFunction.Quick_Start_Request,
1595
+ func_default: 'Optional[int]' = None,
1596
+ func_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
1597
+ func_reversed: 'bool' = False,
1598
+ rate: 'int' = 0,
1599
+ ttl: 'timedelta | int' = 0,
1600
+ nonce: 'int' = 0,
1601
+ **kwargs: 'Any') -> 'Schema_QuickStartOption':
1602
+ """Make IPv6-Opts QS option.
1603
+
1604
+ Args:
1605
+ code: option type value
1606
+ opt: option data
1607
+ func: QS function type
1608
+ func_default: default value for QS function type
1609
+ func_namespace: namespace for QS function type
1610
+ func_reversed: reversed flag for QS function type
1611
+ rate: rate (in kbps)
1612
+ ttl: time to live (in seconds)
1613
+ nonce: nonce value
1614
+ **kwargs: arbitrary keyword arguments
1615
+
1616
+ Returns:
1617
+ Constructured option schema.
1618
+
1619
+ """
1620
+ if opt is not None:
1621
+ func_enum = opt.func
1622
+ rate = opt.rate
1623
+ ttl = getattr(opt, 'ttl', 0)
1624
+ nonce = getattr(opt, 'nonce', 0)
1625
+ else:
1626
+ func_enum = self._make_index(func, func_default, namespace=func_namespace, # type: ignore[assignment]
1627
+ reversed=func_reversed, pack=False)
1628
+ rate_val = math.floor(math.log2(rate * 1000 / 40000)) if rate > 0 else 0
1629
+
1630
+ if func_enum == Enum_QSFunction.Quick_Start_Request:
1631
+ ttl_value = ttl if isinstance(ttl, int) else math.floor(ttl.total_seconds())
1632
+
1633
+ return Schema_QuickStartRequestOption(
1634
+ type=code,
1635
+ len=6,
1636
+ flags={
1637
+ 'func': func_enum,
1638
+ 'rate': rate_val,
1639
+ },
1640
+ ttl=ttl_value,
1641
+ nonce={
1642
+ 'nonce': nonce,
1643
+ },
1644
+ )
1645
+ if func_enum == Enum_QSFunction.Report_of_Approved_Rate:
1646
+ return Schema_QuickStartReportOption(
1647
+ type=code,
1648
+ len=6,
1649
+ flags={
1650
+ 'func': func_enum,
1651
+ 'rate': rate_val,
1652
+ },
1653
+ nonce={
1654
+ 'nonce': nonce,
1655
+ },
1656
+ )
1657
+ raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid QS function: {func_enum}')
1658
+
1659
+ def _make_opt_rpl(self, code: 'Enum_Option', opt: 'Optional[Data_RPLOption]' = None, *,
1660
+ down: 'bool' = False,
1661
+ rank_err: 'bool' = False,
1662
+ fwd_err: 'bool' = False,
1663
+ id: 'int' = 0,
1664
+ rank: 'int' = 0,
1665
+ **kwargs: 'Any') -> 'Schema_RPLOption':
1666
+ """Make IPv6-Opts RPL option.
1667
+
1668
+ Args:
1669
+ code: option type value
1670
+ opt: option data
1671
+ down: down flag
1672
+ rank_err: rank error flag
1673
+ fwd_err: forwarding error flag
1674
+ id: RPL instance ID
1675
+ rank: sender rank
1676
+ **kwargs: arbitrary keyword arguments
1677
+
1678
+ Returns:
1679
+ Constructured option schema.
1680
+
1681
+ """
1682
+ if opt is not None:
1683
+ down = opt.flags.down
1684
+ rank_err = opt.flags.rank_err
1685
+ fwd_err = opt.flags.fwd_err
1686
+ id = opt.id
1687
+ rank = opt.rank
1688
+
1689
+ return Schema_RPLOption(
1690
+ type=code,
1691
+ len=4,
1692
+ flags={
1693
+ 'down': down,
1694
+ 'rank_err': rank_err,
1695
+ 'fwd_err': fwd_err,
1696
+ },
1697
+ id=id,
1698
+ rank=rank,
1699
+ )
1700
+
1701
+ def _make_opt_mpl(self, code: 'Enum_Option', opt: 'Optional[Data_MPLOption]' = None, *,
1702
+ max: 'bool' = False,
1703
+ drop: 'bool' = False,
1704
+ seq: 'int' = 0,
1705
+ seed: 'Optional[int]' = None,
1706
+ **kwargs: 'Any') -> 'Schema_MPLOption':
1707
+ """Make IPv6-Opts MPL option.
1708
+
1709
+ Args:
1710
+ code: option type value
1711
+ opt: option data
1712
+ max: maximum sequence number flag
1713
+ drop: drop packet flag
1714
+ seq: MPL sequence number
1715
+ seed: MPL seed ID
1716
+ **kwargs: arbitrary keyword arguments
1717
+
1718
+ Returns:
1719
+ Constructured option schema.
1720
+
1721
+ """
1722
+ if opt is not None:
1723
+ max = opt.flags.max
1724
+ drop = opt.flags.drop
1725
+ seq = opt.seq
1726
+ seed = opt.seed_id
1727
+
1728
+ if seed is None:
1729
+ kind = Enum_SeedID.IPV6_SOURCE_ADDRESS
1730
+ clen = 2
1731
+ else:
1732
+ seed_bl = seed.bit_length()
1733
+ if seed_bl <= 16:
1734
+ kind = Enum_SeedID.SEEDID_16_BIT_UNSIGNED_INTEGER
1735
+ clen = 4
1736
+ elif seed_bl <= 64:
1737
+ kind = Enum_SeedID.SEEDID_64_BIT_UNSIGNED_INTEGER
1738
+ clen = 10
1739
+ elif seed_bl <= 128:
1740
+ kind = Enum_SeedID.SEEDID_128_BIT_UNSIGNED_INTEGER
1741
+ clen = 18
1742
+ else:
1743
+ raise ProtocolError(f'{self.alias}: [OptNo {code}] too large MPL seed ID: {seed}')
1744
+
1745
+ return Schema_MPLOption(
1746
+ type=code,
1747
+ len=clen,
1748
+ flags={
1749
+ 'type': kind,
1750
+ 'max': max,
1751
+ 'drop': drop,
1752
+ },
1753
+ seq=seq,
1754
+ seed=seed,
1755
+ )
1756
+
1757
+ def _make_opt_ilnp(self, code: 'Enum_Option', opt: 'Optional[Data_ILNPOption]' = None, *,
1758
+ nonce: 'int' = 0,
1759
+ **kwargs: 'Any') -> 'Schema_ILNPOption':
1760
+ """Make IPv6-Opts ILNP option.
1761
+
1762
+ Args:
1763
+ code: option type value
1764
+ opt: option data
1765
+ nonce: ILNP nonce value
1766
+ **kwargs: arbitrary keyword arguments
1767
+
1768
+ Returns:
1769
+ Constructured option schema.
1770
+
1771
+ """
1772
+ if opt is not None:
1773
+ nonce = opt.nonce
1774
+
1775
+ return Schema_ILNPOption(
1776
+ type=code,
1777
+ len=math.ceil(nonce.bit_length() // 8),
1778
+ nonce=nonce,
1779
+ )
1780
+
1781
+ def _make_opt_lio(self, code: 'Enum_Option', opt: 'Optional[Data_LineIdentificationOption]' = None, *,
1782
+ id: 'bytes' = b'',
1783
+ **kwargs: 'Any') -> 'Schema_LineIdentificationOption':
1784
+ """Make IPv6-Opts LIO option.
1785
+
1786
+ Args:
1787
+ code: option type value
1788
+ opt: option data
1789
+ id: line ID value
1790
+ **kwargs: arbitrary keyword arguments
1791
+
1792
+ Returns:
1793
+ Constructured option schema.
1794
+
1795
+ """
1796
+ if opt is not None:
1797
+ id = opt.line_id
1798
+
1799
+ return Schema_LineIdentificationOption(
1800
+ type=code,
1801
+ len=len(id) + 1,
1802
+ id_len=len(id),
1803
+ id=id,
1804
+ )
1805
+
1806
+ def _make_opt_jumbo(self, code: 'Enum_Option', opt: 'Optional[Data_JumboPayloadOption]' = None, *,
1807
+ len: 'int' = 0,
1808
+ **kwargs: 'Any') -> 'Schema_JumboPayloadOption':
1809
+ """Make IPv6-Opts Jumbo Payload option.
1810
+
1811
+ Args:
1812
+ code: option type value
1813
+ opt: option data
1814
+ len: jumbo payload length
1815
+ **kwargs: arbitrary keyword arguments
1816
+
1817
+ Returns:
1818
+ Constructured option schema.
1819
+
1820
+ """
1821
+ if opt is not None:
1822
+ len = opt.jumbo_len
1823
+
1824
+ return Schema_JumboPayloadOption(
1825
+ type=code,
1826
+ len=4,
1827
+ jumbo_len=len,
1828
+ )
1829
+
1830
+ def _make_opt_home(self, code: 'Enum_Option', opt: 'Optional[Data_HomeAddressOption]' = None, *,
1831
+ addr: 'IPv6Address | str | bytes | int' = '::',
1832
+ **kwargs: 'Any') -> 'Schema_HomeAddressOption':
1833
+ """Make IPv6-Opts Home Address option.
1834
+
1835
+ Args:
1836
+ code: option type value
1837
+ opt: option data
1838
+ addr: home address value
1839
+ **kwargs: arbitrary keyword arguments
1840
+
1841
+ Returns:
1842
+ Constructured option schema.
1843
+
1844
+ """
1845
+ if opt is not None:
1846
+ addr = opt.address
1847
+
1848
+ return Schema_HomeAddressOption(
1849
+ type=code,
1850
+ len=16,
1851
+ addr=addr,
1852
+ )
1853
+
1854
+ def _make_opt_ip_dff(self, code: 'Enum_Option', opt: 'Optional[Data_IPDFFOption]' = None, *,
1855
+ version: 'int' = 0,
1856
+ dup: 'bool' = False,
1857
+ ret: 'bool' = False,
1858
+ seq: 'int' = 0,
1859
+ **kwargs: 'Any') -> 'Schema_IPDFFOption':
1860
+ """Make IPv6-Opts IP DFF option.
1861
+
1862
+ Args:
1863
+ code: option type value
1864
+ opt: option data
1865
+ version: DFF version
1866
+ dup: duplicate packet flag
1867
+ ret: return packet flag
1868
+ seq: DFF sequence number
1869
+ **kwargs: arbitrary keyword arguments
1870
+
1871
+ Returns:
1872
+ Constructured option schema.
1873
+
1874
+ """
1875
+ if opt is not None:
1876
+ version = opt.version
1877
+ dup = opt.flags.dup
1878
+ ret = opt.flags.ret
1879
+ seq = opt.seq
1880
+
1881
+ return Schema_IPDFFOption(
1882
+ type=code,
1883
+ len=2,
1884
+ flags={
1885
+ 'ver': version,
1886
+ 'dup': dup,
1887
+ 'ret': ret,
1888
+ },
1889
+ seq=seq,
1890
+ )