pypcapkit 1.3.5.post6__cp313-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (466) hide show
  1. pcapkit/__init__.py +124 -0
  2. pcapkit/__main__.py +138 -0
  3. pcapkit/all.py +136 -0
  4. pcapkit/const/__init__.py +81 -0
  5. pcapkit/const/arp/__init__.py +25 -0
  6. pcapkit/const/arp/hardware.py +181 -0
  7. pcapkit/const/arp/operation.py +131 -0
  8. pcapkit/const/ftp/__init__.py +25 -0
  9. pcapkit/const/ftp/command.py +309 -0
  10. pcapkit/const/ftp/return_code.py +304 -0
  11. pcapkit/const/hip/__init__.py +94 -0
  12. pcapkit/const/hip/certificate.py +77 -0
  13. pcapkit/const/hip/cipher.py +65 -0
  14. pcapkit/const/hip/di.py +59 -0
  15. pcapkit/const/hip/ecdsa_curve.py +59 -0
  16. pcapkit/const/hip/ecdsa_low_curve.py +56 -0
  17. pcapkit/const/hip/eddsa_curve.py +65 -0
  18. pcapkit/const/hip/esp_transform_suite.py +98 -0
  19. pcapkit/const/hip/group.py +86 -0
  20. pcapkit/const/hip/hi_algorithm.py +86 -0
  21. pcapkit/const/hip/hit_suite.py +68 -0
  22. pcapkit/const/hip/nat_traversal.py +62 -0
  23. pcapkit/const/hip/notify_message.py +200 -0
  24. pcapkit/const/hip/packet.py +89 -0
  25. pcapkit/const/hip/parameter.py +377 -0
  26. pcapkit/const/hip/registration.py +68 -0
  27. pcapkit/const/hip/registration_failure.py +84 -0
  28. pcapkit/const/hip/suite.py +71 -0
  29. pcapkit/const/hip/transport.py +59 -0
  30. pcapkit/const/http/__init__.py +39 -0
  31. pcapkit/const/http/error_code.py +95 -0
  32. pcapkit/const/http/frame.py +95 -0
  33. pcapkit/const/http/method.py +184 -0
  34. pcapkit/const/http/setting.py +96 -0
  35. pcapkit/const/http/status_code.py +298 -0
  36. pcapkit/const/ipv4/__init__.py +57 -0
  37. pcapkit/const/ipv4/classification_level.py +64 -0
  38. pcapkit/const/ipv4/option_class.py +55 -0
  39. pcapkit/const/ipv4/option_number.py +137 -0
  40. pcapkit/const/ipv4/protection_authority.py +63 -0
  41. pcapkit/const/ipv4/qs_function.py +51 -0
  42. pcapkit/const/ipv4/router_alert.py +251 -0
  43. pcapkit/const/ipv4/tos_del.py +51 -0
  44. pcapkit/const/ipv4/tos_ecn.py +55 -0
  45. pcapkit/const/ipv4/tos_pre.py +63 -0
  46. pcapkit/const/ipv4/tos_rel.py +51 -0
  47. pcapkit/const/ipv4/tos_thr.py +51 -0
  48. pcapkit/const/ipv4/ts_flag.py +53 -0
  49. pcapkit/const/ipv6/__init__.py +53 -0
  50. pcapkit/const/ipv6/extension_header.py +69 -0
  51. pcapkit/const/ipv6/option.py +137 -0
  52. pcapkit/const/ipv6/option_action.py +55 -0
  53. pcapkit/const/ipv6/qs_function.py +51 -0
  54. pcapkit/const/ipv6/router_alert.py +266 -0
  55. pcapkit/const/ipv6/routing.py +80 -0
  56. pcapkit/const/ipv6/seed_id.py +55 -0
  57. pcapkit/const/ipv6/smf_dpd_mode.py +51 -0
  58. pcapkit/const/ipv6/tagger_id.py +62 -0
  59. pcapkit/const/ipx/__init__.py +27 -0
  60. pcapkit/const/ipx/packet.py +72 -0
  61. pcapkit/const/ipx/socket.py +104 -0
  62. pcapkit/const/l2tp/__init__.py +21 -0
  63. pcapkit/const/l2tp/type.py +51 -0
  64. pcapkit/const/mh/__init__.py +204 -0
  65. pcapkit/const/mh/access_type.py +92 -0
  66. pcapkit/const/mh/ack_status_code.py +71 -0
  67. pcapkit/const/mh/ani_suboption.py +74 -0
  68. pcapkit/const/mh/auth_subtype.py +53 -0
  69. pcapkit/const/mh/binding_ack_flag.py +66 -0
  70. pcapkit/const/mh/binding_error.py +51 -0
  71. pcapkit/const/mh/binding_revocation.py +59 -0
  72. pcapkit/const/mh/binding_update_flag.py +81 -0
  73. pcapkit/const/mh/cga_extension.py +66 -0
  74. pcapkit/const/mh/cga_sec.py +57 -0
  75. pcapkit/const/mh/cga_type.py +68 -0
  76. pcapkit/const/mh/dhcp_support_mode.py +53 -0
  77. pcapkit/const/mh/dns_status_code.py +65 -0
  78. pcapkit/const/mh/dsmip6_tls_packet.py +62 -0
  79. pcapkit/const/mh/dsmipv6_home_address.py +74 -0
  80. pcapkit/const/mh/enumerating_algorithm.py +56 -0
  81. pcapkit/const/mh/fb_ack_status.py +62 -0
  82. pcapkit/const/mh/fb_action.py +71 -0
  83. pcapkit/const/mh/fb_indication_trigger.py +65 -0
  84. pcapkit/const/mh/fb_type.py +59 -0
  85. pcapkit/const/mh/flow_id_status.py +77 -0
  86. pcapkit/const/mh/flow_id_suboption.py +71 -0
  87. pcapkit/const/mh/handoff_type.py +71 -0
  88. pcapkit/const/mh/handover_ack_flag.py +54 -0
  89. pcapkit/const/mh/handover_ack_status.py +92 -0
  90. pcapkit/const/mh/handover_initiate_flag.py +57 -0
  91. pcapkit/const/mh/handover_initiate_status.py +62 -0
  92. pcapkit/const/mh/home_address_reply.py +71 -0
  93. pcapkit/const/mh/lla_code.py +63 -0
  94. pcapkit/const/mh/lma_mag_suboption.py +59 -0
  95. pcapkit/const/mh/mn_group_id.py +59 -0
  96. pcapkit/const/mh/mn_id_subtype.py +77 -0
  97. pcapkit/const/mh/operator_id.py +63 -0
  98. pcapkit/const/mh/option.py +260 -0
  99. pcapkit/const/mh/packet.py +119 -0
  100. pcapkit/const/mh/qos_attribute.py +89 -0
  101. pcapkit/const/mh/revocation_status_code.py +83 -0
  102. pcapkit/const/mh/revocation_trigger.py +86 -0
  103. pcapkit/const/mh/status_code.py +232 -0
  104. pcapkit/const/mh/traffic_selector.py +62 -0
  105. pcapkit/const/mh/upa_status.py +71 -0
  106. pcapkit/const/mh/upn_reason.py +80 -0
  107. pcapkit/const/ospf/__init__.py +27 -0
  108. pcapkit/const/ospf/authentication.py +65 -0
  109. pcapkit/const/ospf/packet.py +71 -0
  110. pcapkit/const/pcapng/__init__.py +51 -0
  111. pcapkit/const/pcapng/block_type.py +152 -0
  112. pcapkit/const/pcapng/filter_type.py +48 -0
  113. pcapkit/const/pcapng/hash_algorithm.py +59 -0
  114. pcapkit/const/pcapng/option_type.py +233 -0
  115. pcapkit/const/pcapng/record_type.py +57 -0
  116. pcapkit/const/pcapng/secrets_type.py +56 -0
  117. pcapkit/const/pcapng/verdict_type.py +53 -0
  118. pcapkit/const/reg/__init__.py +34 -0
  119. pcapkit/const/reg/apptype.py +32728 -0
  120. pcapkit/const/reg/ethertype.py +714 -0
  121. pcapkit/const/reg/linktype.py +890 -0
  122. pcapkit/const/reg/transtype.py +526 -0
  123. pcapkit/const/tcp/__init__.py +35 -0
  124. pcapkit/const/tcp/checksum.py +55 -0
  125. pcapkit/const/tcp/flags.py +73 -0
  126. pcapkit/const/tcp/mp_tcp_option.py +80 -0
  127. pcapkit/const/tcp/option.py +198 -0
  128. pcapkit/const/vlan/__init__.py +23 -0
  129. pcapkit/const/vlan/priority_level.py +71 -0
  130. pcapkit/corekit/__init__.py +59 -0
  131. pcapkit/corekit/fields/__init__.py +45 -0
  132. pcapkit/corekit/fields/collections.py +282 -0
  133. pcapkit/corekit/fields/field.py +269 -0
  134. pcapkit/corekit/fields/ipaddress.py +274 -0
  135. pcapkit/corekit/fields/misc.py +722 -0
  136. pcapkit/corekit/fields/numbers.py +375 -0
  137. pcapkit/corekit/fields/strings.py +245 -0
  138. pcapkit/corekit/infoclass.py +394 -0
  139. pcapkit/corekit/io.py +506 -0
  140. pcapkit/corekit/module.py +39 -0
  141. pcapkit/corekit/multidict.py +626 -0
  142. pcapkit/corekit/protochain.py +263 -0
  143. pcapkit/corekit/version.py +33 -0
  144. pcapkit/dumpkit/__init__.py +15 -0
  145. pcapkit/dumpkit/common.py +199 -0
  146. pcapkit/dumpkit/null.py +77 -0
  147. pcapkit/dumpkit/pcap.py +144 -0
  148. pcapkit/foundation/__init__.py +45 -0
  149. pcapkit/foundation/engines/__init__.py +36 -0
  150. pcapkit/foundation/engines/dpkt.py +230 -0
  151. pcapkit/foundation/engines/engine.py +194 -0
  152. pcapkit/foundation/engines/pcap.py +188 -0
  153. pcapkit/foundation/engines/pcapng.py +310 -0
  154. pcapkit/foundation/engines/pyshark.py +166 -0
  155. pcapkit/foundation/engines/scapy.py +161 -0
  156. pcapkit/foundation/extraction.py +915 -0
  157. pcapkit/foundation/reassembly/__init__.py +49 -0
  158. pcapkit/foundation/reassembly/data/__init__.py +48 -0
  159. pcapkit/foundation/reassembly/data/ip.py +117 -0
  160. pcapkit/foundation/reassembly/data/tcp.py +145 -0
  161. pcapkit/foundation/reassembly/ip.py +192 -0
  162. pcapkit/foundation/reassembly/ipv4.py +50 -0
  163. pcapkit/foundation/reassembly/ipv6.py +50 -0
  164. pcapkit/foundation/reassembly/reassembly.py +389 -0
  165. pcapkit/foundation/reassembly/tcp.py +249 -0
  166. pcapkit/foundation/registry/__init__.py +41 -0
  167. pcapkit/foundation/registry/foundation.py +327 -0
  168. pcapkit/foundation/registry/protocols.py +885 -0
  169. pcapkit/foundation/traceflow/__init__.py +44 -0
  170. pcapkit/foundation/traceflow/data/__init__.py +30 -0
  171. pcapkit/foundation/traceflow/data/tcp.py +105 -0
  172. pcapkit/foundation/traceflow/tcp.py +159 -0
  173. pcapkit/foundation/traceflow/traceflow.py +390 -0
  174. pcapkit/interface/__init__.py +22 -0
  175. pcapkit/interface/core.py +185 -0
  176. pcapkit/interface/misc.py +120 -0
  177. pcapkit/protocols/__init__.py +85 -0
  178. pcapkit/protocols/application/NotImplemented/bgp.py +0 -0
  179. pcapkit/protocols/application/NotImplemented/dhcp.py +0 -0
  180. pcapkit/protocols/application/NotImplemented/dhcpv6.py +0 -0
  181. pcapkit/protocols/application/NotImplemented/dns.py +0 -0
  182. pcapkit/protocols/application/NotImplemented/imap.py +0 -0
  183. pcapkit/protocols/application/NotImplemented/ldap.py +0 -0
  184. pcapkit/protocols/application/NotImplemented/mqtt.py +0 -0
  185. pcapkit/protocols/application/NotImplemented/nntp.py +0 -0
  186. pcapkit/protocols/application/NotImplemented/ntp.py +0 -0
  187. pcapkit/protocols/application/NotImplemented/onc_rpc.py +0 -0
  188. pcapkit/protocols/application/NotImplemented/pop.py +0 -0
  189. pcapkit/protocols/application/NotImplemented/rip.py +0 -0
  190. pcapkit/protocols/application/NotImplemented/rtp.py +0 -0
  191. pcapkit/protocols/application/NotImplemented/sip.py +0 -0
  192. pcapkit/protocols/application/NotImplemented/smtp.py +0 -0
  193. pcapkit/protocols/application/NotImplemented/snmp.py +0 -0
  194. pcapkit/protocols/application/NotImplemented/ssh.py +0 -0
  195. pcapkit/protocols/application/NotImplemented/telnet.py +0 -0
  196. pcapkit/protocols/application/NotImplemented/tls.py +0 -0
  197. pcapkit/protocols/application/NotImplemented/xmpp.py +0 -0
  198. pcapkit/protocols/application/__init__.py +34 -0
  199. pcapkit/protocols/application/application.py +114 -0
  200. pcapkit/protocols/application/ftp.py +206 -0
  201. pcapkit/protocols/application/http.py +176 -0
  202. pcapkit/protocols/application/httpv1.py +320 -0
  203. pcapkit/protocols/application/httpv2.py +1255 -0
  204. pcapkit/protocols/data/__init__.py +192 -0
  205. pcapkit/protocols/data/application/__init__.py +57 -0
  206. pcapkit/protocols/data/application/ftp.py +59 -0
  207. pcapkit/protocols/data/application/httpv1.py +79 -0
  208. pcapkit/protocols/data/application/httpv2.py +293 -0
  209. pcapkit/protocols/data/data.py +25 -0
  210. pcapkit/protocols/data/internet/__init__.py +298 -0
  211. pcapkit/protocols/data/internet/ah.py +31 -0
  212. pcapkit/protocols/data/internet/hip.py +804 -0
  213. pcapkit/protocols/data/internet/hopopt.py +351 -0
  214. pcapkit/protocols/data/internet/ipv4.py +369 -0
  215. pcapkit/protocols/data/internet/ipv6.py +67 -0
  216. pcapkit/protocols/data/internet/ipv6_frag.py +29 -0
  217. pcapkit/protocols/data/internet/ipv6_opts.py +368 -0
  218. pcapkit/protocols/data/internet/ipv6_route.py +86 -0
  219. pcapkit/protocols/data/internet/ipx.py +56 -0
  220. pcapkit/protocols/data/internet/mh.py +509 -0
  221. pcapkit/protocols/data/link/__init__.py +33 -0
  222. pcapkit/protocols/data/link/arp.py +74 -0
  223. pcapkit/protocols/data/link/ethernet.py +28 -0
  224. pcapkit/protocols/data/link/l2tp.py +63 -0
  225. pcapkit/protocols/data/link/ospf.py +58 -0
  226. pcapkit/protocols/data/link/vlan.py +42 -0
  227. pcapkit/protocols/data/misc/__init__.py +109 -0
  228. pcapkit/protocols/data/misc/null.py +18 -0
  229. pcapkit/protocols/data/misc/pcap/__init__.py +18 -0
  230. pcapkit/protocols/data/misc/pcap/frame.py +56 -0
  231. pcapkit/protocols/data/misc/pcap/header.py +53 -0
  232. pcapkit/protocols/data/misc/pcapng.py +925 -0
  233. pcapkit/protocols/data/misc/raw.py +25 -0
  234. pcapkit/protocols/data/protocol.py +32 -0
  235. pcapkit/protocols/data/transport/__init__.py +71 -0
  236. pcapkit/protocols/data/transport/tcp.py +555 -0
  237. pcapkit/protocols/data/transport/udp.py +29 -0
  238. pcapkit/protocols/internet/NotImplemented/ecn.py +0 -0
  239. pcapkit/protocols/internet/NotImplemented/esp.py +97 -0
  240. pcapkit/protocols/internet/NotImplemented/icmp.py +0 -0
  241. pcapkit/protocols/internet/NotImplemented/icmpv6.py +0 -0
  242. pcapkit/protocols/internet/NotImplemented/igmp.py +0 -0
  243. pcapkit/protocols/internet/NotImplemented/shim6.py +0 -0
  244. pcapkit/protocols/internet/__init__.py +43 -0
  245. pcapkit/protocols/internet/ah.py +275 -0
  246. pcapkit/protocols/internet/hip.py +4727 -0
  247. pcapkit/protocols/internet/hopopt.py +1879 -0
  248. pcapkit/protocols/internet/internet.py +249 -0
  249. pcapkit/protocols/internet/ip.py +51 -0
  250. pcapkit/protocols/internet/ipsec.py +50 -0
  251. pcapkit/protocols/internet/ipv4.py +1782 -0
  252. pcapkit/protocols/internet/ipv6.py +412 -0
  253. pcapkit/protocols/internet/ipv6_frag.py +258 -0
  254. pcapkit/protocols/internet/ipv6_opts.py +1890 -0
  255. pcapkit/protocols/internet/ipv6_route.py +708 -0
  256. pcapkit/protocols/internet/ipx.py +230 -0
  257. pcapkit/protocols/internet/mh.py +2764 -0
  258. pcapkit/protocols/link/NotImplemented/dsl.py +0 -0
  259. pcapkit/protocols/link/NotImplemented/eapol.py +1 -0
  260. pcapkit/protocols/link/NotImplemented/fddi.py +0 -0
  261. pcapkit/protocols/link/NotImplemented/isdn.py +0 -0
  262. pcapkit/protocols/link/NotImplemented/ndp.py +0 -0
  263. pcapkit/protocols/link/NotImplemented/ppp.py +0 -0
  264. pcapkit/protocols/link/__init__.py +35 -0
  265. pcapkit/protocols/link/arp.py +421 -0
  266. pcapkit/protocols/link/ethernet.py +248 -0
  267. pcapkit/protocols/link/l2tp.py +267 -0
  268. pcapkit/protocols/link/link.py +140 -0
  269. pcapkit/protocols/link/ospf.py +342 -0
  270. pcapkit/protocols/link/rarp.py +82 -0
  271. pcapkit/protocols/link/vlan.py +225 -0
  272. pcapkit/protocols/misc/__init__.py +37 -0
  273. pcapkit/protocols/misc/null.py +129 -0
  274. pcapkit/protocols/misc/pcap/__init__.py +17 -0
  275. pcapkit/protocols/misc/pcap/frame.py +478 -0
  276. pcapkit/protocols/misc/pcap/header.py +358 -0
  277. pcapkit/protocols/misc/pcapng.py +5520 -0
  278. pcapkit/protocols/misc/raw.py +180 -0
  279. pcapkit/protocols/protocol.py +1216 -0
  280. pcapkit/protocols/schema/__init__.py +140 -0
  281. pcapkit/protocols/schema/application/__init__.py +40 -0
  282. pcapkit/protocols/schema/application/ftp.py +21 -0
  283. pcapkit/protocols/schema/application/httpv1.py +21 -0
  284. pcapkit/protocols/schema/application/httpv2.py +384 -0
  285. pcapkit/protocols/schema/internet/__init__.py +294 -0
  286. pcapkit/protocols/schema/internet/ah.py +40 -0
  287. pcapkit/protocols/schema/internet/hip.py +1184 -0
  288. pcapkit/protocols/schema/internet/hopopt.py +679 -0
  289. pcapkit/protocols/schema/internet/ipv4.py +576 -0
  290. pcapkit/protocols/schema/internet/ipv6.py +63 -0
  291. pcapkit/protocols/schema/internet/ipv6_frag.py +48 -0
  292. pcapkit/protocols/schema/internet/ipv6_opts.py +680 -0
  293. pcapkit/protocols/schema/internet/ipv6_route.py +197 -0
  294. pcapkit/protocols/schema/internet/ipx.py +40 -0
  295. pcapkit/protocols/schema/internet/mh.py +718 -0
  296. pcapkit/protocols/schema/link/__init__.py +19 -0
  297. pcapkit/protocols/schema/link/arp.py +39 -0
  298. pcapkit/protocols/schema/link/ethernet.py +51 -0
  299. pcapkit/protocols/schema/link/l2tp.py +88 -0
  300. pcapkit/protocols/schema/link/ospf.py +90 -0
  301. pcapkit/protocols/schema/link/vlan.py +69 -0
  302. pcapkit/protocols/schema/misc/__init__.py +108 -0
  303. pcapkit/protocols/schema/misc/null.py +18 -0
  304. pcapkit/protocols/schema/misc/pcap/__init__.py +10 -0
  305. pcapkit/protocols/schema/misc/pcap/frame.py +51 -0
  306. pcapkit/protocols/schema/misc/pcap/header.py +63 -0
  307. pcapkit/protocols/schema/misc/pcapng.py +1689 -0
  308. pcapkit/protocols/schema/misc/raw.py +24 -0
  309. pcapkit/protocols/schema/schema.py +809 -0
  310. pcapkit/protocols/schema/transport/__init__.py +69 -0
  311. pcapkit/protocols/schema/transport/tcp.py +928 -0
  312. pcapkit/protocols/schema/transport/udp.py +90 -0
  313. pcapkit/protocols/transport/NotImplemented/dccp.py +0 -0
  314. pcapkit/protocols/transport/NotImplemented/rsvp.py +0 -0
  315. pcapkit/protocols/transport/NotImplemented/sctp.py +0 -0
  316. pcapkit/protocols/transport/__init__.py +27 -0
  317. pcapkit/protocols/transport/tcp.py +3025 -0
  318. pcapkit/protocols/transport/transport.py +158 -0
  319. pcapkit/protocols/transport/udp.py +214 -0
  320. pcapkit/py.typed +0 -0
  321. pcapkit/toolkit/__init__.py +57 -0
  322. pcapkit/toolkit/dpkt.py +306 -0
  323. pcapkit/toolkit/pcap.py +212 -0
  324. pcapkit/toolkit/pcapng.py +251 -0
  325. pcapkit/toolkit/pyshark.py +99 -0
  326. pcapkit/toolkit/scapy.py +297 -0
  327. pcapkit/utilities/__init__.py +20 -0
  328. pcapkit/utilities/compat.py +196 -0
  329. pcapkit/utilities/decorators.py +197 -0
  330. pcapkit/utilities/exceptions.py +365 -0
  331. pcapkit/utilities/logging.py +55 -0
  332. pcapkit/utilities/warnings.py +185 -0
  333. pcapkit/vendor/__init__.py +105 -0
  334. pcapkit/vendor/__main__.py +92 -0
  335. pcapkit/vendor/arp/__init__.py +27 -0
  336. pcapkit/vendor/arp/hardware.py +29 -0
  337. pcapkit/vendor/arp/operation.py +29 -0
  338. pcapkit/vendor/default.py +474 -0
  339. pcapkit/vendor/ftp/__init__.py +27 -0
  340. pcapkit/vendor/ftp/command.py +244 -0
  341. pcapkit/vendor/ftp/return_code.py +256 -0
  342. pcapkit/vendor/hip/__init__.py +94 -0
  343. pcapkit/vendor/hip/certificate.py +29 -0
  344. pcapkit/vendor/hip/cipher.py +29 -0
  345. pcapkit/vendor/hip/di.py +29 -0
  346. pcapkit/vendor/hip/ecdsa_curve.py +29 -0
  347. pcapkit/vendor/hip/ecdsa_low_curve.py +29 -0
  348. pcapkit/vendor/hip/eddsa_curve.py +85 -0
  349. pcapkit/vendor/hip/esp_transform_suite.py +29 -0
  350. pcapkit/vendor/hip/group.py +87 -0
  351. pcapkit/vendor/hip/hi_algorithm.py +29 -0
  352. pcapkit/vendor/hip/hit_suite.py +29 -0
  353. pcapkit/vendor/hip/nat_traversal.py +29 -0
  354. pcapkit/vendor/hip/notify_message.py +29 -0
  355. pcapkit/vendor/hip/packet.py +88 -0
  356. pcapkit/vendor/hip/parameter.py +88 -0
  357. pcapkit/vendor/hip/registration.py +29 -0
  358. pcapkit/vendor/hip/registration_failure.py +29 -0
  359. pcapkit/vendor/hip/suite.py +29 -0
  360. pcapkit/vendor/hip/transport.py +29 -0
  361. pcapkit/vendor/http/__init__.py +39 -0
  362. pcapkit/vendor/http/error_code.py +95 -0
  363. pcapkit/vendor/http/frame.py +91 -0
  364. pcapkit/vendor/http/method.py +167 -0
  365. pcapkit/vendor/http/setting.py +93 -0
  366. pcapkit/vendor/http/status_code.py +185 -0
  367. pcapkit/vendor/ipv4/__init__.py +57 -0
  368. pcapkit/vendor/ipv4/classification_level.py +91 -0
  369. pcapkit/vendor/ipv4/option_class.py +80 -0
  370. pcapkit/vendor/ipv4/option_number.py +105 -0
  371. pcapkit/vendor/ipv4/protection_authority.py +84 -0
  372. pcapkit/vendor/ipv4/qs_function.py +78 -0
  373. pcapkit/vendor/ipv4/router_alert.py +93 -0
  374. pcapkit/vendor/ipv4/tos_del.py +78 -0
  375. pcapkit/vendor/ipv4/tos_ecn.py +95 -0
  376. pcapkit/vendor/ipv4/tos_pre.py +84 -0
  377. pcapkit/vendor/ipv4/tos_rel.py +78 -0
  378. pcapkit/vendor/ipv4/tos_thr.py +77 -0
  379. pcapkit/vendor/ipv4/ts_flag.py +79 -0
  380. pcapkit/vendor/ipv6/__init__.py +53 -0
  381. pcapkit/vendor/ipv6/extension_header.py +171 -0
  382. pcapkit/vendor/ipv6/option.py +104 -0
  383. pcapkit/vendor/ipv6/option_action.py +90 -0
  384. pcapkit/vendor/ipv6/qs_function.py +78 -0
  385. pcapkit/vendor/ipv6/router_alert.py +93 -0
  386. pcapkit/vendor/ipv6/routing.py +87 -0
  387. pcapkit/vendor/ipv6/seed_id.py +81 -0
  388. pcapkit/vendor/ipv6/smf_dpd_mode.py +78 -0
  389. pcapkit/vendor/ipv6/tagger_id.py +81 -0
  390. pcapkit/vendor/ipx/__init__.py +37 -0
  391. pcapkit/vendor/ipx/packet.py +123 -0
  392. pcapkit/vendor/ipx/socket.py +125 -0
  393. pcapkit/vendor/l2tp/__init__.py +21 -0
  394. pcapkit/vendor/l2tp/type.py +78 -0
  395. pcapkit/vendor/mh/__init__.py +204 -0
  396. pcapkit/vendor/mh/access_type.py +87 -0
  397. pcapkit/vendor/mh/ack_status_code.py +88 -0
  398. pcapkit/vendor/mh/ani_suboption.py +88 -0
  399. pcapkit/vendor/mh/auth_subtype.py +83 -0
  400. pcapkit/vendor/mh/binding_ack_flag.py +148 -0
  401. pcapkit/vendor/mh/binding_error.py +78 -0
  402. pcapkit/vendor/mh/binding_revocation.py +87 -0
  403. pcapkit/vendor/mh/binding_update_flag.py +147 -0
  404. pcapkit/vendor/mh/cga_extension.py +91 -0
  405. pcapkit/vendor/mh/cga_sec.py +91 -0
  406. pcapkit/vendor/mh/cga_type.py +74 -0
  407. pcapkit/vendor/mh/dhcp_support_mode.py +77 -0
  408. pcapkit/vendor/mh/dns_status_code.py +87 -0
  409. pcapkit/vendor/mh/dsmip6_tls_packet.py +87 -0
  410. pcapkit/vendor/mh/dsmipv6_home_address.py +87 -0
  411. pcapkit/vendor/mh/enumerating_algorithm.py +82 -0
  412. pcapkit/vendor/mh/fb_ack_status.py +87 -0
  413. pcapkit/vendor/mh/fb_action.py +88 -0
  414. pcapkit/vendor/mh/fb_indication_trigger.py +87 -0
  415. pcapkit/vendor/mh/fb_type.py +88 -0
  416. pcapkit/vendor/mh/flow_id_status.py +87 -0
  417. pcapkit/vendor/mh/flow_id_suboption.py +87 -0
  418. pcapkit/vendor/mh/handoff_type.py +87 -0
  419. pcapkit/vendor/mh/handover_ack_flag.py +143 -0
  420. pcapkit/vendor/mh/handover_ack_status.py +87 -0
  421. pcapkit/vendor/mh/handover_initiate_flag.py +143 -0
  422. pcapkit/vendor/mh/handover_initiate_status.py +87 -0
  423. pcapkit/vendor/mh/home_address_reply.py +87 -0
  424. pcapkit/vendor/mh/lla_code.py +97 -0
  425. pcapkit/vendor/mh/lma_mag_suboption.py +88 -0
  426. pcapkit/vendor/mh/mn_group_id.py +87 -0
  427. pcapkit/vendor/mh/mn_id_subtype.py +87 -0
  428. pcapkit/vendor/mh/operator_id.py +87 -0
  429. pcapkit/vendor/mh/option.py +83 -0
  430. pcapkit/vendor/mh/packet.py +82 -0
  431. pcapkit/vendor/mh/qos_attribute.py +87 -0
  432. pcapkit/vendor/mh/revocation_status_code.py +87 -0
  433. pcapkit/vendor/mh/revocation_trigger.py +87 -0
  434. pcapkit/vendor/mh/status_code.py +91 -0
  435. pcapkit/vendor/mh/traffic_selector.py +87 -0
  436. pcapkit/vendor/mh/upa_status.py +87 -0
  437. pcapkit/vendor/mh/upn_reason.py +87 -0
  438. pcapkit/vendor/ospf/__init__.py +27 -0
  439. pcapkit/vendor/ospf/authentication.py +29 -0
  440. pcapkit/vendor/ospf/packet.py +29 -0
  441. pcapkit/vendor/pcapng/__init__.py +51 -0
  442. pcapkit/vendor/pcapng/block_type.py +94 -0
  443. pcapkit/vendor/pcapng/filter_type.py +77 -0
  444. pcapkit/vendor/pcapng/hash_algorithm.py +82 -0
  445. pcapkit/vendor/pcapng/option_type.py +287 -0
  446. pcapkit/vendor/pcapng/record_type.py +81 -0
  447. pcapkit/vendor/pcapng/secrets_type.py +81 -0
  448. pcapkit/vendor/pcapng/verdict_type.py +79 -0
  449. pcapkit/vendor/reg/__init__.py +34 -0
  450. pcapkit/vendor/reg/apptype.py +338 -0
  451. pcapkit/vendor/reg/ethertype.py +121 -0
  452. pcapkit/vendor/reg/linktype.py +110 -0
  453. pcapkit/vendor/reg/transtype.py +111 -0
  454. pcapkit/vendor/tcp/__init__.py +35 -0
  455. pcapkit/vendor/tcp/checksum.py +80 -0
  456. pcapkit/vendor/tcp/flags.py +149 -0
  457. pcapkit/vendor/tcp/mp_tcp_option.py +90 -0
  458. pcapkit/vendor/tcp/option.py +103 -0
  459. pcapkit/vendor/vlan/__init__.py +23 -0
  460. pcapkit/vendor/vlan/priority_level.py +97 -0
  461. pypcapkit-1.3.5.post6.dist-info/LICENSE +29 -0
  462. pypcapkit-1.3.5.post6.dist-info/METADATA +238 -0
  463. pypcapkit-1.3.5.post6.dist-info/RECORD +466 -0
  464. pypcapkit-1.3.5.post6.dist-info/WHEEL +5 -0
  465. pypcapkit-1.3.5.post6.dist-info/entry_points.txt +3 -0
  466. pypcapkit-1.3.5.post6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,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.