Skip to main content

atmos/kernel/net/
addr_util.rs

1// L2/L3アドレス表現・チェックサムの純粋関数群。
2//
3// ハードウェア(NIC)やグローバル状態(`super::TCP_SOCKETS`/`NET_LOCK`)に
4// 一切依存しない自己完結モジュールとして`net/mod.rs`から切り出した
5// (`os_lib/web_engine/url_resolve.rs`と同じ狙い)。これによりホスト側
6// ユニットテスト(`tests/`, `x86_64-pc-windows-msvc`ターゲット, `make test`)
7// から`#[path]`で直接取り込んで検証できる。
8
9use alloc::string::String;
10
11pub fn parse_ipv4(s: &str) -> Option<[u8; 4]> {
12    let mut out = [0u8; 4];
13    let mut part_idx = 0usize;
14    let mut cur: u16 = 0;
15    let mut has_digit = false;
16
17    for ch in s.chars() {
18        if ch == '.' {
19            if !has_digit || part_idx >= 4 || cur > 255 {
20                return None;
21            }
22            out[part_idx] = cur as u8;
23            part_idx += 1;
24            cur = 0;
25            has_digit = false;
26            continue;
27        }
28
29        if !ch.is_ascii_digit() {
30            return None;
31        }
32
33        cur = cur
34            .saturating_mul(10)
35            .saturating_add((ch as u16).saturating_sub('0' as u16));
36        if cur > 255 {
37            return None;
38        }
39        has_digit = true;
40    }
41
42    if !has_digit || part_idx != 3 {
43        return None;
44    }
45
46    out[3] = cur as u8;
47    Some(out)
48}
49
50pub fn parse_mac(s: &str) -> Option<[u8; 6]> {
51    let mut mac = [0u8; 6];
52    let mut idx = 0usize;
53
54    for part in s.split(':') {
55        if idx >= 6 || part.len() != 2 {
56            return None;
57        }
58
59        let bytes = part.as_bytes();
60        let hi = hex_nibble(bytes[0])?;
61        let lo = hex_nibble(bytes[1])?;
62        mac[idx] = (hi << 4) | lo;
63        idx += 1;
64    }
65
66    if idx != 6 {
67        return None;
68    }
69
70    Some(mac)
71}
72
73pub fn format_ipv4(ip: [u8; 4]) -> String {
74    alloc::format!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3])
75}
76
77pub fn format_mac(mac: [u8; 6]) -> String {
78    alloc::format!(
79        "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
80        mac[0],
81        mac[1],
82        mac[2],
83        mac[3],
84        mac[4],
85        mac[5]
86    )
87}
88
89pub(crate) fn ipv4_header_checksum(header: &[u8]) -> u16 {
90    internet_checksum(header)
91}
92
93/// RFC 1071 インターネットチェックサム(IPv4ヘッダ/ICMP/UDP擬似ヘッダ共通)。
94pub(crate) fn internet_checksum(data: &[u8]) -> u16 {
95    let mut sum: u32 = 0;
96    let mut i = 0usize;
97
98    while i + 1 < data.len() {
99        let word = ((data[i] as u16) << 8) | data[i + 1] as u16;
100        sum = sum.wrapping_add(word as u32);
101        i += 2;
102    }
103
104    if i < data.len() {
105        let word = (data[i] as u16) << 8;
106        sum = sum.wrapping_add(word as u32);
107    }
108
109    while (sum >> 16) != 0 {
110        sum = (sum & 0xFFFF) + (sum >> 16);
111    }
112
113    !(sum as u16)
114}
115
116fn hex_nibble(c: u8) -> Option<u8> {
117    match c {
118        b'0'..=b'9' => Some(c - b'0'),
119        b'a'..=b'f' => Some(c - b'a' + 10),
120        b'A'..=b'F' => Some(c - b'A' + 10),
121        _ => None,
122    }
123}