crafter 0.3.1

Packet-level network interaction for Rust tools and agents.
Documentation
use super::super::*;
use super::*;
use crate::error::CrafterError;

#[test]
fn dot11_constants_frame_control_masks_match_ieee_layout() {
    assert_eq!(DOT11_FRAME_CONTROL_LEN, 2);
    assert_eq!(DOT11_DURATION_ID_LEN, 2);
    assert_eq!(DOT11_ADDRESS_LEN, 6);
    assert_eq!(DOT11_SEQUENCE_CONTROL_LEN, 2);
    assert_eq!(DOT11_QOS_CONTROL_LEN, 2);
    assert_eq!(DOT11_HT_CONTROL_LEN, 4);
    assert_eq!(DOT11_MIN_HEADER_LEN, 10);
    assert_eq!(DOT11_DATA_HEADER_LEN, 24);
    assert_eq!(DOT11_DATA_ADDR4_HEADER_LEN, 30);
    assert_eq!(DOT11_CONTROL_ONE_ADDRESS_HEADER_LEN, 10);
    assert_eq!(DOT11_CONTROL_TWO_ADDRESS_HEADER_LEN, 16);

    assert_eq!(DOT11_FC_PROTOCOL_VERSION_MASK, 0x0003);
    assert_eq!(DOT11_FC_PROTOCOL_VERSION_SHIFT, 0);
    assert_eq!(DOT11_FC_TYPE_MASK, 0x000c);
    assert_eq!(DOT11_FC_TYPE_SHIFT, 2);
    assert_eq!(DOT11_FC_SUBTYPE_MASK, 0x00f0);
    assert_eq!(DOT11_FC_SUBTYPE_SHIFT, 4);

    assert_eq!(DOT11_FC_TO_DS, 0x0100);
    assert_eq!(DOT11_FC_FROM_DS, 0x0200);
    assert_eq!(DOT11_FC_MORE_FRAGMENTS, 0x0400);
    assert_eq!(DOT11_FC_RETRY, 0x0800);
    assert_eq!(DOT11_FC_POWER_MANAGEMENT, 0x1000);
    assert_eq!(DOT11_FC_MORE_DATA, 0x2000);
    assert_eq!(DOT11_FC_PROTECTED, 0x4000);
    assert_eq!(DOT11_FC_ORDER, 0x8000);
}

#[test]
fn dot11_header_length_data_family_tracks_ds_qos_and_ht_control_boundaries() {
    let data = dot11_test_frame_control(DOT11_FRAME_TYPE_DATA, DOT11_DATA_SUBTYPE_DATA);
    let four_address = data.with_to_ds(true).with_from_ds(true);
    let qos = dot11_test_frame_control(DOT11_FRAME_TYPE_DATA, DOT11_DATA_SUBTYPE_QOS_DATA);
    let qos_four_address = qos.with_to_ds(true).with_from_ds(true);
    let qos_four_address_htc = qos_four_address.with_order(true);
    let non_qos_order = data.with_order(true);

    assert_eq!(Dot11::minimum_header_len_for(data), DOT11_DATA_HEADER_LEN);
    assert_eq!(
        Dot11::minimum_header_len_for(four_address),
        DOT11_DATA_ADDR4_HEADER_LEN
    );
    assert_eq!(
        Dot11::minimum_header_len_for(qos),
        DOT11_DATA_HEADER_LEN + DOT11_QOS_CONTROL_LEN
    );
    assert_eq!(
        Dot11::minimum_header_len_for(qos_four_address),
        DOT11_DATA_ADDR4_HEADER_LEN + DOT11_QOS_CONTROL_LEN
    );
    assert_eq!(
        Dot11::minimum_header_len_for(qos_four_address_htc),
        DOT11_DATA_ADDR4_HEADER_LEN + DOT11_QOS_CONTROL_LEN + DOT11_HT_CONTROL_LEN
    );
    assert_eq!(
        Dot11::minimum_header_len_for(non_qos_order),
        DOT11_DATA_HEADER_LEN
    );
    assert_eq!(Dot11::data().minimum_header_len(), DOT11_DATA_HEADER_LEN);
    assert_eq!(
        Dot11::qos_data().minimum_header_len(),
        DOT11_DATA_HEADER_LEN + DOT11_QOS_CONTROL_LEN
    );
}

#[test]
fn dot11_header_length_management_family_includes_selected_fixed_fields() {
    let cases = [
        (
            DOT11_MGMT_SUBTYPE_ASSOCIATION_REQUEST,
            DOT11_MGMT_ASSOCIATION_REQUEST_FIXED_LEN,
        ),
        (
            DOT11_MGMT_SUBTYPE_ASSOCIATION_RESPONSE,
            DOT11_MGMT_ASSOCIATION_RESPONSE_FIXED_LEN,
        ),
        (
            DOT11_MGMT_SUBTYPE_REASSOCIATION_REQUEST,
            DOT11_MGMT_REASSOCIATION_REQUEST_FIXED_LEN,
        ),
        (
            DOT11_MGMT_SUBTYPE_REASSOCIATION_RESPONSE,
            DOT11_MGMT_REASSOCIATION_RESPONSE_FIXED_LEN,
        ),
        (DOT11_MGMT_SUBTYPE_PROBE_REQUEST, 0),
        (
            DOT11_MGMT_SUBTYPE_PROBE_RESPONSE,
            DOT11_MGMT_PROBE_RESPONSE_FIXED_LEN,
        ),
        (DOT11_MGMT_SUBTYPE_BEACON, DOT11_MGMT_BEACON_FIXED_LEN),
        (DOT11_MGMT_SUBTYPE_ATIM, 0),
        (
            DOT11_MGMT_SUBTYPE_DISASSOCIATION,
            DOT11_MGMT_DISASSOCIATION_FIXED_LEN,
        ),
        (
            DOT11_MGMT_SUBTYPE_AUTHENTICATION,
            DOT11_MGMT_AUTHENTICATION_FIXED_LEN,
        ),
        (
            DOT11_MGMT_SUBTYPE_DEAUTHENTICATION,
            DOT11_MGMT_DEAUTHENTICATION_FIXED_LEN,
        ),
        (DOT11_MGMT_SUBTYPE_ACTION, DOT11_MGMT_ACTION_FIXED_LEN),
        (
            DOT11_MGMT_SUBTYPE_ACTION_NO_ACK,
            DOT11_MGMT_ACTION_FIXED_LEN,
        ),
        (7, 0),
    ];

    for (subtype, fixed_len) in cases {
        let frame_control = dot11_test_frame_control(DOT11_FRAME_TYPE_MANAGEMENT, subtype);

        assert_eq!(
            Dot11::minimum_header_len_for(frame_control),
            DOT11_DATA_HEADER_LEN + fixed_len,
            "management subtype {subtype}"
        );
    }

    let beacon_with_ht_control =
        dot11_test_frame_control(DOT11_FRAME_TYPE_MANAGEMENT, DOT11_MGMT_SUBTYPE_BEACON)
            .with_order(true);

    assert_eq!(
        Dot11::minimum_header_len_for(beacon_with_ht_control),
        DOT11_DATA_HEADER_LEN + DOT11_HT_CONTROL_LEN + DOT11_MGMT_BEACON_FIXED_LEN
    );
}

#[test]
fn dot11_header_length_control_family_uses_subtype_address_layouts() {
    let one_address = [
        DOT11_CONTROL_SUBTYPE_CTS,
        DOT11_CONTROL_SUBTYPE_ACK,
        0,
        DOT11_CONTROL_SUBTYPE_TRIGGER,
    ];
    let two_address = [
        DOT11_CONTROL_SUBTYPE_BLOCK_ACK_REQUEST,
        DOT11_CONTROL_SUBTYPE_BLOCK_ACK,
        DOT11_CONTROL_SUBTYPE_RTS,
        DOT11_CONTROL_SUBTYPE_PS_POLL,
        DOT11_CONTROL_SUBTYPE_CF_END,
        DOT11_CONTROL_SUBTYPE_CF_END_CF_ACK,
    ];

    for subtype in one_address {
        let frame_control = dot11_test_frame_control(DOT11_FRAME_TYPE_CONTROL, subtype);

        assert_eq!(
            Dot11::minimum_header_len_for(frame_control),
            DOT11_CONTROL_ONE_ADDRESS_HEADER_LEN,
            "control subtype {subtype}"
        );
    }

    for subtype in two_address {
        let frame_control = dot11_test_frame_control(DOT11_FRAME_TYPE_CONTROL, subtype);

        assert_eq!(
            Dot11::minimum_header_len_for(frame_control),
            DOT11_CONTROL_TWO_ADDRESS_HEADER_LEN,
            "control subtype {subtype}"
        );
    }
}

#[test]
fn dot11_header_length_from_bytes_reports_supported_boundaries() {
    let qos_four_address_htc =
        dot11_test_frame_control(DOT11_FRAME_TYPE_DATA, DOT11_DATA_SUBTYPE_QOS_DATA)
            .with_to_ds(true)
            .with_from_ds(true)
            .with_order(true);
    let header_len = DOT11_DATA_ADDR4_HEADER_LEN + DOT11_QOS_CONTROL_LEN + DOT11_HT_CONTROL_LEN;
    let bytes = dot11_test_bytes(qos_four_address_htc, header_len + 3);

    assert_eq!(Dot11::header_len_from_bytes(&bytes).unwrap(), header_len);

    let ack = dot11_test_frame_control(DOT11_FRAME_TYPE_CONTROL, DOT11_CONTROL_SUBTYPE_ACK);
    let bytes = dot11_test_bytes(ack, DOT11_CONTROL_ONE_ADDRESS_HEADER_LEN);

    assert_eq!(
        Dot11::header_len_from_bytes(&bytes).unwrap(),
        DOT11_CONTROL_ONE_ADDRESS_HEADER_LEN
    );
}

#[test]
fn dot11_header_length_from_bytes_rejects_truncated_boundaries() {
    let err = Dot11::header_len_from_bytes([0x08]).unwrap_err();

    assert_eq!(
        err,
        CrafterError::buffer_too_short("dot11.frame_control", 2, 1)
    );

    let beacon = dot11_test_frame_control(DOT11_FRAME_TYPE_MANAGEMENT, DOT11_MGMT_SUBTYPE_BEACON);
    let beacon_header_len = DOT11_DATA_HEADER_LEN + DOT11_MGMT_BEACON_FIXED_LEN;
    let err =
        Dot11::header_len_from_bytes(dot11_test_bytes(beacon, beacon_header_len - 1)).unwrap_err();

    assert_eq!(
        err,
        CrafterError::buffer_too_short("dot11.header", beacon_header_len, beacon_header_len - 1)
    );

    let qos_four_address =
        dot11_test_frame_control(DOT11_FRAME_TYPE_DATA, DOT11_DATA_SUBTYPE_QOS_DATA)
            .with_to_ds(true)
            .with_from_ds(true);
    let qos_header_len = DOT11_DATA_ADDR4_HEADER_LEN + DOT11_QOS_CONTROL_LEN;
    let err = Dot11::header_len_from_bytes(dot11_test_bytes(qos_four_address, qos_header_len - 1))
        .unwrap_err();

    assert_eq!(
        err,
        CrafterError::buffer_too_short("dot11.header", qos_header_len, qos_header_len - 1)
    );

    let ack = dot11_test_frame_control(DOT11_FRAME_TYPE_CONTROL, DOT11_CONTROL_SUBTYPE_ACK);
    let err = Dot11::header_len_from_bytes(dot11_test_bytes(
        ack,
        DOT11_CONTROL_ONE_ADDRESS_HEADER_LEN - 1,
    ))
    .unwrap_err();

    assert_eq!(
        err,
        CrafterError::buffer_too_short(
            "dot11.header",
            DOT11_CONTROL_ONE_ADDRESS_HEADER_LEN,
            DOT11_CONTROL_ONE_ADDRESS_HEADER_LEN - 1
        )
    );
}

#[test]
fn dot11_constants_type_and_subtype_values_are_stable() {
    assert_eq!(DOT11_FRAME_TYPE_MANAGEMENT, 0);
    assert_eq!(DOT11_FRAME_TYPE_CONTROL, 1);
    assert_eq!(DOT11_FRAME_TYPE_DATA, 2);
    assert_eq!(DOT11_FRAME_TYPE_EXTENSION, 3);

    assert_eq!(DOT11_MGMT_SUBTYPE_ASSOCIATION_REQUEST, 0);
    assert_eq!(DOT11_MGMT_SUBTYPE_PROBE_REQUEST, 4);
    assert_eq!(DOT11_MGMT_SUBTYPE_BEACON, 8);
    assert_eq!(DOT11_MGMT_SUBTYPE_AUTHENTICATION, 11);
    assert_eq!(DOT11_MGMT_SUBTYPE_DEAUTHENTICATION, 12);
    assert_eq!(DOT11_MGMT_SUBTYPE_ACTION_NO_ACK, 14);

    assert_eq!(DOT11_CONTROL_SUBTYPE_TRIGGER, 2);
    assert_eq!(DOT11_CONTROL_SUBTYPE_BLOCK_ACK_REQUEST, 8);
    assert_eq!(DOT11_CONTROL_SUBTYPE_RTS, 11);
    assert_eq!(DOT11_CONTROL_SUBTYPE_CTS, 12);
    assert_eq!(DOT11_CONTROL_SUBTYPE_ACK, 13);

    assert_eq!(DOT11_DATA_SUBTYPE_DATA, 0);
    assert_eq!(DOT11_DATA_SUBTYPE_NULL, 4);
    assert_eq!(DOT11_DATA_SUBTYPE_QOS_DATA, 8);
    assert_eq!(DOT11_DATA_SUBTYPE_QOS_NULL, 12);
    assert_eq!(DOT11_DATA_SUBTYPE_QOS_CF_ACK_CF_POLL, 15);
}

#[test]
fn dot11_constants_label_helpers_cover_known_values() {
    assert_eq!(
        dot11_frame_type_label(DOT11_FRAME_TYPE_MANAGEMENT),
        "management"
    );
    assert_eq!(dot11_frame_type_label(DOT11_FRAME_TYPE_CONTROL), "control");
    assert_eq!(dot11_frame_type_label(DOT11_FRAME_TYPE_DATA), "data");
    assert_eq!(
        dot11_frame_type_label(DOT11_FRAME_TYPE_EXTENSION),
        "extension"
    );

    assert_eq!(
        dot11_management_subtype_label(DOT11_MGMT_SUBTYPE_BEACON),
        "beacon"
    );
    assert_eq!(
        dot11_management_subtype_label(DOT11_MGMT_SUBTYPE_AUTHENTICATION),
        "authentication"
    );
    assert_eq!(
        dot11_control_subtype_label(DOT11_CONTROL_SUBTYPE_RTS),
        "rts"
    );
    assert_eq!(
        dot11_control_subtype_label(DOT11_CONTROL_SUBTYPE_ACK),
        "ack"
    );
    assert_eq!(dot11_data_subtype_label(DOT11_DATA_SUBTYPE_DATA), "data");
    assert_eq!(
        dot11_data_subtype_label(DOT11_DATA_SUBTYPE_QOS_DATA),
        "qos-data"
    );

    assert_eq!(
        dot11_subtype_label(
            DOT11_FRAME_TYPE_MANAGEMENT,
            DOT11_MGMT_SUBTYPE_PROBE_REQUEST
        ),
        "probe-request"
    );
    assert_eq!(
        dot11_subtype_label(DOT11_FRAME_TYPE_CONTROL, DOT11_CONTROL_SUBTYPE_CTS),
        "cts"
    );
    assert_eq!(
        dot11_subtype_label(DOT11_FRAME_TYPE_DATA, DOT11_DATA_SUBTYPE_QOS_NULL),
        "qos-null"
    );
}

#[test]
fn dot11_constants_label_helpers_format_unknown_fallbacks() {
    assert_eq!(dot11_frame_type_label(4), "unknown-frame-type(4)");
    assert_eq!(
        dot11_management_subtype_label(7),
        "unknown-management-subtype(7)"
    );
    assert_eq!(dot11_control_subtype_label(0), "unknown-control-subtype(0)");
    assert_eq!(dot11_data_subtype_label(13), "unknown-data-subtype(13)");
    assert_eq!(
        dot11_subtype_label(DOT11_FRAME_TYPE_EXTENSION, 9),
        "extension-subtype(9)"
    );
    assert_eq!(
        dot11_subtype_label(6, 1),
        "unknown-frame-type(6)-subtype(1)"
    );
    assert_eq!(dot11_category_label(42), "unknown-category(42)");
}

#[test]
fn dot11_constants_sequence_category_and_capability_values_are_stable() {
    assert_eq!(DOT11_SEQUENCE_FRAGMENT_NUMBER_MASK, 0x000f);
    assert_eq!(DOT11_SEQUENCE_FRAGMENT_NUMBER_SHIFT, 0);
    assert_eq!(DOT11_SEQUENCE_NUMBER_MASK, 0xfff0);
    assert_eq!(DOT11_SEQUENCE_NUMBER_SHIFT, 4);

    assert_eq!(DOT11_CATEGORY_SPECTRUM_MANAGEMENT, 0);
    assert_eq!(DOT11_CATEGORY_BLOCK_ACK, 3);
    assert_eq!(DOT11_CATEGORY_PUBLIC, 4);
    assert_eq!(DOT11_CATEGORY_SA_QUERY, 8);
    assert_eq!(DOT11_CATEGORY_SELF_PROTECTED, 15);
    assert_eq!(
        dot11_category_label(DOT11_CATEGORY_PROTECTED_DUAL_OF_PUBLIC_ACTION),
        "protected-dual-of-public-action"
    );

    assert_eq!(DOT11_CAPABILITY_ESS, 0x0001);
    assert_eq!(DOT11_CAPABILITY_IBSS, 0x0002);
    assert_eq!(DOT11_CAPABILITY_PRIVACY, 0x0010);
    assert_eq!(DOT11_CAPABILITY_QOS, 0x0200);
    assert_eq!(DOT11_CAPABILITY_SHORT_SLOT_TIME, 0x0400);
    assert_eq!(DOT11_CAPABILITY_IMMEDIATE_BLOCK_ACK, 0x8000);

    assert_eq!(DOT11_TAG_SSID, 0);
    assert_eq!(DOT11_TAG_SUPPORTED_RATES, 1);
    assert_eq!(DOT11_TAG_DS_PARAMETER_SET, 3);
    assert_eq!(DOT11_TAG_TIM, 5);
    assert_eq!(DOT11_TAG_RSN, 48);
}