def _read_opt_smf_dpd(self, code, *, desc): """Read HOPOPT SMF_DPD option. Structure of HOPOPT SMF_DPD option [RFC 5570]: * IPv6 SMF_DPD Option Header in I-DPD mode 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ... |0|0|0| 01000 | Opt. Data Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|TidTy| TidLen| TaggerID (optional) ... | +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | Identifier ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Octets Bits Name Description 0 0 hopopt.smf_dpd.type Option Type 0 0 hopopt.smf_dpd.type.value Option Number 0 0 hopopt.smf_dpd.type.action Action (00) 0 2 hopopt.smf_dpd.type.change Change Flag (0) 1 8 hopopt.smf_dpd.length Length of Option Data 2 16 hopopt.smf_dpd.dpd_type DPD Type (0) 2 17 hopopt.smf_dpd.tid_type TaggerID Type 2 20 hopopt.smf_dpd.tid_len TaggerID Length 3 24 hopopt.smf_dpd.tid TaggerID ? ? hopopt.smf_dpd.id Identifier * IPv6 SMF_DPD Option Header in H-DPD Mode 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ... |0|0|0| OptType | Opt. Data Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| Hash Assist Value (HAV) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Octets Bits Name Description 0 0 hopopt.smf_dpd.type Option Type 0 0 hopopt.smf_dpd.type.value Option Number 0 0 hopopt.smf_dpd.type.action Action (00) 0 2 hopopt.smf_dpd.type.change Change Flag (0) 1 8 hopopt.smf_dpd.length Length of Option Data 2 16 hopopt.smf_dpd.dpd_type DPD Type (1) 2 17 hopopt.smf_dpd.hav Hash Assist Value """ _type = self._read_opt_type(code) _size = self._read_unpack(1) _tidd = self._read_binary(1) if _tidd[0] == '0': _mode = 'I-DPD' _tidt = _TID_TYPE.get(_tidd[1:4], 'Unassigned') _tidl = int(_tidd[4:], base=2) if _tidt == 'NULL': if _tidl != 0: raise ProtocolError(f'{self.alias}: [Optno {code}] invalid format') _iden = self._read_fileng(_size-1) opt = dict( desc=desc, type=_type, length=_size + 2, dpd_type=_mode, tid_type=_tidt, tid_len=_tidl, id=_iden, ) elif _tidt == 'IPv4': if _tidl != 3: raise ProtocolError(f'{self.alias}: [Optno {code}] invalid format') _tidf = self._read_fileng(4) _iden = self._read_fileng(_size-4) opt = dict( desc=desc, type=_type, length=_size + 2, dpd_type=_mode, tid_type=_tidt, tid_len=_tidl, tid=ipaddress.ip_address(_tidf), id=_iden, ) elif _tidt == 'IPv6': if _tidl != 15: raise ProtocolError(f'{self.alias}: [Optno {code}] invalid format') _tidf = self._read_fileng(15) _iden = self._read_fileng(_size-15) opt = dict( desc=desc, type=_type, length=_size + 2, dpd_type=_mode, tid_type=_tidt, tid_len=_tidl, tid=ipaddress.ip_address(_tidf), id=_iden, ) else: _tidf = self._read_unpack(_tidl+1) _iden = self._read_fileng(_size-_tidl-2) opt = dict( desc=desc, type=_type, length=_size + 2, dpd_type=_mode, tid_type=_tidt, tid_len=_tidl, tid=_tidf, id=_iden, ) elif _tidd[0] == '1': _data = self._read_binary(_size-1) opt = dict( desc=desc, type=_type, length=_size + 2, dpd_type=_mode, tid_type=_tidt, hav=_tidd[1:] + _data, ) else: raise ProtocolError(f'{self.alias}: [Optno {code}] invalid format') return opt
def _read_opt_smf_dpd(self, code, *, desc): """Read HOPOPT ``SMF_DPD`` option. Structure of HOPOPT ``SMF_DPD`` option [:rfc:`5570`]: * IPv6 ``SMF_DPD`` option header in **I-DPD** mode .. code:: text 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ... |0|0|0| 01000 | Opt. Data Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|TidTy| TidLen| TaggerID (optional) ... | +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | Identifier ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * IPv6 ``SMF_DPD`` option header in **H-DPD** mode .. code:: text 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ... |0|0|0| OptType | Opt. Data Len | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| Hash Assist Value (HAV) ... +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Args: code (int): option type value Keyword Args: desc (str): option description Returns: Union[DataType_Opt_SMF_I_PDP, DataType_Opt_SMF_H_PDP]: parsed option data Raises: ProtocolError: If the option is malformed. """ _type = self._read_opt_type(code) _size = self._read_unpack(1) _tidd = self._read_binary(1) if _tidd[0] == '0': _mode = 'I-DPD' _tidt = _TID_TYPE.get(_tidd[1:4]) _tidl = int(_tidd[4:], base=2) if _tidt == _TID_TYPE.NULL: if _tidl != 0: raise ProtocolError( f'{self.alias}: [OptNo {code}] invalid format') _iden = self._read_fileng(_size - 1) opt = dict( desc=desc, type=_type, length=_size + 2, dpd_type=_mode, tid_type=_tidt, tid_len=_tidl, id=_iden, ) elif _tidt == _TID_TYPE.IPv4: if _tidl != 3: raise ProtocolError( f'{self.alias}: [OptNo {code}] invalid format') _tidf = self._read_fileng(4) _iden = self._read_fileng(_size - 4) opt = dict( desc=desc, type=_type, length=_size + 2, dpd_type=_mode, tid_type=_tidt, tid_len=_tidl, tid=ipaddress.ip_address(_tidf), id=_iden, ) elif _tidt == _TID_TYPE.IPv6: if _tidl != 15: raise ProtocolError( f'{self.alias}: [OptNo {code}] invalid format') _tidf = self._read_fileng(15) _iden = self._read_fileng(_size - 15) opt = dict( desc=desc, type=_type, length=_size + 2, dpd_type=_mode, tid_type=_tidt, tid_len=_tidl, tid=ipaddress.ip_address(_tidf), id=_iden, ) else: _tidf = self._read_unpack(_tidl + 1) _iden = self._read_fileng(_size - _tidl - 2) opt = dict( desc=desc, type=_type, length=_size + 2, dpd_type=_mode, tid_type=_tidt, tid_len=_tidl, tid=_tidf, id=_iden, ) elif _tidd[0] == '1': _mode = 'H-DPD' _tidt = _TID_TYPE.get(_tidd[1:4]) _data = self._read_binary(_size - 1) opt = dict( desc=desc, type=_type, length=_size + 2, dpd_type=_mode, tid_type=_tidt, hav=_tidd[1:] + _data, ) else: raise ProtocolError(f'{self.alias}: [OptNo {code}] invalid format') return opt