pypcapkit 1.3.5.post6__cp312-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (466) hide show
  1. pcapkit/__init__.py +124 -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 +298 -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 +69 -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 +32728 -0
  120. pcapkit/const/reg/ethertype.py +714 -0
  121. pcapkit/const/reg/linktype.py +890 -0
  122. pcapkit/const/reg/transtype.py +526 -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 +249 -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 +412 -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 +708 -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 +197 -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 +197 -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.5.post6.dist-info/LICENSE +29 -0
  462. pypcapkit-1.3.5.post6.dist-info/METADATA +238 -0
  463. pypcapkit-1.3.5.post6.dist-info/RECORD +466 -0
  464. pypcapkit-1.3.5.post6.dist-info/WHEEL +5 -0
  465. pypcapkit-1.3.5.post6.dist-info/entry_points.txt +3 -0
  466. pypcapkit-1.3.5.post6.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
+ )