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,2764 @@
1
+ # -*- coding: utf-8 -*-
2
+ # pylint: disable=fixme
3
+ """mobility header
4
+
5
+ :mod:`pcapkit.protocols.internet.mh` contains
6
+ :class:`~pcapkit.protocols.internet.mh.MH` only,
7
+ which implements extractor for Mobility Header
8
+ (MH) [*]_, whose structure is described as below:
9
+
10
+ ======= ========= ================== ===============================
11
+ Octets Bits Name Description
12
+ ======= ========= ================== ===============================
13
+ 0 0 ``mh.next`` Next Header
14
+ 1 8 ``mh.length`` Header Length
15
+ 2 16 ``mh.type`` Mobility Header Type
16
+ 3 24 Reserved
17
+ 4 32 ``mh.chksum`` Checksum
18
+ 6 48 ``mh.data`` Message Data
19
+ ======= ========= ================== ===============================
20
+
21
+ .. [*] https://en.wikipedia.org/wiki/Mobile_IP#Changes_in_IPv6_for_Mobile_IPv6
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.mh.access_type import AccessType as Enum_AccessType
31
+ from pcapkit.const.mh.ack_status_code import ACKStatusCode as Enum_ACKStatusCode
32
+ from pcapkit.const.mh.ani_suboption import ANISuboption as Enum_ANISuboption
33
+ from pcapkit.const.mh.auth_subtype import AuthSubtype as Enum_AuthSubtype
34
+ from pcapkit.const.mh.binding_ack_flag import BindingACKFlag as Enum_BindingACKFlag
35
+ from pcapkit.const.mh.binding_error import BindingError as Enum_BindingError
36
+ from pcapkit.const.mh.binding_revocation import BindingRevocation as Enum_BindingRevocation
37
+ from pcapkit.const.mh.binding_update_flag import BindingUpdateFlag as Enum_BindingUpdateFlag
38
+ from pcapkit.const.mh.cga_extension import CGAExtension as Enum_CGAExtension
39
+ from pcapkit.const.mh.cga_type import CGAType as Enum_CGAType
40
+ from pcapkit.const.mh.dhcp_support_mode import DHCPSupportMode as Enum_DHCPSupportMode
41
+ from pcapkit.const.mh.dns_status_code import DNSStatusCode as Enum_DNSStatusCode
42
+ from pcapkit.const.mh.dsmip6_tls_packet import DSMIP6TLSPacket as Enum_DSMIP6TLSPacket
43
+ from pcapkit.const.mh.dsmipv6_home_address import DSMIPv6HomeAddress as Enum_DSMIPv6HomeAddress
44
+ from pcapkit.const.mh.enumerating_algorithm import EnumeratingAlgorithm as Enum_EnumeratingAlgorithm
45
+ from pcapkit.const.mh.fb_ack_status import FlowBindingACKStatus as Enum_FlowBindingACKStatus
46
+ from pcapkit.const.mh.fb_action import FlowBindingAction as Enum_FlowBindingAction
47
+ from pcapkit.const.mh.fb_indication_trigger import \
48
+ FlowBindingIndicationTrigger as Enum_FlowBindingIndicationTrigger
49
+ from pcapkit.const.mh.fb_type import FlowBindingType as Enum_FlowBindingType
50
+ from pcapkit.const.mh.flow_id_status import FlowIDStatus as Enum_FlowIDStatus
51
+ from pcapkit.const.mh.flow_id_suboption import FlowIDSuboption as Enum_FlowIDSuboption
52
+ from pcapkit.const.mh.handoff_type import HandoffType as Enum_HandoffType
53
+ from pcapkit.const.mh.handover_ack_flag import HandoverACKFlag as Enum_HandoverACKFlag
54
+ from pcapkit.const.mh.handover_ack_status import HandoverACKStatus as Enum_HandoverACKStatus
55
+ from pcapkit.const.mh.handover_initiate_flag import \
56
+ HandoverInitiateFlag as Enum_HandoverInitiateFlag
57
+ from pcapkit.const.mh.home_address_reply import HomeAddressReply as Enum_HomeAddressReply
58
+ from pcapkit.const.mh.lla_code import LLACode as Enum_LLACode
59
+ from pcapkit.const.mh.lma_mag_suboption import \
60
+ LMAControlledMAGSuboption as Enum_LMAControlledMAGSuboption
61
+ from pcapkit.const.mh.mn_group_id import MNGroupID as Enum_MNGroupID
62
+ from pcapkit.const.mh.mn_id_subtype import MNIDSubtype as Enum_MNIDSubtype
63
+ from pcapkit.const.mh.operator_id import OperatorID as Enum_OperatorID
64
+ from pcapkit.const.mh.option import Option as Enum_Option
65
+ from pcapkit.const.mh.packet import Packet as Enum_Packet
66
+ from pcapkit.const.mh.qos_attribute import QoSAttribute as Enum_QoSAttribute
67
+ from pcapkit.const.mh.revocation_status_code import \
68
+ RevocationStatusCode as Enum_RevocationStatusCode
69
+ from pcapkit.const.mh.revocation_trigger import RevocationTrigger as Enum_RevocationTrigger
70
+ from pcapkit.const.mh.status_code import StatusCode as Enum_StatusCode
71
+ from pcapkit.const.mh.traffic_selector import TrafficSelector as Enum_TrafficSelector
72
+ from pcapkit.const.mh.upa_status import \
73
+ UpdateNotificationACKStatus as Enum_UpdateNotificationACKStatus
74
+ from pcapkit.const.mh.upn_reason import UpdateNotificationReason as Enum_UpdateNotificationReason
75
+ from pcapkit.const.reg.transtype import TransType as Enum_TransType
76
+ from pcapkit.protocols.data.internet.mh import MH as Data_MH
77
+ from pcapkit.protocols.data.internet.mh import \
78
+ AlternateCareofAddressOption as Data_AlternateCareofAddressOption
79
+ from pcapkit.protocols.data.internet.mh import AuthOption as Data_AuthOption
80
+ from pcapkit.protocols.data.internet.mh import \
81
+ AuthorizationDataOption as Data_AuthorizationDataOption
82
+ from pcapkit.protocols.data.internet.mh import \
83
+ BindingAcknowledgementMessage as Data_BindingAcknowledgementMessage
84
+ from pcapkit.protocols.data.internet.mh import BindingErrorMessage as Data_BindingErrorMessage
85
+ from pcapkit.protocols.data.internet.mh import \
86
+ BindingRefreshAdviceOption as Data_BindingRefreshAdviceOption
87
+ from pcapkit.protocols.data.internet.mh import \
88
+ BindingRefreshRequestMessage as Data_BindingRefreshRequestMessage
89
+ from pcapkit.protocols.data.internet.mh import BindingUpdateMessage as Data_BindingUpdateMessage
90
+ from pcapkit.protocols.data.internet.mh import CareofTestInitMessage as Data_CareofTestInitMessage
91
+ from pcapkit.protocols.data.internet.mh import CareofTestInitOption as Data_CareofTestInitOption
92
+ from pcapkit.protocols.data.internet.mh import CareofTestMessage as Data_CareofTestMessage
93
+ from pcapkit.protocols.data.internet.mh import CareofTestOption as Data_CareofTestOption
94
+ from pcapkit.protocols.data.internet.mh import CGAExtension as Data_CGAExtension
95
+ from pcapkit.protocols.data.internet.mh import CGAParameter as Data_CGAParameter
96
+ from pcapkit.protocols.data.internet.mh import CGAParametersOption as Data_CGAParametersOption
97
+ from pcapkit.protocols.data.internet.mh import \
98
+ CGAParametersRequestOption as Data_CGAParametersRequestOption
99
+ from pcapkit.protocols.data.internet.mh import HomeTestInitMessage as Data_HomeTestInitMessage
100
+ from pcapkit.protocols.data.internet.mh import HomeTestMessage as Data_HomeTestMessage
101
+ from pcapkit.protocols.data.internet.mh import LinkLayerAddressOption as Data_LinkLayerAddressOption
102
+ from pcapkit.protocols.data.internet.mh import MesgIDOption as Data_MesgIDOption
103
+ from pcapkit.protocols.data.internet.mh import MNIDOption as Data_MNIDOption
104
+ from pcapkit.protocols.data.internet.mh import \
105
+ MobileNetworkPrefixOption as Data_MobileNetworkPrefixOption
106
+ from pcapkit.protocols.data.internet.mh import MultiPrefixExtension as Data_MultiPrefixExtension
107
+ from pcapkit.protocols.data.internet.mh import NonceIndicesOption as Data_NonceIndicesOption
108
+ from pcapkit.protocols.data.internet.mh import PadOption as Data_PadOption
109
+ from pcapkit.protocols.data.internet.mh import \
110
+ PermanentHomeKeygenTokenOption as Data_PermanentHomeKeygenTokenOption
111
+ from pcapkit.protocols.data.internet.mh import SignatureOption as Data_SignatureOption
112
+ from pcapkit.protocols.data.internet.mh import UnassignedOption as Data_UnassignedOption
113
+ from pcapkit.protocols.data.internet.mh import UnknownExtension as Data_UnknownExtension
114
+ from pcapkit.protocols.data.internet.mh import UnknownMessage as Data_UnknownMessage
115
+ from pcapkit.protocols.internet.internet import Internet
116
+ from pcapkit.protocols.schema.internet.mh import MH as Schema_MH
117
+ from pcapkit.protocols.schema.internet.mh import \
118
+ AlternateCareofAddressOption as Schema_AlternateCareofAddressOption
119
+ from pcapkit.protocols.schema.internet.mh import AuthOption as Schema_AuthOption
120
+ from pcapkit.protocols.schema.internet.mh import \
121
+ AuthorizationDataOption as Schema_AuthorizationDataOption
122
+ from pcapkit.protocols.schema.internet.mh import \
123
+ BindingAcknowledgementMessage as Schema_BindingAcknowledgementMessage
124
+ from pcapkit.protocols.schema.internet.mh import BindingErrorMessage as Schema_BindingErrorMessage
125
+ from pcapkit.protocols.schema.internet.mh import \
126
+ BindingRefreshAdviceOption as Schema_BindingRefreshAdviceOption
127
+ from pcapkit.protocols.schema.internet.mh import \
128
+ BindingRefreshRequestMessage as Schema_BindingRefreshRequestMessage
129
+ from pcapkit.protocols.schema.internet.mh import BindingUpdateMessage as Schema_BindingUpdateMessage
130
+ from pcapkit.protocols.schema.internet.mh import \
131
+ CareofTestInitMessage as Schema_CareofTestInitMessage
132
+ from pcapkit.protocols.schema.internet.mh import CareofTestInitOption as Schema_CareofTestInitOption
133
+ from pcapkit.protocols.schema.internet.mh import CareofTestMessage as Schema_CareofTestMessage
134
+ from pcapkit.protocols.schema.internet.mh import CareofTestOption as Schema_CareofTestOption
135
+ from pcapkit.protocols.schema.internet.mh import CGAExtension as Schema_CGAExtension
136
+ from pcapkit.protocols.schema.internet.mh import CGAParameter as Schema_CGAParameter
137
+ from pcapkit.protocols.schema.internet.mh import CGAParametersOption as Schema_CGAParametersOption
138
+ from pcapkit.protocols.schema.internet.mh import \
139
+ CGAParametersRequestOption as Schema_CGAParametersRequestOption
140
+ from pcapkit.protocols.schema.internet.mh import HomeTestInitMessage as Schema_HomeTestInitMessage
141
+ from pcapkit.protocols.schema.internet.mh import HomeTestMessage as Schema_HomeTestMessage
142
+ from pcapkit.protocols.schema.internet.mh import \
143
+ LinkLayerAddressOption as Schema_LinkLayerAddressOption
144
+ from pcapkit.protocols.schema.internet.mh import MesgIDOption as Schema_MesgIDOption
145
+ from pcapkit.protocols.schema.internet.mh import MNIDOption as Schema_MNIDOption
146
+ from pcapkit.protocols.schema.internet.mh import \
147
+ MobileNetworkPrefixOption as Schema_MobileNetworkPrefixOption
148
+ from pcapkit.protocols.schema.internet.mh import MultiPrefixExtension as Schema_MultiPrefixExtension
149
+ from pcapkit.protocols.schema.internet.mh import NonceIndicesOption as Schema_NonceIndicesOption
150
+ from pcapkit.protocols.schema.internet.mh import PadOption as Schema_PadOption
151
+ from pcapkit.protocols.schema.internet.mh import \
152
+ PermanentHomeKeygenTokenOption as Schema_PermanentHomeKeygenTokenOption
153
+ from pcapkit.protocols.schema.internet.mh import SignatureOption as Schema_SignatureOption
154
+ from pcapkit.protocols.schema.internet.mh import UnassignedOption as Schema_UnassignedOption
155
+ from pcapkit.protocols.schema.internet.mh import UnknownExtension as Schema_UnknownExtension
156
+ from pcapkit.protocols.schema.internet.mh import UnknownMessage as Schema_UnknownMessage
157
+ from pcapkit.utilities.exceptions import ProtocolError, UnsupportedCall
158
+ from pcapkit.utilities.warnings import ProtocolWarning, RegistryWarning, warn
159
+
160
+ if TYPE_CHECKING:
161
+ from datetime import datetime as dt_type
162
+ from datetime import timedelta
163
+ from enum import IntEnum as StdlibEnum
164
+ from ipaddress import IPv6Address, IPv6Network
165
+ from typing import IO, Any, Callable, DefaultDict, NoReturn, Optional, Type
166
+
167
+ from aenum import IntEnum as AenumEnum
168
+ from mypy_extensions import DefaultArg, KwArg, NamedArg
169
+ from typing_extensions import Literal
170
+
171
+ from pcapkit.corekit.multidict import OrderedMultiDict
172
+ from pcapkit.corekit.protochain import ProtoChain
173
+ from pcapkit.protocols.data.internet.mh import Option as Data_Option
174
+ from pcapkit.protocols.protocol import ProtocolBase as Protocol
175
+ from pcapkit.protocols.schema.internet.mh import Option as Schema_Option
176
+ from pcapkit.protocols.schema.internet.mh import Packet as Schema_Packet
177
+ from pcapkit.protocols.schema.schema import Schema
178
+
179
+ Option = OrderedMultiDict[Enum_Option, Data_Option]
180
+ Extension = OrderedMultiDict[Enum_CGAExtension, Data_CGAExtension]
181
+
182
+ PacketParser = Callable[[Schema_Packet, NamedArg(Schema_MH, 'header')], Data_MH]
183
+ PacketConstructor = Callable[[DefaultArg(Optional[Data_MH]),
184
+ KwArg(Any)], Schema_Packet]
185
+
186
+ OptionParser = Callable[[Schema_Option, NamedArg(Option, 'options')], Data_Option]
187
+ OptionConstructor = Callable[[Enum_Option, DefaultArg(Optional[Data_Option]),
188
+ KwArg(Any)], Schema_Option]
189
+
190
+ ExtensionParser = Callable[[Schema_CGAExtension, NamedArg(Extension, 'extensions')], Data_CGAExtension]
191
+ ExtensionConstructor = Callable[[Enum_CGAExtension, DefaultArg(Optional[Data_CGAExtension]),
192
+ KwArg(Any)], Schema_CGAExtension]
193
+
194
+ __all__ = ['MH']
195
+
196
+
197
+ class NTPTimestamp(collections.namedtuple('NTPTimestamp', 'seconds fraction')):
198
+ """NTP timestamp format, c.f., :rfc:`1305`."""
199
+
200
+ __slots__ = ()
201
+
202
+ #: Seconds since 1 January 1900.
203
+ seconds: int
204
+ #: Fraction of a second.
205
+ fraction: int
206
+
207
+
208
+ class MH(Internet[Data_MH, Schema_MH],
209
+ schema=Schema_MH, data=Data_MH):
210
+ """This class implements Mobility Header.
211
+
212
+ This class currently supports parsing og the following MH message types,
213
+ which are resgitered in the :attr:`self.__message__ <pcapkit.protocols.internet.mh.MH.__message__>`
214
+ attribute:
215
+
216
+ .. list-table::
217
+ :header-rows: 1
218
+
219
+ * - Message Type
220
+ - Message Parser
221
+ - Message Constructor
222
+ * - :attr:`~pcapkit.const.mh.packet.Packet.Binding_Refresh_Request`
223
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_msg_brr`
224
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_msg_brr`
225
+ * - :attr:`~pcapkit.const.mh.packet.Packet.Home_Test_Init`
226
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_msg_hoti`
227
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_msg_hoti`
228
+ * - :attr:`~pcapkit.const.mh.packet.Packet.Care_of_Test_Init`
229
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_msg_coti`
230
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_msg_coti`
231
+ * - :attr:`~pcapkit.const.mh.packet.Packet.Home_Test`
232
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_msg_hot`
233
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_msg_hot`
234
+ * - :attr:`~pcapkit.const.mh.packet.Packet.Care_of_Test`
235
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_msg_cot`
236
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_msg_cot`
237
+ * - :attr:`~pcapkit.const.mh.packet.Packet.Binding_Update`
238
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_msg_bu`
239
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_msg_bu`
240
+ * - :attr:`~pcapkit.const.mh.packet.Packet.Binding_Acknowledgement`
241
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_msg_ba`
242
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_msg_ba`
243
+ * - :attr:`~pcapkit.const.mh.packet.Packet.Binding_Error`
244
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_msg_be`
245
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_msg_be`
246
+
247
+ This class currently supports parsing the following MH options, which are
248
+ registered in the :attr:`self.__option__ <pcapkit.protocols.internet.mh.MH.__option__>`
249
+ attribute:
250
+
251
+ .. list-table::
252
+ :header-rows: 1
253
+
254
+ * - Option Code
255
+ - Option Parser
256
+ - Option Constructor
257
+
258
+ * - :attr:`~pcapkit.const.mh.option.Option.Pad1`
259
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_pad`
260
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_pad`
261
+ * - :attr:`~pcapkit.const.mh.option.Option.PadN`
262
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_pad`
263
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_pad`
264
+ * - :attr:`~pcapkit.const.mh.option.Option.Binding_Refresh_Advice`
265
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_bra`
266
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_bra`
267
+ * - :attr:`~pcapkit.const.mh.option.Option.Alternate_Care_of_Address`
268
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_aca`
269
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_aca`
270
+ * - :attr:`~pcapkit.const.mh.option.Option.Nonce_Indices`
271
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_ni`
272
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_ni`
273
+ * - :attr:`~pcapkit.const.mh.option.Option.Authorization_Data`
274
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_bad`
275
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_bad`
276
+ * - :attr:`~pcapkit.const.mh.option.Option.Mobile_Network_Prefix_Option`
277
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_mnp`
278
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_mnp`
279
+ * - :attr:`~pcapkit.const.mh.option.Option.Mobility_Header_Link_Layer_Address_option`
280
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_lla`
281
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_lla`
282
+ * - :attr:`~pcapkit.const.mh.option.Option.MN_ID_OPTION_TYPE`
283
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_mn_id`
284
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_mn_id`
285
+ * - :attr:`~pcapkit.const.mh.option.Option.AUTH_OPTION_TYPE`
286
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_auth`
287
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_auth`
288
+ * - :attr:`~pcapkit.const.mh.option.Option.MESG_ID_OPTION_TYPE`
289
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_mesg_id`
290
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_mesg_id`
291
+ * - :attr:`~pcapkit.const.mh.option.Option.CGA_Parameters_Request`
292
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_cga_pr`
293
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_cga_pr`
294
+ * - :attr:`~pcapkit.const.mh.option.Option.CGA_Parameters`
295
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_cga_param`
296
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_cga_param`
297
+ * - :attr:`~pcapkit.const.mh.option.Option.Signature`
298
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_signature`
299
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_signature`
300
+ * - :attr:`~pcapkit.const.mh.option.Option.Permanent_Home_Keygen_Token`
301
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_phkt`
302
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_phkt`
303
+ * - :attr:`~pcapkit.const.mh.option.Option.Care_of_Test_Init`
304
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_ct_init`
305
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_ct_init`
306
+ * - :attr:`~pcapkit.const.mh.option.Option.Care_of_Test`
307
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_opt_ct`
308
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_opt_ct`
309
+
310
+ This class currently supports parsing of the following MH CGA extensions,
311
+ which are registered in the :attr:`self.__extension__ <pcapkit.protocols.internet.mh.MH.__extension__>`
312
+ attribute:
313
+
314
+ .. list-table::
315
+ :header-rows: 1
316
+
317
+ * - CGA Extension Code
318
+ - CGA Extension Parser
319
+ - CGA Extension Constructor
320
+ * - :attr:`~pcapkit.const.mh.extension.cga_extension.CGAExtension.Multi_Prefix`
321
+ - :meth:`~pcapkit.protocols.internet.mh.MH._read_ext_multiprefix`
322
+ - :meth:`~pcapkit.protocols.internet.mh.MH._make_ext_multiprefix`
323
+
324
+ """
325
+
326
+ ##########################################################################
327
+ # Defaults.
328
+ ##########################################################################
329
+
330
+ #: DefaultDict[Enum_Packet, str | tuple[PacketParser, PacketConstructor]]:
331
+ #: Message type to method mapping. Method names are expected to be referred
332
+ #: to the class by ``_read_msg_${name}`` and/or ``_make_msg_${name}``,
333
+ #: and if such name not found, the value should then be a method that can
334
+ #: parse the message type by itself.
335
+ __message__ = collections.defaultdict(
336
+ lambda: 'unknown',
337
+ {
338
+ Enum_Packet.Binding_Refresh_Request: 'brr',
339
+ Enum_Packet.Home_Test_Init: 'hoti',
340
+ Enum_Packet.Care_of_Test_Init: 'coti',
341
+ Enum_Packet.Home_Test: 'hot',
342
+ Enum_Packet.Care_of_Test: 'cot',
343
+ Enum_Packet.Binding_Update: 'bu',
344
+ Enum_Packet.Binding_Acknowledgement: 'ba',
345
+ Enum_Packet.Binding_Error: 'be',
346
+ },
347
+ ) # type: DefaultDict[Enum_Packet | int, str | tuple[PacketParser, PacketConstructor]]
348
+
349
+ #: DefaultDict[Enum_Option, str | tuple[OptionParser, OptionConstructor]]:
350
+ #: Option type to method mapping. Method names are expected to be referred
351
+ #: to the class by ``_read_option_${name}`` and/or ``_make_opt_${name}``,
352
+ #: and if such name not found, the value should then be a method that can
353
+ #: parse the option by itself.
354
+ __option__ = collections.defaultdict(
355
+ lambda: 'none',
356
+ {
357
+ Enum_Option.Pad1: 'pad',
358
+ Enum_Option.PadN: 'pad',
359
+ Enum_Option.Binding_Refresh_Advice: 'bra',
360
+ Enum_Option.Alternate_Care_of_Address: 'aca',
361
+ Enum_Option.Nonce_Indices: 'ni',
362
+ Enum_Option.Authorization_Data: 'bad',
363
+ Enum_Option.Mobile_Network_Prefix_Option: 'mnp',
364
+ Enum_Option.Mobility_Header_Link_Layer_Address_option: 'lla',
365
+ Enum_Option.MN_ID_OPTION_TYPE: 'mn_id',
366
+ Enum_Option.AUTH_OPTION_TYPE: 'auth',
367
+ Enum_Option.MESG_ID_OPTION_TYPE: 'mesg_id',
368
+ Enum_Option.CGA_Parameters_Request: 'cga_pr',
369
+ Enum_Option.CGA_Parameters: 'cga_param',
370
+ Enum_Option.Signature: 'signature',
371
+ Enum_Option.Permanent_Home_Keygen_Token: 'phkt',
372
+ Enum_Option.Care_of_Test_Init: 'ct_init',
373
+ Enum_Option.Care_of_Test: 'ct',
374
+ },
375
+ ) # type: DefaultDict[Enum_Option | int, str | tuple[OptionParser, OptionConstructor]]
376
+
377
+ #: DefaultDict[Enum_CGAExtension, str | tuple[ExtensionParser, ExtensionConstructor]]:
378
+ #: CGA extension type to method mapping. Method names are expected to be referred
379
+ #: to the class by ``_read_extension_${name}`` and/or ``_make_ext_${name}``,
380
+ #: and if such name not found, the value should then be a method that can
381
+ #: parse the CGA extension by itself.
382
+ __extension__ = collections.defaultdict(
383
+ lambda: 'none',
384
+ {
385
+ Enum_CGAExtension.Multi_Prefix: 'multiprefix',
386
+ },
387
+ ) # type: DefaultDict[Enum_CGAExtension | int, str | tuple[ExtensionParser, ExtensionConstructor]]
388
+
389
+ ##########################################################################
390
+ # Properties.
391
+ ##########################################################################
392
+
393
+ @property
394
+ def name(self) -> 'Literal["Mobility Header"]':
395
+ """Name of current protocol."""
396
+ return 'Mobility Header'
397
+
398
+ @property
399
+ def length(self) -> 'int':
400
+ """Header length of current protocol."""
401
+ return self._info.length
402
+
403
+ @property
404
+ def payload(self) -> 'Protocol | NoReturn':
405
+ """Payload of current instance.
406
+
407
+ Raises:
408
+ UnsupportedCall: if the protocol is used as an IPv6 extension header
409
+
410
+ """
411
+ if self._extf:
412
+ raise UnsupportedCall(f"'{self.__class__.__name__}' object has no attribute 'payload'")
413
+ return super().payload
414
+
415
+ @property
416
+ def protocol(self) -> 'Optional[str] | NoReturn':
417
+ """Name of next layer protocol (if any).
418
+
419
+ Raises:
420
+ UnsupportedCall: if the protocol is used as an IPv6 extension header
421
+
422
+ """
423
+ if self._extf:
424
+ raise UnsupportedCall(f"'{self.__class__.__name__}' object has no attribute 'protocol'")
425
+ return super().protocol
426
+
427
+ @property
428
+ def protochain(self) -> 'ProtoChain | NoReturn':
429
+ """Protocol chain of current instance.
430
+
431
+ Raises:
432
+ UnsupportedCall: if the protocol is used as an IPv6 extension header
433
+
434
+ """
435
+ if self._extf:
436
+ raise UnsupportedCall(f"'{self.__class__.__name__}' object has no attribute 'protochain'")
437
+ return super().protochain
438
+
439
+ ##########################################################################
440
+ # Methods.
441
+ ##########################################################################
442
+
443
+ def read(self, length: 'Optional[int]' = None, *, version: 'Literal[4, 6]' = 4, # pylint: disable=arguments-differ,unused-argument
444
+ extension: bool = False, **kwargs: 'Any') -> 'Data_MH': # pylint: disable=unused-argument
445
+ """Read Mobility Header.
446
+
447
+ Structure of MH header [:rfc:`6275`]:
448
+
449
+ .. code-block:: text
450
+
451
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
452
+ | Payload Proto | Header Len | MH Type | Reserved |
453
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
454
+ | Checksum | |
455
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
456
+ | |
457
+ . .
458
+ . Message Data .
459
+ . .
460
+ | |
461
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
462
+
463
+ Args:
464
+ length: Length of packet data.
465
+ version: IP protocol version.
466
+ extension: If the protocol is used as an IPv6 extension header.
467
+ **kwargs: Arbitrary keyword arguments.
468
+
469
+ Returns:
470
+ Parsed packet data.
471
+
472
+ """
473
+ if length is None:
474
+ length = len(self)
475
+ schema = self.__header__
476
+
477
+ name = self.__message__[schema.type]
478
+ if isinstance(name, str):
479
+ meth_name = f'_read_msg_{name}'
480
+ meth = cast('PacketParser',
481
+ getattr(self, meth_name, self._read_msg_unknown))
482
+ else:
483
+ meth = name[0]
484
+ mh = meth(schema.data, header=schema)
485
+
486
+ if extension:
487
+ return mh
488
+ return self._decode_next_layer(mh, schema.next, length - mh.length)
489
+
490
+ def make(self,
491
+ next: 'Enum_TransType | StdlibEnum | AenumEnum | str | int' = Enum_TransType.UDP,
492
+ next_default: 'Optional[int]' = None,
493
+ next_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
494
+ next_reversed: 'bool' = False,
495
+ type: 'Enum_Packet | StdlibEnum | AenumEnum | str | int' = Enum_Packet.Binding_Refresh_Request,
496
+ type_default: 'Optional[int]' = None,
497
+ type_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
498
+ type_reversed: 'bool' = False,
499
+ chksum: 'bytes' = b'',
500
+ data: 'bytes | Data_MH | Schema_Packet | dict[str, Any]' = b'\x00\x00', # minimum length
501
+ payload: 'Protocol | Schema | bytes' = b'',
502
+ **kwargs: 'Any') -> 'Schema_MH':
503
+ """Make (construct) packet data.
504
+
505
+ Args:
506
+ next: Next header type.
507
+ next_default: Default value for next header type field.
508
+ next_namespace: Namespace of next header type field.
509
+ next_reversed: Whether the bits of next header type field is reversed.
510
+ type: Mobility Header type.
511
+ type_default: Default value for Mobility Header type field.
512
+ type_namespace: Namespace of Mobility Header type field.
513
+ type_reversed: Whether the bits of Mobility Header type field is reversed.
514
+ chksum: Checksum.
515
+ data: Message data.
516
+ payload: Payload of next layer protocol.
517
+ **kwargs: Arbitrary keyword arguments.
518
+
519
+ Returns:
520
+ Constructed packet data.
521
+
522
+ """
523
+ next_val = self._make_index(next, next_default, namespace=next_namespace,
524
+ reversed=next_reversed, pack=False)
525
+ type_val = self._make_index(type, type_default, namespace=type_namespace,
526
+ reversed=type_reversed, pack=False)
527
+
528
+ if isinstance(data, bytes):
529
+ data_val = data # type: bytes | Schema_Packet
530
+ elif isinstance(data, (dict, Data_MH)):
531
+ name = self.__message__[type_val]
532
+ if isinstance(name, str):
533
+ meth_name = f'_make_msg_{name}'
534
+ meth = cast('PacketConstructor',
535
+ getattr(self, meth_name, self._make_msg_unknown))
536
+ else:
537
+ meth = name[1]
538
+
539
+ if isinstance(data, dict):
540
+ data_val = meth(**data)
541
+ else:
542
+ data_val = meth(data)
543
+ elif isinstance(data, Schema_Packet):
544
+ data_val = data
545
+ else:
546
+ raise ProtocolError(f'MH: [Type {type_val}] invalid format')
547
+
548
+ return Schema_MH(
549
+ next=next_val,
550
+ length=math.ceil((len(data_val) + 6) / 8) - 1,
551
+ type=type_val,
552
+ chksum=chksum,
553
+ data=data_val,
554
+ payload=payload,
555
+ )
556
+
557
+ @classmethod
558
+ def register_message(cls, code: 'Enum_Packet', meth: 'str | tuple[PacketParser, PacketConstructor]') -> 'None':
559
+ """Register a message parser.
560
+
561
+ Args:
562
+ code: MH message type code.
563
+ meth: Method name or callable to parse and/or construct the message.
564
+
565
+ """
566
+ if code in cls.__message__:
567
+ warn(f'message type {code} already registered, overwriting', RegistryWarning)
568
+ cls.__message__[code] = meth
569
+
570
+ @classmethod
571
+ def register_option(cls, code: 'Enum_Option', meth: 'str | tuple[OptionParser, OptionConstructor]') -> 'None':
572
+ """Register an option parser.
573
+
574
+ Args:
575
+ code: MH option code.
576
+ meth: Method name or callable to parse and/or construct the option.
577
+
578
+ """
579
+ if code in cls.__option__:
580
+ warn(f'option {code} already registered, overwriting', RegistryWarning)
581
+ cls.__option__[code] = meth
582
+
583
+ @classmethod
584
+ def register_extension(cls, code: 'Enum_CGAExtension', meth: 'str | tuple[ExtensionParser, ExtensionConstructor]') -> 'None':
585
+ """Register a CGA extension parser.
586
+
587
+ Args:
588
+ code: CGA extension code.
589
+ meth: Method name or callable to parse and/or construct the extension.
590
+
591
+ """
592
+ if code in cls.__extension__:
593
+ warn(f'extension {code} already registered, overwriting', RegistryWarning)
594
+ cls.__extension__[code] = meth
595
+
596
+ ##########################################################################
597
+ # Data models.
598
+ ##########################################################################
599
+
600
+ @overload
601
+ def __post_init__(self, file: 'IO[bytes] | bytes', length: 'Optional[int]' = ..., *, # pylint: disable=arguments-differ
602
+ extension: 'bool' = ..., **kwargs: 'Any') -> 'None': ...
603
+
604
+ @overload
605
+ def __post_init__(self, **kwargs: 'Any') -> 'None': ... # pylint: disable=arguments-differ
606
+
607
+ def __post_init__(self, file: 'Optional[IO[bytes] | bytes]' = None, length: 'Optional[int]' = None, *, # pylint: disable=arguments-differ
608
+ extension: 'bool' = False, **kwargs: 'Any') -> 'None':
609
+ """Post initialisation hook.
610
+
611
+ Args:
612
+ file: Source packet stream.
613
+ length: Length of packet data.
614
+ extension: If the protocol is used as an IPv6 extension header.
615
+ **kwargs: Arbitrary keyword arguments.
616
+
617
+ See Also:
618
+ For construction argument, please refer to :meth:`self.make <MH.make>`.
619
+
620
+ """
621
+ #: bool: If the protocol is used as an IPv6 extension header.
622
+ self._extf = extension
623
+
624
+ # call super __post_init__
625
+ super().__post_init__(file, length, extension=extension, **kwargs) # type: ignore[arg-type]
626
+
627
+ def __length_hint__(self) -> 'Literal[6]':
628
+ """Return an estimated length for the object."""
629
+ return 6
630
+
631
+ @classmethod
632
+ def __index__(cls) -> 'Enum_TransType': # pylint: disable=invalid-index-returned
633
+ """Numeral registry index of the protocol.
634
+
635
+ Returns:
636
+ Numeral registry index of the protocol in `IANA`_.
637
+
638
+ .. _IANA: https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
639
+
640
+ """
641
+ return Enum_TransType.Mobility_Header # type: ignore[return-value]
642
+
643
+ ##########################################################################
644
+ # Utilities.
645
+ ##########################################################################
646
+
647
+ @classmethod
648
+ def _make_data(cls, data: 'Data_MH') -> 'dict[str, Any]': # type: ignore[override]
649
+ """Create key-value pairs from ``data`` for protocol construction.
650
+
651
+ Args:
652
+ data: protocol data
653
+
654
+ Returns:
655
+ Key-value pairs for protocol construction.
656
+
657
+ """
658
+ return {
659
+ 'next': data.next,
660
+ 'type': data.type,
661
+ 'chksum': data.chksum,
662
+ 'data': data,
663
+ 'payload': cls._make_payload(data),
664
+ }
665
+
666
+ def _read_msg_unknown(self, schema: 'Schema_UnknownMessage', *,
667
+ header: 'Schema_MH') -> 'Data_UnknownMessage':
668
+ """Read unknown MH message type.
669
+
670
+ Args:
671
+ schema: Parsed message type schema.
672
+ header: Parsed MH header schema.
673
+
674
+ Returns:
675
+ Parsed message type data.
676
+
677
+ """
678
+ data = Data_UnknownMessage(
679
+ next=header.next,
680
+ length=(header.length + 1) * 8,
681
+ type=header.type,
682
+ chksum=header.chksum,
683
+ data=schema.data,
684
+ )
685
+ return data
686
+
687
+ def _read_msg_brr(self, schema: 'Schema_BindingRefreshRequestMessage', *,
688
+ header: 'Schema_MH') -> 'Data_BindingRefreshRequestMessage':
689
+ """Read MH binding refresh request (BRR) message type.
690
+
691
+ Structure of MH Binding Refresh Request Message [:rfc:`6275`]:
692
+
693
+ .. code-block:: text
694
+
695
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
696
+ | Reserved |
697
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
698
+ | |
699
+ . .
700
+ . Mobility Options .
701
+ . .
702
+ | |
703
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
704
+
705
+ Args:
706
+ schema: Parsed message type schema.
707
+ header: Parsed MH header schema.
708
+
709
+ Returns:
710
+ Parsed message type data.
711
+
712
+ """
713
+ data = Data_BindingRefreshRequestMessage(
714
+ next=header.next,
715
+ length=(header.length + 1) * 8,
716
+ type=header.type,
717
+ chksum=header.chksum,
718
+ options=self._read_mh_options(schema.options)
719
+ )
720
+ return data
721
+
722
+ def _read_msg_hoti(self, schema: 'Schema_HomeTestInitMessage', *,
723
+ header: 'Schema_MH') -> 'Data_HomeTestInitMessage':
724
+ """Read MH home test initiation (HoTI) message type.
725
+
726
+ Structure of MH Home Test Initiation Message [:rfc:`6275`]:
727
+
728
+ .. code-block:: text
729
+
730
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
731
+ | Reserved |
732
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
733
+ | |
734
+ + Home Init Cookie +
735
+ | |
736
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
737
+ | |
738
+ . .
739
+ . Mobility Options .
740
+ . .
741
+ | |
742
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
743
+
744
+ Args:
745
+ schema: Parsed message type schema.
746
+ header: Parsed MH header schema.
747
+
748
+ Returns:
749
+ Parsed message type data.
750
+
751
+ """
752
+ data = Data_HomeTestInitMessage(
753
+ next=header.next,
754
+ length=(header.length + 1) * 8,
755
+ type=header.type,
756
+ chksum=header.chksum,
757
+ cookie=schema.cookie,
758
+ options=self._read_mh_options(schema.options)
759
+ )
760
+ return data
761
+
762
+ def _read_msg_coti(self, schema: 'Schema_CareofTestInitMessage', *,
763
+ header: 'Schema_MH') -> 'Data_CareofTestInitMessage':
764
+ """Read MH care-of test initiation (CoTI) message type.
765
+
766
+ Structure of MH Care-of Test Initiation Message [:rfc:`6275`]:
767
+
768
+ .. code-block:: text
769
+
770
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
771
+ | Reserved |
772
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
773
+ | |
774
+ + Care-of Init Cookie +
775
+ | |
776
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
777
+ | |
778
+ . .
779
+ . Mobility Options .
780
+ . .
781
+ | |
782
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
783
+
784
+ Args:
785
+ schema: Parsed message type schema.
786
+ header: Parsed MH header schema.
787
+
788
+ Returns:
789
+ Parsed message type data.
790
+
791
+ """
792
+ data = Data_CareofTestInitMessage(
793
+ next=header.next,
794
+ length=(header.length + 1) * 8,
795
+ type=header.type,
796
+ chksum=header.chksum,
797
+ cookie=schema.cookie,
798
+ options=self._read_mh_options(schema.options)
799
+ )
800
+ return data
801
+
802
+ def _read_msg_hot(self, schema: 'Schema_HomeTestMessage', *,
803
+ header: 'Schema_MH') -> 'Data_HomeTestMessage':
804
+ """Read MH home test (HoT) message type.
805
+
806
+ Structure of MH Home Test Message [:rfc:`6275`]:
807
+
808
+ .. code-block:: text
809
+
810
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
811
+ | Home Nonce Index |
812
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
813
+ | |
814
+ + Home Init Cookie +
815
+ | |
816
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
817
+ | |
818
+ + Home Keygen Token +
819
+ | |
820
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
821
+ | |
822
+ . .
823
+ . Mobility Options .
824
+ . .
825
+ | |
826
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
827
+
828
+ Args:
829
+ schema: Parsed message type schema.
830
+ header: Parsed MH header schema.
831
+
832
+ Returns:
833
+ Parsed message type data.
834
+
835
+ """
836
+ data = Data_HomeTestMessage(
837
+ next=header.next,
838
+ length=(header.length + 1) * 8,
839
+ type=header.type,
840
+ chksum=header.chksum,
841
+ nonce_index=schema.nonce_index,
842
+ cookie=schema.cookie,
843
+ token=schema.token,
844
+ options=self._read_mh_options(schema.options),
845
+ )
846
+ return data
847
+
848
+ def _read_msg_cot(self, schema: 'Schema_CareofTestMessage', *,
849
+ header: 'Schema_MH') -> 'Data_CareofTestMessage':
850
+ """Read MH care-of test (CoT) message type.
851
+
852
+ Structure of MH Care-of Test Message [:rfc:`6275`]:
853
+
854
+ .. code-block:: text
855
+
856
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
857
+ | Care-of Nonce Index |
858
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
859
+ | |
860
+ + Care-of Init Cookie +
861
+ | |
862
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
863
+ | |
864
+ + Care-of Keygen Token +
865
+ | |
866
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
867
+ | |
868
+ . .
869
+ . Mobility Options .
870
+ . .
871
+ | |
872
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
873
+
874
+ Args:
875
+ schema: Parsed message type schema.
876
+ header: Parsed MH header schema.
877
+
878
+ Returns:
879
+ Parsed message type data.
880
+
881
+ """
882
+ data = Data_CareofTestMessage(
883
+ next=header.next,
884
+ length=(header.length + 1) * 8,
885
+ type=header.type,
886
+ chksum=header.chksum,
887
+ nonce_index=schema.nonce_index,
888
+ cookie=schema.cookie,
889
+ token=schema.token,
890
+ options=self._read_mh_options(schema.options),
891
+ )
892
+ return data
893
+
894
+ def _read_msg_bu(self, schema: 'Schema_BindingUpdateMessage', *,
895
+ header: 'Schema_MH') -> 'Data_BindingUpdateMessage':
896
+ """Read MH binding update (BU) message type.
897
+
898
+ Structure of MH Binding Update Message [:rfc:`6275`]:
899
+
900
+ .. code-block:: text
901
+
902
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
903
+ | Sequence # |
904
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
905
+ |A|H|L|K| Reserved | Lifetime |
906
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
907
+ | |
908
+ . .
909
+ . Mobility Options .
910
+ . .
911
+ | |
912
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
913
+
914
+ Args:
915
+ schema: Parsed message type schema.
916
+ header: Parsed MH header schema.
917
+
918
+ Returns:
919
+ Parsed message type data.
920
+
921
+ """
922
+ data = Data_BindingUpdateMessage(
923
+ next=header.next,
924
+ length=(header.length + 1) * 8,
925
+ type=header.type,
926
+ chksum=header.chksum,
927
+ seq=schema.seq,
928
+ ack=bool(schema.flags['A']),
929
+ home=bool(schema.flags['H']),
930
+ lla_compat=bool(schema.flags['L']),
931
+ key_mngt=bool(schema.flags['K']),
932
+ lifetime=datetime.timedelta(seconds=schema.lifetime * 4),
933
+ options=self._read_mh_options(schema.options),
934
+ )
935
+ return data
936
+
937
+ def _read_msg_ba(self, schema: 'Schema_BindingAcknowledgementMessage', *,
938
+ header: 'Schema_MH') -> 'Data_BindingAcknowledgementMessage':
939
+ """Read MH binding acknowledgement (BA) message type.
940
+
941
+ Structure of MH Binding Acknowledgement Message [:rfc:`6275`]:
942
+
943
+ .. code-block:: text
944
+
945
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
946
+ | Status |K| Reserved |
947
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
948
+ | Sequence # | Lifetime |
949
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
950
+ | |
951
+ . .
952
+ . Mobility Options .
953
+ . .
954
+ | |
955
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
956
+
957
+ Args:
958
+ schema: Parsed message type schema.
959
+ header: Parsed MH header schema.
960
+
961
+ Returns:
962
+ Parsed message type data.
963
+
964
+ """
965
+ data = Data_BindingAcknowledgementMessage(
966
+ next=header.next,
967
+ length=(header.length + 1) * 8,
968
+ type=header.type,
969
+ chksum=header.chksum,
970
+ status=schema.status,
971
+ key_mngt=bool(schema.flags['K']),
972
+ seq=schema.seq,
973
+ lifetime=datetime.timedelta(seconds=schema.lifetime * 4),
974
+ options=self._read_mh_options(schema.options),
975
+ )
976
+ return data
977
+
978
+ def _read_msg_be(self, schema: 'Schema_BindingErrorMessage', *,
979
+ header: 'Schema_MH') -> 'Data_BindingErrorMessage':
980
+ """Read MH binding error (BE) message type.
981
+
982
+ Structure of MH Binding Error Message [:rfc:`6275`]:
983
+
984
+ .. code-block:: text
985
+
986
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
987
+ | Status | Reserved |
988
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
989
+ | |
990
+ + +
991
+ | |
992
+ + Home Address +
993
+ | |
994
+ + +
995
+ | |
996
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
997
+ . .
998
+ . Mobility Options .
999
+ . .
1000
+ | |
1001
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1002
+
1003
+ Args:
1004
+ schema: Parsed message type schema.
1005
+ header: Parsed MH header schema.
1006
+
1007
+ Returns:
1008
+ Parsed message type data.
1009
+
1010
+ """
1011
+ data = Data_BindingErrorMessage(
1012
+ next=header.next,
1013
+ length=(header.length + 1) * 8,
1014
+ type=header.type,
1015
+ chksum=header.chksum,
1016
+ status=schema.status,
1017
+ home=schema.home,
1018
+ options=self._read_mh_options(schema.options),
1019
+ )
1020
+ return data
1021
+
1022
+ # TODO: Implement other message types.
1023
+
1024
+ def _read_mh_options(self, options_schema: 'list[Schema_Option]') -> 'Option':
1025
+ """Read MH options.
1026
+
1027
+ Structure of MH option [:rfc:`6275`]:
1028
+
1029
+ .. code-block:: text
1030
+
1031
+ 0 1 2 3
1032
+ 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
1033
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1034
+ | Option Type | Option Length | Option Data...
1035
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1036
+
1037
+ Args:
1038
+ options_schema: Parsed MH options.
1039
+
1040
+ Returns:
1041
+ Parsed MH options data.
1042
+
1043
+ """
1044
+ options = OrderedMultiDict() # type: Option
1045
+
1046
+ for schema in options_schema:
1047
+ type = schema.type
1048
+ name = self.__option__[type]
1049
+
1050
+ if isinstance(name, str):
1051
+ meth_name = f'_read_opt_{name}'
1052
+ meth = cast('OptionParser',
1053
+ getattr(self, meth_name, self._read_opt_none))
1054
+ else:
1055
+ meth = name[0]
1056
+ data = meth(schema, options=options)
1057
+
1058
+ # record option data
1059
+ options.add(type, data)
1060
+
1061
+ return options
1062
+
1063
+ def _read_opt_none(self, schema: 'Schema_UnassignedOption', *
1064
+ options: 'Option') -> 'Data_UnassignedOption':
1065
+ """Read MH unassigned option.
1066
+
1067
+ Args:
1068
+ schema: Parsed option schema.
1069
+ options: Parsed MH options.
1070
+
1071
+ Returns:
1072
+ Constructed option data.
1073
+
1074
+ """
1075
+ data = Data_UnassignedOption(
1076
+ type=schema.type,
1077
+ length=schema.length + 2,
1078
+ data=schema.data,
1079
+ )
1080
+ return data
1081
+
1082
+ def _read_opt_pad(self, schema: 'Schema_PadOption', *,
1083
+ options: 'Option') -> 'Data_PadOption':
1084
+ """Read MH padding option.
1085
+
1086
+ Structure of MH padding option [:rfc:`6275`]:
1087
+
1088
+ * ``Pad1`` option:
1089
+
1090
+ .. code-block:: text
1091
+
1092
+ 0
1093
+ 0 1 2 3 4 5 6 7
1094
+ +-+-+-+-+-+-+-+-+
1095
+ | Type = 0 |
1096
+ +-+-+-+-+-+-+-+-+
1097
+
1098
+ * ``PadN`` option:
1099
+
1100
+ .. code-block:: text
1101
+
1102
+ 0 1
1103
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
1104
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
1105
+ | Type = 1 | Option Length | Option Data
1106
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- - - - - - - - -
1107
+
1108
+ Args:
1109
+ schema: Parsed option schema.
1110
+ options: Parsed MH options.
1111
+
1112
+ Returns:
1113
+ Constructed option data.
1114
+
1115
+ """
1116
+ code, clen = schema.type, schema.length
1117
+
1118
+ if code not in (Enum_Option.Pad1, Enum_Option.PadN):
1119
+ raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
1120
+ if code == Enum_Option.Pad1 and clen != 0:
1121
+ raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
1122
+ if code == Enum_Option.PadN and clen == 0:
1123
+ raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format')
1124
+
1125
+ if code == Enum_Option.Pad1:
1126
+ size = 1
1127
+ else:
1128
+ size = clen + 2
1129
+
1130
+ data = Data_PadOption(
1131
+ type=schema.type,
1132
+ length=size,
1133
+ )
1134
+ return data
1135
+
1136
+ def _read_opt_bra(self, schema: 'Schema_BindingRefreshAdviceOption', *,
1137
+ options: 'Option') -> 'Data_BindingRefreshAdviceOption':
1138
+ """Read MH binding refresh advice option.
1139
+
1140
+ Structure of MH Binding Refresh Advice option [:rfc:`6275`]:
1141
+
1142
+ .. code-block:: text
1143
+
1144
+ 0 1 2 3
1145
+ 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
1146
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1147
+ | Type = 2 | Length = 2 |
1148
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1149
+ | Refresh Interval |
1150
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1151
+
1152
+ Args:
1153
+ schema: Parsed option schema.
1154
+ options: Parsed MH options.
1155
+
1156
+ Returns:
1157
+ Constructed option data.
1158
+
1159
+ """
1160
+ if schema.length != 2:
1161
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1162
+
1163
+ data = Data_BindingRefreshAdviceOption(
1164
+ type=schema.type,
1165
+ length=schema.length + 2,
1166
+ interval=schema.interval,
1167
+ )
1168
+ return data
1169
+
1170
+ def _read_opt_aca(self, schema: 'Schema_AlternateCareofAddressOption', *,
1171
+ options: 'Option') -> 'Data_AlternateCareofAddressOption':
1172
+ """Read MH alternate care-of address option.
1173
+
1174
+ Structure of MH Alternate Care-of Address option [:rfc:`6275`]:
1175
+
1176
+ .. code-block:: text
1177
+
1178
+ 0 1 2 3
1179
+ 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
1180
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1181
+ | Type = 3 | Length = 16 |
1182
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1183
+ | |
1184
+ + +
1185
+ | |
1186
+ + Alternate Care-of Address +
1187
+ | |
1188
+ + +
1189
+ | |
1190
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1191
+
1192
+ Args:
1193
+ schema: Parsed option schema.
1194
+ options: Parsed MH options.
1195
+
1196
+ Returns:
1197
+ Constructed option data.
1198
+
1199
+ """
1200
+ if schema.length != 16:
1201
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1202
+
1203
+ data = Data_AlternateCareofAddressOption(
1204
+ type=schema.type,
1205
+ length=schema.length + 2,
1206
+ address=schema.address,
1207
+ )
1208
+ return data
1209
+
1210
+ def _read_opt_ni(self, schema: 'Schema_NonceIndicesOption', *,
1211
+ options: 'Option') -> 'Data_NonceIndicesOption':
1212
+ """Read MH nonce indices option.
1213
+
1214
+ Structure of MH Nonce Indices option [:rfc:`6275`]:
1215
+
1216
+ .. code-block:: text
1217
+
1218
+ 0 1 2 3
1219
+ 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
1220
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1221
+ | Type = 4 | Length = 4 |
1222
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1223
+ | Home Nonce Index | Care-of Nonce Index |
1224
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1225
+
1226
+ Args:
1227
+ schema: Parsed option schema.
1228
+ options: Parsed MH options.
1229
+
1230
+ Returns:
1231
+ Constructed option data.
1232
+
1233
+ """
1234
+ if schema.length != 4:
1235
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1236
+
1237
+ data = Data_NonceIndicesOption(
1238
+ type=schema.type,
1239
+ length=schema.length + 2,
1240
+ home=schema.home,
1241
+ careof=schema.careof,
1242
+ )
1243
+ return data
1244
+
1245
+ def _read_opt_bad(self, schema: 'Schema_AuthorizationDataOption', *,
1246
+ options: 'Option') -> 'Data_AuthorizationDataOption':
1247
+ """Read MH binding authorization data option.
1248
+
1249
+ Structure of MH Binding Authorization Data option [:rfc:`6275`]:
1250
+
1251
+ .. code-block:: text
1252
+
1253
+ 0 1 2 3
1254
+ 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
1255
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1256
+ | Type = 5 | Option Length |
1257
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1258
+ | |
1259
+ + +
1260
+ | Authenticator |
1261
+ + +
1262
+ | |
1263
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1264
+
1265
+ Args:
1266
+ schema: Parsed option schema.
1267
+ options: Parsed MH options.
1268
+
1269
+ Returns:
1270
+ Constructed option data.
1271
+
1272
+ """
1273
+ if schema.length % 8 != 0:
1274
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1275
+
1276
+ data = Data_AuthorizationDataOption(
1277
+ type=schema.type,
1278
+ length=schema.length + 2,
1279
+ data=schema.data,
1280
+ )
1281
+ return data
1282
+
1283
+ def _read_opt_mnp(self, schema: 'Schema_MobileNetworkPrefixOption', *,
1284
+ options: 'Option') -> 'Data_MobileNetworkPrefixOption':
1285
+ """Read MH mobile network prefix option.
1286
+
1287
+ Structure of MH Mobile Network Prefix option [:rfc:`3963`]:
1288
+
1289
+ .. code-block:: text
1290
+
1291
+ 0 1 2 3
1292
+ 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
1293
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1294
+ | Type | Length | Reserved | Prefix Length |
1295
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1296
+ | |
1297
+ + +
1298
+ | |
1299
+ + Mobile Network Prefix +
1300
+ | |
1301
+ + +
1302
+ | |
1303
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1304
+
1305
+ Args:
1306
+ schema: Parsed option schema.
1307
+ options: Parsed MH options.
1308
+
1309
+ Returns:
1310
+ Constructed option data.
1311
+
1312
+ """
1313
+ if schema.length != 18:
1314
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1315
+
1316
+ prefix = cast('IPv6Network',
1317
+ ipaddress.ip_network((schema.prefix, schema.prefix_length)))
1318
+
1319
+ data = Data_MobileNetworkPrefixOption(
1320
+ type=schema.type,
1321
+ length=schema.length + 2,
1322
+ prefix=prefix,
1323
+ )
1324
+ return data
1325
+
1326
+ def _read_opt_lla(self, schema: 'Schema_LinkLayerAddressOption', *,
1327
+ options: 'Option') -> 'Data_LinkLayerAddressOption':
1328
+ """Read MH link-layer address (MH-LLA) option.
1329
+
1330
+ Structure of MH Link-Layer Address option [:rfc:`5568`]:
1331
+
1332
+ .. code-block:: text
1333
+
1334
+ 0 1 2 3
1335
+ 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
1336
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1337
+ | Type | Length |
1338
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1339
+ | Option-Code | LLA ....
1340
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1341
+
1342
+ Args:
1343
+ schema: Parsed option schema.
1344
+ options: Parsed MH options.
1345
+
1346
+ Returns:
1347
+ Constructed option data.
1348
+
1349
+ """
1350
+ if schema.code != Enum_LLACode.MH:
1351
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1352
+
1353
+ data = Data_LinkLayerAddressOption(
1354
+ type=schema.type,
1355
+ length=schema.length + 2,
1356
+ code=schema.code,
1357
+ lla=schema.lla,
1358
+ )
1359
+ return data
1360
+
1361
+ def _read_opt_mn_id(self, schema: 'Schema_MNIDOption', *,
1362
+ options: 'Option') -> 'Data_MNIDOption':
1363
+ """Read MH mobile node identifier option.
1364
+
1365
+ Structure of MH Mobile Node Identifier option [:rfc:`4283`]:
1366
+
1367
+ .. code-block:: text
1368
+
1369
+ 0 1 2 3
1370
+ 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
1371
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1372
+ | Option Type | Option Length |
1373
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1374
+ | Subtype | Identifier ...
1375
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1376
+
1377
+ Args:
1378
+ schema: Parsed option schema.
1379
+ options: Parsed MH options.
1380
+
1381
+ Returns:
1382
+ Constructed option data.
1383
+
1384
+ """
1385
+ data = Data_MNIDOption(
1386
+ type=schema.type,
1387
+ length=schema.length + 2,
1388
+ subtype=schema.subtype,
1389
+ identifier=schema.identifier,
1390
+ )
1391
+ return data
1392
+
1393
+ def _read_opt_auth(self, schema: 'Schema_AuthOption', *,
1394
+ options: 'Option') -> 'Data_AuthOption':
1395
+ """Read MH mobility message authentication option.
1396
+
1397
+ Structure of MH Mobility Message Authentication option [:rfc:`4285`]:
1398
+
1399
+ .. code-block:: text
1400
+
1401
+ 0 1 2 3
1402
+ 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
1403
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1404
+ | Option Type | Option Length | Subtype |
1405
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1406
+ | Mobility SPI |
1407
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1408
+ | Authentication Data ....
1409
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1410
+
1411
+ Args:
1412
+ schema: Parsed option schema.
1413
+ options: Parsed MH options.
1414
+
1415
+ Returns:
1416
+ Constructed option data.
1417
+
1418
+ """
1419
+ if (schema.length + 1) % 4 != 0:
1420
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1421
+
1422
+ data = Data_AuthOption(
1423
+ type=schema.type,
1424
+ length=schema.length + 2,
1425
+ subtype=schema.subtype,
1426
+ spi=schema.spi,
1427
+ data=schema.data,
1428
+ )
1429
+ return data
1430
+
1431
+ def _read_opt_mesg_id(self, schema: 'Schema_MesgIDOption', *,
1432
+ options: 'Option') -> 'Data_MesgIDOption':
1433
+ """Read MH mobility message replay protection option.
1434
+
1435
+ Structure of MH Mobility Message Replay Protection option [:rfc:`4285`]:
1436
+
1437
+ .. code-block:: text
1438
+
1439
+ 0 1 2 3
1440
+ 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
1441
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1442
+ | Option Type | Option Length |
1443
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1444
+ | Timestamp ... |
1445
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1446
+ | Timestamp |
1447
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1448
+
1449
+ Args:
1450
+ schema: Parsed option schema.
1451
+ options: Parsed MH options.
1452
+
1453
+ Returns:
1454
+ Constructed option data.
1455
+
1456
+ """
1457
+ if (schema.length) % 8 != 0:
1458
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1459
+
1460
+ data = Data_MesgIDOption(
1461
+ type=schema.type,
1462
+ length=schema.length + 2,
1463
+ timestamp=schema.timestamp,
1464
+ ntp_timestamp=NTPTimestamp(schema.seconds, schema.fraction),
1465
+ )
1466
+ return data
1467
+
1468
+ def _read_opt_cga_pr(self, schema: 'Schema_CGAParametersRequestOption', *,
1469
+ options: 'Option') -> 'Data_CGAParametersRequestOption':
1470
+ """Read MH CGA parameters request option.
1471
+
1472
+ Structure of MH CGA Parameters Request option [:rfc:`4866`]:
1473
+
1474
+ .. code-block:: text
1475
+
1476
+ 0 1 2 3
1477
+ 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
1478
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1479
+ | Option Type | Option Length |
1480
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1481
+
1482
+ Args:
1483
+ schema: Parsed option schema.
1484
+ options: Parsed MH options.
1485
+
1486
+ Returns:
1487
+ Constructed option data.
1488
+
1489
+ """
1490
+ if schema.length != 0:
1491
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1492
+
1493
+ data = Data_CGAParametersRequestOption(
1494
+ type=schema.type,
1495
+ length=schema.length + 2,
1496
+ )
1497
+ return data
1498
+
1499
+ def _read_opt_cga_param(self, schema: 'Schema_CGAParametersOption', *,
1500
+ options: 'Option') -> 'Data_CGAParametersOption':
1501
+ """Read MH CGA parameters option.
1502
+
1503
+ Structure of MH CGA Parameters option [:rfc:`4866`]:
1504
+
1505
+ .. code-block:: text
1506
+
1507
+ 0 1 2 3
1508
+ 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
1509
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1510
+ | Option Type | Option Length |
1511
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1512
+ | |
1513
+ : :
1514
+ : CGA Parameters :
1515
+ : :
1516
+ | |
1517
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1518
+
1519
+ Args:
1520
+ schema: Parsed option schema.
1521
+ options: Parsed MH options.
1522
+
1523
+ Returns:
1524
+ Constructed option data.
1525
+
1526
+ """
1527
+ for param in schema.parameters:
1528
+ if param.collision_count not in (0, 1, 2):
1529
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1530
+
1531
+ data = Data_CGAParametersOption(
1532
+ type=schema.type,
1533
+ length=schema.length + 2,
1534
+ parameters=tuple(Data_CGAParameter(
1535
+ modifier=param.modifier,
1536
+ prefix=param.prefix,
1537
+ collision_count=param.collision_count,
1538
+ public_key=param.public_key,
1539
+ extensions=self._read_cga_extensions(param.extensions),
1540
+ ) for param in schema.parameters),
1541
+ )
1542
+ return data
1543
+
1544
+ def _read_opt_signature(self, schema: 'Schema_SignatureOption', *,
1545
+ options: 'Option') -> 'Data_SignatureOption':
1546
+ """Read MH signature option.
1547
+
1548
+ Structure of MH Signature option [:rfc:`4866`]:
1549
+
1550
+ .. code-block:: text
1551
+
1552
+ 0 1 2 3
1553
+ 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
1554
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1555
+ | Option Type | Option Length |
1556
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1557
+ | |
1558
+ : :
1559
+ : Signature :
1560
+ : :
1561
+ | |
1562
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1563
+
1564
+ Args:
1565
+ schema: Parsed option schema.
1566
+ options: Parsed MH options.
1567
+
1568
+ Returns:
1569
+ Constructed option data.
1570
+
1571
+ """
1572
+ data = Data_SignatureOption(
1573
+ type=schema.type,
1574
+ length=schema.length + 2,
1575
+ signature=schema.signature,
1576
+ )
1577
+ return data
1578
+
1579
+ def _read_opt_phkt(self, schema: 'Schema_PermanentHomeKeygenTokenOption', *,
1580
+ options: 'Option') -> 'Data_PermanentHomeKeygenTokenOption':
1581
+ """Read MH permanent home keygen token option.
1582
+
1583
+ Structure of MH Permanent Home Keygen Token option [:rfc:`4866`]:
1584
+
1585
+ .. code-block:: text
1586
+
1587
+ 0 1 2 3
1588
+ 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
1589
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1590
+ | Option Type | Option Length |
1591
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1592
+ | |
1593
+ : :
1594
+ : Permanent Home Keygen Token :
1595
+ : :
1596
+ | |
1597
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1598
+
1599
+ Args:
1600
+ schema: Parsed option schema.
1601
+ options: Parsed MH options.
1602
+
1603
+ Returns:
1604
+ Constructed option data.
1605
+
1606
+ """
1607
+ data = Data_PermanentHomeKeygenTokenOption(
1608
+ type=schema.type,
1609
+ length=schema.length + 2,
1610
+ token=schema.token,
1611
+ )
1612
+ return data
1613
+
1614
+ def _read_opt_ct_init(self, schema: 'Schema_CareofTestInitOption', *,
1615
+ options: 'Option') -> 'Data_CareofTestInitOption':
1616
+ """Read MH Care-of Test Init option.
1617
+
1618
+ Structure of MH Care-of Test Init option [:rfc:`4866`]:
1619
+
1620
+ .. code-block:: text
1621
+
1622
+ 0 1 2 3
1623
+ 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
1624
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1625
+ | Option Type | Option Length |
1626
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1627
+
1628
+ Args:
1629
+ schema: Parsed option schema.
1630
+ options: Parsed MH options.
1631
+
1632
+ Returns:
1633
+ Constructed option data.
1634
+
1635
+ """
1636
+ if schema.length != 0:
1637
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1638
+
1639
+ data = Data_CareofTestInitOption(
1640
+ type=schema.type,
1641
+ length=schema.length + 2,
1642
+ )
1643
+ return data
1644
+
1645
+ def _read_opt_ct(self, schema: 'Schema_CareofTestOption', *,
1646
+ options: 'Option') -> 'Data_CareofTestOption':
1647
+ """Read MH Care-of Test option.
1648
+
1649
+ Structure of MH Care-of Test option [:rfc:`4866`]:
1650
+
1651
+ .. code-block:: text
1652
+
1653
+ 0 1 2 3
1654
+ 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
1655
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1656
+ | Option Type | Option Length |
1657
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1658
+ | |
1659
+ + Care-of Keygen Token +
1660
+ | |
1661
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1662
+
1663
+ Args:
1664
+ schema: Parsed option schema.
1665
+ options: Parsed MH options.
1666
+
1667
+ Returns:
1668
+ Constructed option data.
1669
+
1670
+ """
1671
+ if schema.length != 8:
1672
+ raise ProtocolError(f'{self.alias}: [Opt {schema.type}] invalid format')
1673
+
1674
+ data = Data_CareofTestOption(
1675
+ type=schema.type,
1676
+ length=schema.length + 2,
1677
+ token=schema.token,
1678
+ )
1679
+ return data
1680
+
1681
+ # TODO: Implement other options.
1682
+
1683
+ def _read_cga_extensions(self, extensions_schema: 'list[Schema_CGAExtension]') -> 'Extension':
1684
+ """Read CGA extensions.
1685
+
1686
+ Structure of CGA extensions [:rfc:`4581`]:
1687
+
1688
+ .. code-block:: text
1689
+
1690
+ 0 1 2 3
1691
+ 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
1692
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1693
+ | Extension Type | Extension Data Length |
1694
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1695
+ | |
1696
+ ~ Extension Data ~
1697
+ | |
1698
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1699
+
1700
+ Args:
1701
+ extensions_schema: Parsed CGA extensions.
1702
+
1703
+ Returns:
1704
+ Parsed CGA extensions data.
1705
+
1706
+ """
1707
+ extensions = OrderedMultiDict() # type: Extension
1708
+
1709
+ for schema in extensions_schema:
1710
+ type = schema.type
1711
+ name = self.__extension__[type]
1712
+
1713
+ if isinstance(name, str):
1714
+ meth_name = f'_read_ext_{name}'
1715
+ meth = cast('ExtensionParser',
1716
+ getattr(self, meth_name, self._read_ext_none))
1717
+ else:
1718
+ meth = name[0]
1719
+ data = meth(schema, extensions=extensions)
1720
+
1721
+ # record extension data
1722
+ extensions.add(type, data)
1723
+
1724
+ return extensions
1725
+
1726
+ def _read_ext_none(self, schema: 'Schema_UnknownExtension', *,
1727
+ extensions: 'Extension') -> 'Data_UnknownExtension':
1728
+ """Read unknown CGA extension.
1729
+
1730
+ Args:
1731
+ schema: Parsed extension schema.
1732
+ extensions: Parsed MH CGA extensions.
1733
+
1734
+ Returns:
1735
+ Constructed extension data.
1736
+
1737
+ """
1738
+ data = Data_UnknownExtension(
1739
+ type=schema.type,
1740
+ length=schema.length + 2,
1741
+ data=schema.data,
1742
+ )
1743
+ return data
1744
+
1745
+ def _read_ext_multiprefix(self, schema: 'Schema_MultiPrefixExtension', *,
1746
+ extensions: 'Extension') -> 'Data_MultiPrefixExtension':
1747
+ """Read multi-prefix CGA extension.
1748
+
1749
+ Structure of Multi-Prefix CGA extension [:rfc:`5535`]:
1750
+
1751
+ .. code-block:: text
1752
+
1753
+ 0 1 2 3
1754
+ 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
1755
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1756
+ | Extension Type | Extension Data Length |
1757
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1758
+ |P| Reserved |
1759
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1760
+ | |
1761
+ + Prefix[1] +
1762
+ | |
1763
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1764
+ | |
1765
+ + Prefix[2] +
1766
+ | |
1767
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1768
+ . . .
1769
+ . . .
1770
+ . . .
1771
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1772
+ | |
1773
+ + Prefix[n] +
1774
+ | |
1775
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1776
+
1777
+ Args:
1778
+ schema: Parsed extension schema.
1779
+ extensions: Parsed MH CGA extensions.
1780
+
1781
+ Returns:
1782
+ Constructed extension data.
1783
+
1784
+ """
1785
+ data = Data_MultiPrefixExtension(
1786
+ type=schema.type,
1787
+ length=schema.length + 2,
1788
+ flag=bool(schema.flags['P']),
1789
+ prefixes=tuple(schema.prefixes),
1790
+ )
1791
+ return data
1792
+
1793
+ # TODO: Implement other CGA extensions.
1794
+
1795
+ def _make_msg_unknown(self, message: 'Optional[Data_UnknownMessage]', *,
1796
+ data: 'bytes' = b'',
1797
+ **kwargs: 'Any') -> 'Schema_UnknownMessage':
1798
+ """Make MH unknown message type.
1799
+
1800
+ Args:
1801
+ message: Message data model.
1802
+ data: Raw message data.
1803
+ **kwargs: Arbitrary keyword arguments.
1804
+
1805
+ Returns:
1806
+ Constructed message type.
1807
+
1808
+ """
1809
+ if message is not None:
1810
+ data = message.data
1811
+
1812
+ return Schema_UnknownMessage(
1813
+ data=data,
1814
+ )
1815
+
1816
+ def _make_msg_brr(self, message: 'Optional[Data_BindingRefreshRequestMessage]', *,
1817
+ options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None,
1818
+ **kwargs: 'Any') -> 'Schema_BindingRefreshRequestMessage':
1819
+ """Make MH binding refresh request (BRR) message type.
1820
+
1821
+ Args:
1822
+ message: Message data model.
1823
+ options: Mobility options.
1824
+ **kwargs: Arbitrary keyword arguments.
1825
+
1826
+ Returns:
1827
+ Constructed message type.
1828
+
1829
+ """
1830
+ if message is not None:
1831
+ options = message.options
1832
+ else:
1833
+ options = options or []
1834
+
1835
+ return Schema_BindingRefreshRequestMessage(
1836
+ options=self._make_mh_options(options),
1837
+ )
1838
+
1839
+ def _make_msg_hoti(self, message: 'Optional[Data_HomeTestInitMessage]', *,
1840
+ cookie: 'bytes' = b'\x00\x00\x00\x00\x00\x00\x00\x00',
1841
+ options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None,
1842
+ **kwargs: 'Any') -> 'Schema_HomeTestInitMessage':
1843
+ """Make MH home test init (HoTI) message type.
1844
+
1845
+ Args:
1846
+ message: Message data model.
1847
+ cookie: Home test cookie.
1848
+ options: Mobility options.
1849
+ **kwargs: Arbitrary keyword arguments.
1850
+
1851
+ Returns:
1852
+ Constructed message type.
1853
+
1854
+ """
1855
+ if message is not None:
1856
+ cookie = message.cookie
1857
+ options = message.options
1858
+ else:
1859
+ options = options or []
1860
+
1861
+ return Schema_HomeTestInitMessage(
1862
+ cookie=cookie,
1863
+ options=self._make_mh_options(options),
1864
+ )
1865
+
1866
+ def _make_msg_coti(self, message: 'Optional[Data_CareofTestInitMessage]', *,
1867
+ cookie: 'bytes' = b'\x00\x00\x00\x00\x00\x00\x00\x00',
1868
+ options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None,
1869
+ **kwargs: 'Any') -> 'Schema_CareofTestInitMessage':
1870
+ """Make MH care-of test init (CoTI) message type.
1871
+
1872
+ Args:
1873
+ message: Message data model.
1874
+ cookie: Care-of test cookie.
1875
+ options: Mobility options.
1876
+ **kwargs: Arbitrary keyword arguments.
1877
+
1878
+ Returns:
1879
+ Constructed message type.
1880
+
1881
+ """
1882
+ if message is not None:
1883
+ cookie = message.cookie
1884
+ options = message.options
1885
+ else:
1886
+ options = options or []
1887
+
1888
+ return Schema_CareofTestInitMessage(
1889
+ cookie=cookie,
1890
+ options=self._make_mh_options(options),
1891
+ )
1892
+
1893
+ def _make_msg_hot(self, message: 'Optional[Data_HomeTestMessage]', *,
1894
+ nonce_index: 'int' = 0,
1895
+ cookie: 'bytes' = b'\x00\x00\x00\x00\x00\x00\x00\x00',
1896
+ token: 'bytes' = b'\x00\x00\x00\x00\x00\x00\x00\x00',
1897
+ options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None,
1898
+ **kwargs: 'Any') -> 'Schema_HomeTestMessage':
1899
+ """Make MH home test (HoT) message type.
1900
+
1901
+ Args:
1902
+ message: Message data model.
1903
+ nonce_index: Home nonce index.
1904
+ cookie: Home test cookie.
1905
+ token: Home test token.
1906
+ options: Mobility options.
1907
+ **kwargs: Arbitrary keyword arguments.
1908
+
1909
+ Returns:
1910
+ Constructed message type.
1911
+
1912
+ """
1913
+ if message is not None:
1914
+ nonce_index = message.nonce_index
1915
+ cookie = message.cookie
1916
+ token = message.token
1917
+ options = message.options
1918
+ else:
1919
+ options = options or []
1920
+
1921
+ return Schema_HomeTestMessage(
1922
+ nonce_index=nonce_index,
1923
+ cookie=cookie,
1924
+ token=token,
1925
+ options=self._make_mh_options(options),
1926
+ )
1927
+
1928
+ def _make_msg_cot(self, message: 'Optional[Data_CareofTestMessage]', *,
1929
+ nonce_index: 'int' = 0,
1930
+ cookie: 'bytes' = b'\x00\x00\x00\x00\x00\x00\x00\x00',
1931
+ token: 'bytes' = b'\x00\x00\x00\x00\x00\x00\x00\x00',
1932
+ options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None,
1933
+ **kwargs: 'Any') -> 'Schema_CareofTestMessage':
1934
+ """Make MH care-of test (CoT) message type.
1935
+
1936
+ Args:
1937
+ message: Message data model.
1938
+ nonce_index: Care-of nonce index.
1939
+ cookie: Care-of test cookie.
1940
+ token: Care-of test token.
1941
+ options: Mobility options.
1942
+ **kwargs: Arbitrary keyword arguments.
1943
+
1944
+ Returns:
1945
+ Constructed message type.
1946
+
1947
+ """
1948
+ if message is not None:
1949
+ nonce_index = message.nonce_index
1950
+ cookie = message.cookie
1951
+ token = message.token
1952
+ options = message.options
1953
+ else:
1954
+ options = options or []
1955
+
1956
+ return Schema_CareofTestMessage(
1957
+ nonce_index=nonce_index,
1958
+ cookie=cookie,
1959
+ token=token,
1960
+ options=self._make_mh_options(options),
1961
+ )
1962
+
1963
+ def _make_msg_bu(self, message: 'Optional[Data_BindingUpdateMessage]', *,
1964
+ seq: 'int' = 0,
1965
+ ack: 'bool' = False,
1966
+ home: 'bool' = False,
1967
+ lla_compat: 'bool' = False,
1968
+ key_mngt: 'bool' = False,
1969
+ lifetime: 'int | timedelta' = 4, # reasonable default value
1970
+ options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None,
1971
+ **kwargs: 'Any') -> 'Schema_BindingUpdateMessage':
1972
+ """Make MH binding update (BU) message type.
1973
+
1974
+ Args:
1975
+ message: Message data model.
1976
+ seq: Sequence number.
1977
+ ack: Acknowledgement flag.
1978
+ home: Home registration flag.
1979
+ lla_compat: LLA compatibility flag.
1980
+ key_mngt: Key management mobility option flag.
1981
+ lifetime: Lifetime in seconds or timedelta.
1982
+ options: Mobility options.
1983
+ **kwargs: Arbitrary keyword arguments.
1984
+
1985
+ Returns:
1986
+ Constructed message type.
1987
+
1988
+ """
1989
+ if message is not None:
1990
+ seq = message.seq
1991
+ ack = message.ack
1992
+ home = message.home
1993
+ lla_compat = message.lla_compat
1994
+ key_mngt = message.key_mngt
1995
+ lifetime_val = math.ceil(message.lifetime.total_seconds())
1996
+ options = message.options
1997
+ else:
1998
+ lifetime_val = lifetime if isinstance(lifetime, int) else math.ceil(lifetime.total_seconds())
1999
+ options = options or []
2000
+
2001
+ return Schema_BindingUpdateMessage(
2002
+ seq=seq,
2003
+ flags={
2004
+ 'A': ack,
2005
+ 'H': home,
2006
+ 'L': lla_compat,
2007
+ 'K': key_mngt,
2008
+ },
2009
+ lifetime=math.ceil(lifetime_val / 4),
2010
+ options=self._make_mh_options(options),
2011
+ )
2012
+
2013
+ def _make_msg_ba(self, message: 'Optional[Data_BindingAcknowledgementMessage]', *,
2014
+ status: 'Enum_StatusCode | StdlibEnum | AenumEnum | str | int' = Enum_StatusCode.Binding_Update_accepted_Proxy_Binding_Update_accepted,
2015
+ status_default: 'Optional[int]' = None,
2016
+ status_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
2017
+ status_reversed: 'bool' = False,
2018
+ key_mngt: 'bool' = False,
2019
+ seq: 'int' = 0,
2020
+ lifetime: 'int | timedelta' = 4, # reasonable default value
2021
+ options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None,
2022
+ **kwargs: 'Any') -> 'Schema_BindingAcknowledgementMessage':
2023
+ """Make MH binding acknowledge (BA) message type.
2024
+
2025
+ Args:
2026
+ message: Message data model.
2027
+ status: Status code.
2028
+ status_default: Default status code.
2029
+ status_namespace: Status code namespace.
2030
+ status_reversed: Reverse status code namespace.
2031
+ key_mngt: Key management mobility option flag.
2032
+ seq: Sequence number.
2033
+ lifetime: Lifetime in seconds or timedelta.
2034
+ options: Mobility options.
2035
+ **kwargs: Arbitrary keyword arguments.
2036
+
2037
+ Returns:
2038
+ Constructed message type.
2039
+
2040
+ """
2041
+ if message is not None:
2042
+ status_val = message.status
2043
+ key_mngt = message.key_mngt
2044
+ seq = message.seq
2045
+ lifetime_val = math.ceil(message.lifetime.total_seconds())
2046
+ options = message.options
2047
+ else:
2048
+ status_val = self._make_index(status, status_default, namespace=status_namespace, # type: ignore[assignment]
2049
+ reversed=status_reversed, pack=False)
2050
+ lifetime_val = lifetime if isinstance(lifetime, int) else math.ceil(lifetime.total_seconds())
2051
+ options = options or []
2052
+
2053
+ return Schema_BindingAcknowledgementMessage(
2054
+ status=status_val,
2055
+ flags={
2056
+ 'K': key_mngt,
2057
+ },
2058
+ seq=seq,
2059
+ lifetime=math.ceil(lifetime_val / 4),
2060
+ options=self._make_mh_options(options),
2061
+ )
2062
+
2063
+ def _make_msg_be(self, message: 'Optional[Data_BindingErrorMessage]', *,
2064
+ status: 'Enum_StatusCode | StdlibEnum | AenumEnum | str | int' = Enum_StatusCode.Binding_Update_accepted_Proxy_Binding_Update_accepted,
2065
+ status_default: 'Optional[int]' = None,
2066
+ status_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
2067
+ status_reversed: 'bool' = False,
2068
+ home: 'IPv6Address | int | str | bytes' = '::',
2069
+ options: 'Optional[Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]]' = None,
2070
+ **kwargs: 'Any') -> 'Schema_BindingErrorMessage':
2071
+ """Make MH binding error (BE) message type.
2072
+
2073
+ Args:
2074
+ message: Message data model.
2075
+ status: Status code.
2076
+ status_default: Default status code.
2077
+ status_namespace: Status code namespace.
2078
+ status_reversed: Reverse status code namespace.
2079
+ home: Home address.
2080
+ options: Mobility options.
2081
+ **kwargs: Arbitrary keyword arguments.
2082
+
2083
+ Returns:
2084
+ Constructed message type.
2085
+
2086
+ """
2087
+ if message is not None:
2088
+ status_val = message.status
2089
+ home = message.home
2090
+ options = message.options
2091
+ else:
2092
+ status_val = self._make_index(status, status_default, namespace=status_namespace, # type: ignore[assignment]
2093
+ reversed=status_reversed, pack=False)
2094
+ options = options or []
2095
+
2096
+ return Schema_BindingErrorMessage(
2097
+ status=status_val,
2098
+ home=home,
2099
+ options=self._make_mh_options(options),
2100
+ )
2101
+
2102
+ # TODO: Implement other message types.
2103
+
2104
+ def _make_mh_options(self, options: 'Option | list[Schema_Option | tuple[Enum_Option, dict[str, Any]] | bytes]') -> 'list[Schema_Option | bytes]':
2105
+ """Make options for MH.
2106
+
2107
+ Args:
2108
+ options: MH options.
2109
+
2110
+ Returns:
2111
+ Mobility options list.
2112
+
2113
+ """
2114
+ if isinstance(options, list):
2115
+ options_list = [] # type: list[Schema_Option | bytes]
2116
+ for schema in options:
2117
+ if isinstance(schema, bytes):
2118
+ code = Enum_Option.get(int.from_bytes(schema[0:1], 'big', signed=False))
2119
+
2120
+ data = schema # type: Schema_Option | bytes
2121
+ elif isinstance(schema, Schema):
2122
+ data = schema
2123
+ else:
2124
+ code, args = cast('tuple[Enum_Option, dict[str, Any]]', schema)
2125
+ name = self.__option__[code]
2126
+ if isinstance(name, str):
2127
+ meth_name = f'_make_opt_{name}'
2128
+ meth = cast('OptionConstructor',
2129
+ getattr(self, meth_name, self._make_opt_none))
2130
+ else:
2131
+ meth = name[1]
2132
+ data = meth(code, **args)
2133
+
2134
+ options_list.append(data)
2135
+ return options_list
2136
+
2137
+ options_list = []
2138
+ for code, option in options.items(multi=True):
2139
+ name = self.__option__[code]
2140
+ if isinstance(name, str):
2141
+ meth_name = f'_make_opt_{name}'
2142
+ meth = cast('OptionConstructor',
2143
+ getattr(self, meth_name, self._make_opt_none))
2144
+ else:
2145
+ meth = name[1]
2146
+
2147
+ data = meth(code, option)
2148
+ options_list.append(data)
2149
+ return options_list
2150
+
2151
+ def _make_opt_none(self, type: 'Enum_Option', option: 'Optional[Data_UnassignedOption]' = None, *,
2152
+ data: 'bytes' = b'',
2153
+ **kwargs: 'Any') -> 'Schema_UnassignedOption':
2154
+ """Make MH unassigned option.
2155
+
2156
+ Args:
2157
+ type: Option type.
2158
+ option: Option data model.
2159
+ data: Option data.
2160
+ **kwargs: Arbitrary keyword arguments.
2161
+
2162
+ Returns:
2163
+ Constructed option schema.
2164
+
2165
+ """
2166
+ if option is not None:
2167
+ data = option.data
2168
+
2169
+ return Schema_UnassignedOption(
2170
+ type=type,
2171
+ length=len(data),
2172
+ data=data,
2173
+ )
2174
+
2175
+ def _make_opt_pad(self, type: 'Enum_Option', option: 'Optional[Data_PadOption]' = None, *,
2176
+ length: 'int' = 0,
2177
+ **kwargs: 'Any') -> 'Schema_PadOption':
2178
+ """Make MH pad option.
2179
+
2180
+ Args:
2181
+ type: Option type.
2182
+ option: Option data model.
2183
+ length: Padding length.
2184
+ **kwargs: Arbitrary keyword arguments.
2185
+
2186
+ Returns:
2187
+ Constructed option schema.
2188
+
2189
+ """
2190
+ if option is not None:
2191
+ length = option.length
2192
+
2193
+ if type == Enum_Option.Pad1 and length != 0:
2194
+ # raise ProtocolError(f'{self.alias}: [OptNo {type}] invalid format')
2195
+ warn(f'{self.alias}: [OptNo {type}] invalid format', ProtocolWarning)
2196
+ type = Enum_Option.PadN # type: ignore[assignment]
2197
+ if type == Enum_Option.PadN and length == 0:
2198
+ # raise ProtocolError(f'{self.alias}: [OptNo {type}] invalid format')
2199
+ warn(f'{self.alias}: [OptNo {type}] invalid format', ProtocolWarning)
2200
+ type = Enum_Option.Pad1 # type: ignore[assignment]
2201
+
2202
+ return Schema_PadOption(
2203
+ type=type,
2204
+ length=length,
2205
+ )
2206
+
2207
+ def _make_opt_bra(self, type: 'Enum_Option', option: 'Optional[Data_BindingRefreshAdviceOption]' = None, *,
2208
+ interval: 'int' = 0,
2209
+ **kwargs: 'Any') -> 'Schema_BindingRefreshAdviceOption':
2210
+ """Make MH binding refresh advice option.
2211
+
2212
+ Args:
2213
+ type: Option type.
2214
+ option: Option data model.
2215
+ interval: Refresh interval.
2216
+ **kwargs: Arbitrary keyword arguments.
2217
+
2218
+ Returns:
2219
+ Constructed option schema.
2220
+
2221
+ """
2222
+ if option is not None:
2223
+ interval = option.interval
2224
+
2225
+ return Schema_BindingRefreshAdviceOption(
2226
+ type=type,
2227
+ length=2,
2228
+ interval=interval,
2229
+ )
2230
+
2231
+ def _make_opt_aca(self, type: 'Enum_Option', option: 'Optional[Data_AlternateCareofAddressOption]' = None, *,
2232
+ address: 'bytes | str | int | IPv6Address' = '::',
2233
+ **kwargs: 'Any') -> 'Schema_AlternateCareofAddressOption':
2234
+ """Make MH alternate care-of address option.
2235
+
2236
+ Args:
2237
+ type: Option type.
2238
+ option: Option data model.
2239
+ address: Alternate care-of address.
2240
+ **kwargs: Arbitrary keyword arguments.
2241
+
2242
+ Returns:
2243
+ Constructed option schema.
2244
+
2245
+ """
2246
+ if option is not None:
2247
+ address = option.address
2248
+
2249
+ return Schema_AlternateCareofAddressOption(
2250
+ type=type,
2251
+ length=16,
2252
+ address=address,
2253
+ )
2254
+
2255
+ def _make_opt_ni(self, type: 'Enum_Option', option: 'Optional[Data_NonceIndicesOption]' = None, *,
2256
+ home: 'int' = 0,
2257
+ careof: 'int' = 0,
2258
+ **kwargs: 'Any') -> 'Schema_NonceIndicesOption':
2259
+ """Make MH nonce indices option.
2260
+
2261
+ Args:
2262
+ type: Option type.
2263
+ option: Option data model.
2264
+ home: Home nonce index.
2265
+ careof: Care-of nonce index.
2266
+ **kwargs: Arbitrary keyword arguments.
2267
+
2268
+ Returns:
2269
+ Constructed option schema.
2270
+
2271
+ """
2272
+ if option is not None:
2273
+ home = option.home
2274
+ careof = option.careof
2275
+
2276
+ return Schema_NonceIndicesOption(
2277
+ type=type,
2278
+ length=4,
2279
+ home=home,
2280
+ careof=careof,
2281
+ )
2282
+
2283
+ def _make_opt_bad(self, type: 'Enum_Option', option: 'Optional[Data_AuthorizationDataOption]' = None, *,
2284
+ data: 'bytes' = b'',
2285
+ **kwargs: 'Any') -> 'Schema_AuthorizationDataOption':
2286
+ """Make MH binding authorization data option.
2287
+
2288
+ Args:
2289
+ type: Option type.
2290
+ option: Option data model.
2291
+ data: Authenticator.
2292
+ **kwargs: Arbitrary keyword arguments.
2293
+
2294
+ Returns:
2295
+ Constructed option schema.
2296
+
2297
+ """
2298
+ if option is not None:
2299
+ data = option.data
2300
+
2301
+ if len(data) % 8 != 0:
2302
+ raise ProtocolError(f'{self.alias}: [OptNo {type}] invalid format')
2303
+
2304
+ return Schema_AuthorizationDataOption(
2305
+ type=type,
2306
+ length=len(data),
2307
+ data=data,
2308
+ )
2309
+
2310
+ def _make_opt_mnp(self, type: 'Enum_Option', option: 'Optional[Data_MobileNetworkPrefixOption]' = None, *,
2311
+ prefix: 'bytes | str | IPv6Network' = '::/0',
2312
+ **kwargs: 'Any') -> 'Schema_MobileNetworkPrefixOption':
2313
+ """Make MH mobile network prefix option.
2314
+
2315
+ Args:
2316
+ type: Option type.
2317
+ option: Option data model.
2318
+ prefix: Mobile network prefix.
2319
+ **kwargs: Arbitrary keyword arguments.
2320
+
2321
+ Returns:
2322
+ Constructed option schema.
2323
+
2324
+ """
2325
+ if option is not None:
2326
+ prefix = option.prefix
2327
+
2328
+ prefix_val = ipaddress.ip_network(prefix)
2329
+ if prefix_val.version != 6:
2330
+ raise ProtocolError(f'{self.alias}: [OptNo {type}] invalid movile network prefix: {prefix!r}')
2331
+ prefix_length = prefix_val.prefixlen
2332
+ prefix_addr = prefix_val.network_address
2333
+
2334
+ return Schema_MobileNetworkPrefixOption(
2335
+ type=type,
2336
+ length=18,
2337
+ prefix_length=prefix_length,
2338
+ prefix=prefix_addr,
2339
+ )
2340
+
2341
+ def _make_opt_lla(self, type: 'Enum_Option', option: 'Optional[Data_LinkLayerAddressOption]' = None, *,
2342
+ address: 'bytes' = b'',
2343
+ **kwargs: 'Any') -> 'Schema_LinkLayerAddressOption':
2344
+ """Make MH link-layer address option.
2345
+
2346
+ Args:
2347
+ type: Option type.
2348
+ option: Option data model.
2349
+ address: Link-layer address.
2350
+ **kwargs: Arbitrary keyword arguments.
2351
+
2352
+ Returns:
2353
+ Constructed option schema.
2354
+
2355
+ """
2356
+ if option is not None:
2357
+ address = option.lla
2358
+
2359
+ return Schema_LinkLayerAddressOption(
2360
+ type=type,
2361
+ length=len(address) + 1,
2362
+ code=Enum_LLACode.MH, # type: ignore[arg-type]
2363
+ lla=address,
2364
+ )
2365
+
2366
+ def _make_opt_mn_id(self, type: 'Enum_Option', option: 'Optional[Data_MNIDOption]' = None, *,
2367
+ subtype: 'Enum_MNIDSubtype | StdlibEnum | AenumEnum | str | int' = Enum_MNIDSubtype.IPv6_Address,
2368
+ subtype_default: 'Optional[int]' = None,
2369
+ subtype_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
2370
+ subtype_reversed: 'bool' = False,
2371
+ identifier: 'bytes | str | IPv6Address | int' = '::',
2372
+ **kwargs: 'Any') -> 'Schema_MNIDOption':
2373
+ """Make MH mobile node identifier option.
2374
+
2375
+ Args:
2376
+ type: Option type.
2377
+ option: Option data model.
2378
+ subtype: MN-ID subtype.
2379
+ subtype_default: MN-ID subtype default value.
2380
+ subtype_namespace: MN-ID subtype namespace.
2381
+ subtype_reversed: MN-ID subtype reversed flag.
2382
+ identifier: Identifier.
2383
+ **kwargs: Arbitrary keyword arguments.
2384
+
2385
+ Returns:
2386
+ Constructed option schema.
2387
+
2388
+ """
2389
+ if option is not None:
2390
+ subtype_val = option.subtype
2391
+ identifier = option.identifier
2392
+ else:
2393
+ subtype_val = self._make_index(subtype, subtype_default, namespace=subtype_namespace, # type: ignore[assignment]
2394
+ reversed=subtype_reversed, pack=False)
2395
+
2396
+ if isinstance(identifier, ipaddress.IPv6Address):
2397
+ id_len = 16
2398
+ elif isinstance(identifier, int):
2399
+ id_len = math.ceil(identifier.bit_length() / 8)
2400
+ else:
2401
+ id_len = len(identifier)
2402
+
2403
+ return Schema_MNIDOption(
2404
+ type=type,
2405
+ length=1 + id_len,
2406
+ subtype=subtype_val,
2407
+ identifier=identifier,
2408
+ )
2409
+
2410
+ def _make_opt_auth(self, type: 'Enum_Option', option: 'Optional[Data_AuthOption]' = None, *,
2411
+ subtype: 'Enum_AuthSubtype | StdlibEnum | AenumEnum | str | int' = Enum_AuthSubtype.MN_HA,
2412
+ subtype_default: 'Optional[int]' = None,
2413
+ subtype_namespace: 'Optional[dict[str, int] | dict[int, str] | Type[StdlibEnum] | Type[AenumEnum]]' = None, # pylint: disable=line-too-long
2414
+ subtype_reversed: 'bool' = False,
2415
+ spi: 'int' = 0,
2416
+ data: 'bytes' = b'',
2417
+ **kwargs: 'Any') -> 'Schema_AuthOption':
2418
+ """Make MH authentication option.
2419
+
2420
+ Args:
2421
+ type: Option type.
2422
+ option: Option data model.
2423
+ subtype: Authentication subtype.
2424
+ subtype_default: Authentication subtype default value.
2425
+ subtype_namespace: Authentication subtype namespace.
2426
+ subtype_reversed: Authentication subtype reversed flag.
2427
+ spi: Security parameter index.
2428
+ data: Authentication data.
2429
+ **kwargs: Arbitrary keyword arguments.
2430
+
2431
+ Returns:
2432
+ Constructed option schema.
2433
+
2434
+ """
2435
+ if option is not None:
2436
+ subtype_val = option.subtype
2437
+ spi = option.spi
2438
+ data = option.data
2439
+ else:
2440
+ subtype_val = self._make_index(subtype, subtype_default, namespace=subtype_namespace, # type: ignore[assignment]
2441
+ reversed=subtype_reversed, pack=False)
2442
+
2443
+ if (len(data) + 6) % 4 != 0:
2444
+ raise ProtocolError(f'{self.alias}: [OptNo {type}] invalid format')
2445
+
2446
+ return Schema_AuthOption(
2447
+ type=type,
2448
+ length=5 + len(data),
2449
+ subtype=subtype_val,
2450
+ spi=spi,
2451
+ data=data,
2452
+ )
2453
+
2454
+ def _make_opt_mesg_id(self, type: 'Enum_Option', option: 'Optional[Data_MesgIDOption]' = None, *,
2455
+ timestamp: 'Optional[NTPTimestamp]' = None,
2456
+ interval: 'Optional[dt_type]' = None,
2457
+ **kwargs: 'Any') -> 'Schema_MesgIDOption':
2458
+ """Make MH mobility message replay protection option.
2459
+
2460
+ Args:
2461
+ type: Option type.
2462
+ option: Option data model.
2463
+ timestamp: NTP timestamp, c.f., :rfc:`1305`.
2464
+ interval: Timestamp interval (since UNIX-epoch).
2465
+ **kwargs: Arbitrary keyword arguments.
2466
+
2467
+ Returns:
2468
+ Constructed option schema.
2469
+
2470
+ """
2471
+ if option is not None:
2472
+ timestamp = option.ntp_timestamp
2473
+
2474
+ if timestamp is None:
2475
+ interval = interval or datetime.datetime.now(datetime.timezone.utc)
2476
+
2477
+ int_ts = interval.timestamp()
2478
+ ts_sec = math.floor(int_ts)
2479
+ ts_frc = math.ceil(((int_ts - ts_sec) * 1_000_000)) * 2**32
2480
+
2481
+ timestamp = NTPTimestamp(seconds=ts_sec + 2_208_988_800, # 70 years
2482
+ fraction=ts_frc)
2483
+
2484
+ return Schema_MesgIDOption(
2485
+ type=type,
2486
+ length=8,
2487
+ seconds=timestamp.seconds,
2488
+ fraction=timestamp.fraction,
2489
+ )
2490
+
2491
+ def _make_opt_cga_pr(self, type: 'Enum_Option', option: 'Optional[Data_CGAParametersRequestOption]' = None,
2492
+ **kwargs: 'Any') -> 'Schema_CGAParametersRequestOption':
2493
+ """Make MH CGA parameters request option.
2494
+
2495
+ Args:
2496
+ type: Option type.
2497
+ option: Option data model.
2498
+ **kwargs: Arbitrary keyword arguments.
2499
+
2500
+ Returns:
2501
+ Constructed option schema.
2502
+
2503
+ """
2504
+ return Schema_CGAParametersRequestOption(
2505
+ type=type,
2506
+ length=0,
2507
+ )
2508
+
2509
+ def _make_opt_cga_param(self, type: 'Enum_Option', option: 'Optional[Data_CGAParametersOption]' = None, *,
2510
+ parameters: 'Optional[list[Schema_CGAParameter | Data_CGAParameter | dict[str, Any] | bytes]]' = None,
2511
+ **kwargs: 'Any') -> 'Schema_CGAParametersOption':
2512
+ """Make MH CGA paramters option.
2513
+
2514
+ Args:
2515
+ type: Option type.
2516
+ option: Option data model.
2517
+ parameters: CGA parameters.
2518
+ **kwargs: Arbitrary keyword arguments.
2519
+
2520
+ Returns:
2521
+ Constructed option schema.
2522
+
2523
+ """
2524
+ if option is not None:
2525
+ parameters = cast('list[Data_CGAParameter]', option.parameters) # type: ignore[assignment]
2526
+
2527
+ if parameters is None:
2528
+ parameters = []
2529
+
2530
+ param = [] # type: list[Schema_CGAParameter | bytes]
2531
+ length = 0
2532
+ for data in parameters:
2533
+ if isinstance(data, bytes):
2534
+ length += len(data)
2535
+ param.append(data)
2536
+ elif isinstance(data, Schema_CGAParameter):
2537
+ length += len(data)
2538
+ param.append(data)
2539
+ elif isinstance(data, Data_CGAParameter):
2540
+ ext, _ = self._make_cga_extensions(data.extensions)
2541
+ schema = Schema_CGAParameter(
2542
+ modifier=data.modifier,
2543
+ prefix=data.prefix,
2544
+ collision_count=data.collision_count,
2545
+ public_key=data.public_key,
2546
+ extensions=ext,
2547
+ )
2548
+
2549
+ length += len(schema)
2550
+ param.append(schema)
2551
+ else:
2552
+ raise ProtocolError(f'{self.alias}: [OptNo {type}] unknown CGA parameter format: {data}')
2553
+
2554
+ return Schema_CGAParametersOption(
2555
+ type=type,
2556
+ length=length,
2557
+ parameters=param,
2558
+ )
2559
+
2560
+ def _make_opt_signature(self, type: 'Enum_Option', option: 'Optional[Data_SignatureOption]' = None, *,
2561
+ signature: 'bytes' = b'',
2562
+ **kwargs: 'Any') -> 'Schema_SignatureOption':
2563
+ """Make MH signature option.
2564
+
2565
+ Args:
2566
+ type: Option type.
2567
+ option: Option data model.
2568
+ signature: Signature data.
2569
+ **kwargs: Arbitrary keyword arguments.
2570
+
2571
+ Returns:
2572
+ Constructed option schema.
2573
+
2574
+ """
2575
+ if option is not None:
2576
+ signature = option.signature
2577
+
2578
+ return Schema_SignatureOption(
2579
+ type=type,
2580
+ length=len(signature),
2581
+ signature=signature,
2582
+ )
2583
+
2584
+ def _make_opt_phkt(self, type: 'Enum_Option', option: 'Optional[Data_PermanentHomeKeygenTokenOption]' = None, *,
2585
+ token: 'bytes' = b'',
2586
+ **kwargs: 'Any') -> 'Schema_PermanentHomeKeygenTokenOption':
2587
+ """Make MH permanent home keygen token option.
2588
+
2589
+ Args:
2590
+ type: Option type.
2591
+ option: Option data model.
2592
+ token: Token data.
2593
+ **kwargs: Arbitrary keyword arguments.
2594
+
2595
+ Returns:
2596
+ Constructed option schema.
2597
+
2598
+ """
2599
+ if option is not None:
2600
+ token = option.token
2601
+
2602
+ return Schema_PermanentHomeKeygenTokenOption(
2603
+ type=type,
2604
+ length=len(token),
2605
+ token=token,
2606
+ )
2607
+
2608
+ def _make_opt_ct_init(self, type: 'Enum_Option', option: 'Optional[Data_CareofTestInitOption]' = None,
2609
+ **kwargs: 'Any') -> 'Schema_CareofTestInitOption':
2610
+ """Make MH Care-of Test Init option.
2611
+
2612
+ Args:
2613
+ type: Option type.
2614
+ option: Option data model.
2615
+ **kwargs: Arbitrary keyword arguments.
2616
+
2617
+ Returns:
2618
+ Constructed option schema.
2619
+
2620
+ """
2621
+ return Schema_CareofTestInitOption(
2622
+ type=type,
2623
+ length=0,
2624
+ )
2625
+
2626
+ def _make_opt_ct(self, type: 'Enum_Option', option: 'Optional[Data_CareofTestOption]' = None,
2627
+ token: 'bytes' = b'\x00\x00\x00\x00\x00\x00\x00\x00',
2628
+ **kwargs: 'Any') -> 'Schema_CareofTestOption':
2629
+ """Make MH Care-of Test option.
2630
+
2631
+ Args:
2632
+ type: Option type.
2633
+ option: Option data model.
2634
+ token: Care-of keygen token.
2635
+ **kwargs: Arbitrary keyword arguments.
2636
+
2637
+ Returns:
2638
+ Constructed option schema.
2639
+
2640
+ """
2641
+ if option is not None:
2642
+ token = option.token
2643
+
2644
+ return Schema_CareofTestOption(
2645
+ type=type,
2646
+ length=8,
2647
+ token=token,
2648
+ )
2649
+
2650
+ # TODO: Implement other options.
2651
+
2652
+ def _make_cga_extensions(self, extensions: 'Extension | list[Schema_CGAExtension | tuple[Enum_CGAExtension, dict[str, Any]] | bytes]') -> 'tuple[list[Schema_CGAExtension | bytes], int]':
2653
+ """Make CGA extensions for MH.
2654
+
2655
+ Args:
2656
+ extensions: CGA extensions.
2657
+
2658
+ Returns:
2659
+ Tuple of extensions and total length of extensions.
2660
+
2661
+ """
2662
+ total_length = 0
2663
+ if isinstance(extensions, list):
2664
+ extensions_list = [] # type: list[Schema_CGAExtension | bytes]
2665
+ for schema in extensions:
2666
+ if isinstance(schema, bytes):
2667
+ code = Enum_CGAExtension.get(int.from_bytes(schema[0:2], 'big', signed=False))
2668
+
2669
+ data = schema # type: Schema_CGAExtension | bytes
2670
+ data_len = len(data)
2671
+ elif isinstance(schema, Schema):
2672
+ data = schema
2673
+ data_len = len(schema.pack())
2674
+ else:
2675
+ code, args = cast('tuple[Enum_CGAExtension, dict[str, Any]]', schema)
2676
+ name = self.__extension__[code]
2677
+ if isinstance(name, str):
2678
+ meth_name = f'_make_ext_{name}'
2679
+ meth = cast('ExtensionConstructor',
2680
+ getattr(self, meth_name, self._make_ext_none))
2681
+ else:
2682
+ meth = name[1]
2683
+
2684
+ data = meth(code, **args)
2685
+ data_len = len(data.pack())
2686
+
2687
+ extensions_list.append(data)
2688
+ total_length += data_len
2689
+ return extensions_list, total_length
2690
+
2691
+ extensions_list = []
2692
+ for code, extension in extensions.items(multi=True):
2693
+ name = self.__extension__[code]
2694
+ if isinstance(name, str):
2695
+ meth_name = f'_make_ext_{name}'
2696
+ meth = cast('ExtensionConstructor',
2697
+ getattr(self, meth_name, self._make_ext_none))
2698
+ else:
2699
+ meth = name[1]
2700
+
2701
+ data = meth(code, extension)
2702
+ data_len = len(data.pack())
2703
+
2704
+ extensions_list.append(data)
2705
+ total_length += data_len
2706
+ return extensions_list, total_length
2707
+
2708
+ def _make_ext_none(self, type: 'Enum_CGAExtension', option: 'Optional[Data_UnknownExtension]' = None, *,
2709
+ data: 'bytes' = b'',
2710
+ **kwargs: 'Any') -> 'Schema_UnknownExtension':
2711
+ """Make CGA extension.
2712
+
2713
+ Args:
2714
+ type: Extension type.
2715
+ option: Extension data model.
2716
+ data: Extension data.
2717
+ **kwargs: Arbitrary keyword arguments.
2718
+
2719
+ Returns:
2720
+ Constructed extension schema.
2721
+
2722
+ """
2723
+ if option is not None:
2724
+ data = option.data
2725
+
2726
+ return Schema_UnknownExtension(
2727
+ type=type,
2728
+ length=len(data),
2729
+ data=data,
2730
+ )
2731
+
2732
+ def _make_ext_multiprefix(self, type: 'Enum_CGAExtension', option: 'Optional[Data_MultiPrefixExtension]' = None, *,
2733
+ flag: 'bool' = False,
2734
+ prefixes: 'Optional[list[int]]' = None,
2735
+ **kwargs: 'Any') -> 'Schema_MultiPrefixExtension':
2736
+ """Make CGA multi-prefix extension.
2737
+
2738
+ Args:
2739
+ type: Extension type.
2740
+ option: Extension data model.
2741
+ flag: Public key flag.
2742
+ prefixes: Prefixes.
2743
+ **kwargs: Arbitrary keyword arguments.
2744
+
2745
+ Returns:
2746
+ Constructed extension schema.
2747
+
2748
+ """
2749
+ if option is not None:
2750
+ flag = option.flag
2751
+ prefixes = cast('list[int]', option.prefixes)
2752
+ else:
2753
+ prefixes = prefixes or []
2754
+
2755
+ return Schema_MultiPrefixExtension(
2756
+ type=type,
2757
+ length=1 + len(prefixes) * 16,
2758
+ flags={
2759
+ 'P': int(flag),
2760
+ },
2761
+ prefixes=prefixes,
2762
+ )
2763
+
2764
+ # TODO: Implement other CGA extensions.