1use alloc::string::String;
2use alloc::vec::Vec;
3
4pub fn tcp_socket_lines() -> Vec<String> {
5 let mut lines = Vec::new();
6 unsafe {
7 for i in 0..super::TCP_SOCKET_TABLE_SIZE {
8 let s = &super::TCP_SOCKETS[i];
9 if !s.valid {
10 continue;
11 }
12 lines.push(alloc::format!(
13 "lport={} -> {}:{} state={} snd_nxt={} rcv_nxt={} rx_buf={}",
14 s.local_port,
15 super::format_ipv4(s.remote_ip),
16 s.remote_port,
17 tcp_state_name(s.state),
18 s.snd_nxt,
19 s.rcv_nxt,
20 s.rx_buffer.len()
21 ));
22 }
23 }
24 lines
25}
26
27pub fn tcp_connect_real(remote_ip: [u8; 4], remote_port: u16) -> Result<u16, &'static str> {
28 let _p = crate::os_lib::web_engine::perf::start();
29 let r = tcp_connect_real_measured(remote_ip, remote_port);
30 crate::os_lib::web_engine::perf::add(
31 crate::os_lib::web_engine::perf::Slot::TcpConnect,
32 _p,
33 );
34 r
35}
36
37fn tcp_connect_real_measured(remote_ip: [u8; 4], remote_port: u16) -> Result<u16, &'static str> {
38 if remote_port == 0 {
39 return Err("invalid remote port");
40 }
41
42 let local_port = {
43 let _lock = super::NET_LOCK.lock();
44 unsafe {
45 let picked = super::tcp_state::next_ephemeral_port(
49 super::TCP_EPHEMERAL_PORT,
50 |port| {
51 (0..super::TCP_SOCKET_TABLE_SIZE)
52 .any(|i| super::TCP_SOCKETS[i].valid && super::TCP_SOCKETS[i].local_port == port)
53 },
54 );
55 let p = picked.unwrap_or(super::TCP_EPHEMERAL_PORT);
61 super::TCP_EPHEMERAL_PORT = p.wrapping_add(1);
62 if super::TCP_EPHEMERAL_PORT < 40000 {
63 super::TCP_EPHEMERAL_PORT = 40000;
64 }
65 p
66 }
67 };
68
69 let idx = {
70 let _lock = super::NET_LOCK.lock();
71 tcp_alloc_socket(local_port, remote_ip, remote_port)?
72 };
73
74 let mut syn_pkt = [0u8; 128];
75 let syn_len = {
76 let _lock = super::NET_LOCK.lock();
77 unsafe {
78 super::TCP_SOCKETS[idx].state = super::TcpState::SynSent;
79 super::TCP_SOCKETS[idx].snd_nxt = 1000;
80 }
81 build_tcp_ipv4(
82 super::status().ip,
83 local_port,
84 remote_ip,
85 remote_port,
86 1000,
87 0,
88 0x02, &[],
90 &mut syn_pkt,
91 )?
92 };
93 let my_ip = super::status().ip;
94 crate::info!(
95 "TCP CONNECT: {}.{}.{}.{} -> {}.{}.{}.{}:{} (SYN, src_ip valid={})",
96 my_ip[0],
97 my_ip[1],
98 my_ip[2],
99 my_ip[3],
100 remote_ip[0],
101 remote_ip[1],
102 remote_ip[2],
103 remote_ip[3],
104 remote_port,
105 my_ip != [0, 0, 0, 0]
106 );
107 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&syn_pkt[..syn_len]) {
113 crate::warn!("[NET] TCP CONNECT: SYN transmit failed: {}", e);
114 let _lock = super::NET_LOCK.lock();
115 unsafe {
116 super::TCP_SOCKETS[idx] = super::TcpSocket::empty();
117 REASSEMBLERS[idx].clear();
120 }
121 return Err(e);
122 }
123
124 let start_time = crate::kernel::timer::get_system_time_ms();
131 let mut last_retx = start_time;
132 while crate::kernel::timer::get_system_time_ms() - start_time < 6000 {
133 let state = {
134 let _lock = super::NET_LOCK.lock();
135 unsafe { super::TCP_SOCKETS[idx].state }
136 };
137 if state == super::TcpState::Established {
138 crate::info!("[NET] TCP CONNECT: established on local_port={}", local_port);
139 return Ok(local_port);
140 }
141 if state == super::TcpState::Closed {
142 let _lock = super::NET_LOCK.lock();
150 unsafe {
151 super::TCP_SOCKETS[idx] = super::TcpSocket::empty();
152 REASSEMBLERS[idx].clear();
155 }
156 return Err("tcp connection refused (RST received)");
157 }
158 let now = crate::kernel::timer::get_system_time_ms();
159 if now - last_retx >= 500 {
160 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&syn_pkt[..syn_len]) {
164 crate::warn!("[NET] TCP CONNECT: SYN retransmit failed: {}", e);
165 }
166 last_retx = now;
167 }
168 crate::kernel::scheduler::sleep(1);
171 }
172
173 {
174 let _lock = super::NET_LOCK.lock();
175 unsafe {
176 super::TCP_SOCKETS[idx] = super::TcpSocket::empty();
177 REASSEMBLERS[idx].clear();
180 }
181 }
182 crate::warn!(
186 "[NET][SYNDIAG] connect timeout dst={}.{}.{}.{}:{} local_port={}",
187 remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3],
188 remote_port,
189 local_port
190 );
191 Err("tcp connect timeout")
192}
193
194pub fn tcp_send_real(local_port: u16, data: &[u8]) -> Result<(), &'static str> {
195 let _lock = super::NET_LOCK.lock();
196 let idx = tcp_find_socket_by_local(local_port).ok_or("socket not found")?;
197 let (remote_ip, remote_port, seq, ack) = unsafe {
198 let s = &super::TCP_SOCKETS[idx];
199 if s.state != super::TcpState::Established {
200 return Err("socket not established");
201 }
202 (s.remote_ip, s.remote_port, s.snd_nxt, s.rcv_nxt)
203 };
204
205 let mut pkt = alloc::vec![0u8; 128 + data.len()];
206 let pkt_len = build_tcp_ipv4(
207 super::status().ip,
208 local_port,
209 remote_ip,
210 remote_port,
211 seq,
212 ack,
213 0x18,
214 data,
215 &mut pkt,
216 )?;
217 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&pkt[..pkt_len]) {
223 crate::warn!(
224 "[NET] TCP SEND failed on local_port={} len={}: {}",
225 local_port,
226 data.len(),
227 e
228 );
229 return Err(e);
230 }
231 unsafe {
232 super::TCP_SOCKETS[idx].snd_nxt = super::TCP_SOCKETS[idx]
233 .snd_nxt
234 .wrapping_add(data.len() as u32);
235 }
236 Ok(())
237}
238
239pub fn tcp_retransmit_real(local_port: u16, data: &[u8], seq: u32) -> Result<(), &'static str> {
247 let _lock = super::NET_LOCK.lock();
248 let idx = tcp_find_socket_by_local(local_port).ok_or("socket not found")?;
249 let (remote_ip, remote_port, ack) = unsafe {
250 let s = &super::TCP_SOCKETS[idx];
251 if s.state != super::TcpState::Established {
252 return Err("socket not established");
253 }
254 (s.remote_ip, s.remote_port, s.rcv_nxt)
255 };
256
257 let mut pkt = alloc::vec![0u8; 128 + data.len()];
258 let pkt_len = build_tcp_ipv4(
259 super::status().ip,
260 local_port,
261 remote_ip,
262 remote_port,
263 seq,
264 ack,
265 0x18,
266 data,
267 &mut pkt,
268 )?;
269 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&pkt[..pkt_len]) {
271 crate::warn!(
272 "[NET] TCP RETRANSMIT failed on local_port={} seq={}: {}",
273 local_port,
274 seq,
275 e
276 );
277 return Err(e);
278 }
279 Ok(())
280}
281
282pub fn tcp_current_snd_seq(local_port: u16) -> Option<u32> {
286 let _lock = super::NET_LOCK.lock();
287 unsafe {
288 tcp_find_socket_by_local(local_port).map(|idx| super::TCP_SOCKETS[idx].snd_nxt)
289 }
290}
291
292pub fn tcp_recv_real(
293 local_port: u16,
294 timeout_iters: usize,
295) -> Result<alloc::vec::Vec<u8>, &'static str> {
296 let idx = tcp_find_socket_by_local(local_port).ok_or("socket not found")?;
297
298 let max_timeout_ms = if timeout_iters <= 1 {
299 0
300 } else {
301 (timeout_iters as u32 * 5).min(5000)
302 };
303
304 let start_time = crate::kernel::timer::get_system_time_ms();
305 loop {
306 RECV_POLLS.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
310 crate::kernel::usb::poll_ethernet_data_plane_only();
311
312 let buf_opt = {
313 let _lock = super::NET_LOCK.lock();
314 unsafe {
315 if !super::TCP_SOCKETS[idx].rx_buffer.is_empty()
316 || super::TCP_SOCKETS[idx].state == super::TcpState::CloseWait
317 || super::TCP_SOCKETS[idx].fin_received
318 {
319 Some(core::mem::take(&mut super::TCP_SOCKETS[idx].rx_buffer))
340 } else {
341 None
342 }
343 }
344 };
345
346 if let Some(buf) = buf_opt {
347 return Ok(buf);
348 }
349
350 if max_timeout_ms == 0
351 || crate::kernel::timer::get_system_time_ms() - start_time >= max_timeout_ms as u64
352 {
353 break;
354 }
355 crate::kernel::scheduler::sleep(1);
358 }
359
360 Ok(alloc::vec::Vec::new())
361}
362
363pub fn wait_for_first_byte(local_port: u16, max_ticks: usize) {
381 let _p = crate::os_lib::web_engine::perf::start();
382 wait_for_first_byte_inner(local_port, max_ticks);
383 crate::os_lib::web_engine::perf::add(
384 crate::os_lib::web_engine::perf::Slot::FirstByte,
385 _p,
386 );
387}
388
389fn wait_for_first_byte_inner(local_port: u16, max_ticks: usize) {
390 let start = crate::kernel::timer::get_ticks();
391 while crate::kernel::timer::get_ticks().wrapping_sub(start) < max_ticks {
392 crate::kernel::usb::poll_ethernet_data_plane_only();
393 if tcp_recv_peek_nonempty(local_port) || tcp_is_socket_closed(local_port) {
394 return;
395 }
396 crate::kernel::scheduler::sleep(1);
397 }
398}
399
400pub fn tcp_recv_peek_nonempty(local_port: u16) -> bool {
401 let _lock = super::NET_LOCK.lock();
402 unsafe {
403 if let Some(idx) = tcp_find_socket_by_local(local_port) {
404 !super::TCP_SOCKETS[idx].rx_buffer.is_empty()
405 } else {
406 false
407 }
408 }
409}
410
411pub fn tcp_close_diag(local_port: u16) -> alloc::string::String {
414 let _lock = super::NET_LOCK.lock();
415 unsafe {
416 match tcp_find_socket_by_local(local_port) {
417 Some(idx) => {
418 let s = &super::TCP_SOCKETS[idx];
419 alloc::format!(
420 "state={} fin={} rx_left={} rcv_nxt={} reasm_segs={}",
421 tcp_state_name(s.state),
422 s.fin_received,
423 s.rx_buffer.len(),
424 s.rcv_nxt,
425 REASSEMBLERS[idx].len()
426 )
427 }
428 None => alloc::string::String::from("socket-missing"),
429 }
430 }
431}
432
433pub fn tcp_is_socket_closed(local_port: u16) -> bool {
434 let _lock = super::NET_LOCK.lock();
435 unsafe {
436 if let Some(idx) = tcp_find_socket_by_local(local_port) {
437 let s = &super::TCP_SOCKETS[idx];
438 s.state == super::TcpState::CloseWait
439 || s.state == super::TcpState::Closed
440 || s.state == super::TcpState::TimeWait
441 || s.fin_received
442 } else {
443 true
444 }
445 }
446}
447
448static mut REASSEMBLERS: [super::reassembly::Reassembler; super::TCP_SOCKET_TABLE_SIZE] =
451 [const { super::reassembly::Reassembler::new_const() }; super::TCP_SOCKET_TABLE_SIZE];
452
453pub static SEG_ACCEPTED: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
455pub static SEG_DROPPED: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
456
457pub static RECV_POLLS: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
462
463pub fn tcp_close_real(local_port: u16) -> Result<(), &'static str> {
480 let idx = {
481 let _lock = super::NET_LOCK.lock();
482 tcp_find_socket_by_local(local_port).ok_or("socket not found")?
483 };
484
485 let (remote_ip, remote_port, seq, ack) = {
486 let _lock = super::NET_LOCK.lock();
487 unsafe {
488 let s = &super::TCP_SOCKETS[idx];
489 if s.state != super::TcpState::Established && s.state != super::TcpState::CloseWait {
490 super::TCP_SOCKETS[idx] = super::TcpSocket::empty();
502 REASSEMBLERS[idx].clear();
505 return Ok(());
506 }
507 (s.remote_ip, s.remote_port, s.snd_nxt, s.rcv_nxt)
508 }
509 };
510
511 {
512 let _lock = super::NET_LOCK.lock();
513 unsafe {
514 super::TCP_SOCKETS[idx].state = super::TcpState::FinWait1;
515 super::TCP_SOCKETS[idx].snd_nxt = super::TCP_SOCKETS[idx].snd_nxt.wrapping_add(1);
516 }
517 }
518
519 let mut fin_pkt = [0u8; 128];
520 let len = build_tcp_ipv4(
521 super::status().ip,
522 local_port,
523 remote_ip,
524 remote_port,
525 seq,
526 ack,
527 0x11, &[],
529 &mut fin_pkt,
530 )?;
531 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&fin_pkt[..len]) {
535 crate::warn!(
536 "[NET] TCP CLOSE: FIN transmit failed on local_port={}: {}",
537 local_port,
538 e
539 );
540 }
541
542 {
543 let _lock = super::NET_LOCK.lock();
544 unsafe {
545 super::NET_STATE.tx_packets = super::NET_STATE.tx_packets.saturating_add(1);
546 }
547 }
548
549 let start_time = crate::kernel::timer::get_system_time_ms();
550 while crate::kernel::timer::get_system_time_ms() - start_time < 3000 {
551 crate::kernel::usb::poll_ethernet_data_plane_only();
552
553 let state = {
554 let _lock = super::NET_LOCK.lock();
555 unsafe { super::TCP_SOCKETS[idx].state }
556 };
557
558 if state == super::TcpState::TimeWait || state == super::TcpState::Closed {
559 break;
560 }
561 crate::kernel::scheduler::yield_now();
564 }
565
566 {
567 let _lock = super::NET_LOCK.lock();
568 unsafe {
569 super::TCP_SOCKETS[idx] = super::TcpSocket::empty();
570 REASSEMBLERS[idx].clear();
573 }
574 }
575
576 Ok(())
577}
578
579pub(crate) fn parse_tcp_ipv4_packet(packet: &[u8]) -> Result<(), &'static str> {
580 if packet.len() < 20 {
585 return Err("tcp packet too short");
586 }
587 let ihl = ((packet[0] & 0x0F) as usize) * 4;
588 if ihl < 20 || packet.len() < ihl + 20 {
589 return Err("tcp packet too short");
590 }
591
592 let total_len = (((packet[2] as u16) << 8) | packet[3] as u16) as usize;
593 if total_len < ihl + 20 || total_len > packet.len() {
594 return Err("invalid ipv4 total length");
595 }
596
597 let tcp = &packet[ihl..total_len];
598 let src_port = ((tcp[0] as u16) << 8) | tcp[1] as u16;
599 let dst_port = ((tcp[2] as u16) << 8) | tcp[3] as u16;
600 let seq =
601 ((tcp[4] as u32) << 24) | ((tcp[5] as u32) << 16) | ((tcp[6] as u32) << 8) | tcp[7] as u32;
602 let ack = ((tcp[8] as u32) << 24)
603 | ((tcp[9] as u32) << 16)
604 | ((tcp[10] as u32) << 8)
605 | tcp[11] as u32;
606 let data_offset = ((tcp[12] >> 4) as usize) * 4;
607 if data_offset < 20 || data_offset > tcp.len() {
608 return Err("invalid tcp data offset");
609 }
610
611 let flags = tcp[13];
612 let payload_len = tcp.len() - data_offset;
613 let src_ip = [packet[12], packet[13], packet[14], packet[15]];
614
615 if dst_port > 1024 {
616 crate::debug!(
617 "TCP RX: src_port={} dst_port={} flags=0x{:02x} payload_len={}",
618 src_port,
619 dst_port,
620 flags,
621 payload_len
622 );
623 }
624
625 let mut ack_pkt = [0u8; 128];
630 let mut ack_len = 0usize;
631
632 {
633 let _lock = super::NET_LOCK.lock();
634 let idx = tcp_find_socket(dst_port, src_ip, src_port).ok_or("tcp socket not found")?;
635
636 unsafe {
637 let s = &mut super::TCP_SOCKETS[idx];
653
654 let mut rs = super::tcp_state::RecvState {
658 state: s.state,
659 snd_nxt: s.snd_nxt,
660 rcv_nxt: s.rcv_nxt,
661 fin_received: s.fin_received,
662 };
663 let seg = super::tcp_state::Segment {
664 seq,
665 ack,
666 flags,
667 payload_len: payload_len as u32,
668 };
669 let prev_fin = rs.fin_received;
670 let outcome = super::tcp_state::on_segment(&mut rs, &seg);
671 if payload_len > 0 {
674 if outcome.accept_payload {
675 SEG_ACCEPTED.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
676 } else {
677 SEG_DROPPED.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
678 }
679 }
680
681 if outcome.accept_payload {
682 let start = data_offset
684 .saturating_add(outcome.payload_skip as usize)
685 .min(tcp.len());
686 s.rx_buffer.extend_from_slice(&tcp[start..]);
687 let reasm = &mut REASSEMBLERS[idx];
690 reasm.drop_before(rs.rcv_nxt);
691 let (new_nxt, more) = reasm.pop_contiguous(rs.rcv_nxt);
692 if !more.is_empty() {
693 s.rx_buffer.extend_from_slice(&more);
694 rs.rcv_nxt = new_nxt;
695 }
696 } else if payload_len > 0
697 && (flags & super::tcp_state::FLAG_SYN) == 0
698 && rs.state == super::TcpState::Established
699 {
700 let _ = REASSEMBLERS[idx].insert(seq, &tcp[data_offset..]);
704 }
705 if (flags & super::tcp_state::FLAG_RST) != 0 {
707 crate::warn!(
708 "[NET][DIAG] RST seg on local_port={} prev_state={} seq={} rcv_nxt={} rx_buffer_len={}",
709 s.local_port,
710 tcp_state_name(s.state),
711 seq,
712 s.rcv_nxt,
713 s.rx_buffer.len()
714 );
715 }
716 if (flags & super::tcp_state::FLAG_FIN) != 0 && !prev_fin {
717 crate::warn!(
718 "[NET][DIAG] FIN seg on local_port={} state={} accepted={} rx_buffer_len={}",
719 s.local_port,
720 tcp_state_name(s.state),
721 rs.fin_received,
722 s.rx_buffer.len()
723 );
724 }
725
726 s.state = rs.state;
727 s.snd_nxt = rs.snd_nxt;
728 s.rcv_nxt = rs.rcv_nxt;
729 s.fin_received = rs.fin_received;
730
731 if outcome.send_ack {
732 if let Ok(n) = build_tcp_ack_packet(idx, &mut ack_pkt) {
733 ack_len = n;
734 }
735 }
736
737 super::NET_STATE.rx_packets = super::NET_STATE.rx_packets.saturating_add(1);
738 }
739 } if ack_len > 0 {
742 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&ack_pkt[..ack_len]) {
746 crate::warn!("[NET] TCP: ACK transmit failed: {}", e);
747 }
748 }
749
750 Ok(())
751}
752
753fn build_tcp_ack_packet(idx: usize, out: &mut [u8]) -> Result<usize, &'static str> {
769 unsafe {
770 let s = &super::TCP_SOCKETS[idx];
779 build_tcp_ipv4(
780 super::status().ip,
781 s.local_port,
782 s.remote_ip,
783 s.remote_port,
784 s.snd_nxt,
785 s.rcv_nxt,
786 0x10, &[],
788 out,
789 )
790 }
791}
792
793fn tcp_alloc_socket(
794 local_port: u16,
795 remote_ip: [u8; 4],
796 remote_port: u16,
797) -> Result<usize, &'static str> {
798 unsafe {
799 let idx = super::tcp_state::find_free_slot(super::TCP_SOCKET_TABLE_SIZE, |i| {
802 super::TCP_SOCKETS[i].valid
803 })?;
804 REASSEMBLERS[idx].clear();
806 super::TCP_SOCKETS[idx] = super::TcpSocket {
807 valid: true,
808 local_port,
809 remote_ip,
810 remote_port,
811 state: super::TcpState::Closed,
812 snd_nxt: 0,
813 rcv_nxt: 0,
814 rx_buffer: alloc::vec::Vec::new(),
815 fin_received: false,
816 };
817 Ok(idx)
818 }
819}
820
821#[cfg(test)]
831pub fn tcp_fill_socket_table_for_test() -> usize {
832 let _lock = super::NET_LOCK.lock();
833 let mut occupied = 0usize;
834 unsafe {
835 for i in 0..super::TCP_SOCKET_TABLE_SIZE {
836 if super::TCP_SOCKETS[i].valid {
837 continue;
838 }
839 super::TCP_SOCKETS[i] = super::TcpSocket {
840 valid: true,
841 local_port: 40000 + i as u16,
843 remote_ip: [203, 0, 113, 1],
844 remote_port: 9,
845 state: super::TcpState::Closed,
846 snd_nxt: 0,
847 rcv_nxt: 0,
848 rx_buffer: alloc::vec::Vec::new(),
849 fin_received: false,
850 };
851 occupied += 1;
852 }
853 }
854 occupied
855}
856
857#[cfg(test)]
862pub fn tcp_clear_socket_table_for_test() {
863 let _lock = super::NET_LOCK.lock();
864 unsafe {
865 for i in 0..super::TCP_SOCKET_TABLE_SIZE {
866 super::TCP_SOCKETS[i] = super::TcpSocket::empty();
867 }
868 }
869}
870
871fn tcp_find_socket(local_port: u16, remote_ip: [u8; 4], remote_port: u16) -> Option<usize> {
872 unsafe {
873 for i in 0..super::TCP_SOCKET_TABLE_SIZE {
874 let s = &super::TCP_SOCKETS[i];
875 if !s.valid {
876 continue;
877 }
878 if s.local_port == local_port
879 && s.remote_port == remote_port
880 && s.remote_ip == remote_ip
881 {
882 return Some(i);
883 }
884 }
885 }
886 None
887}
888
889pub(crate) fn tcp_find_socket_by_local(local_port: u16) -> Option<usize> {
890 unsafe {
891 for i in 0..super::TCP_SOCKET_TABLE_SIZE {
892 if super::TCP_SOCKETS[i].valid && super::TCP_SOCKETS[i].local_port == local_port {
893 return Some(i);
894 }
895 }
896 }
897 None
898}
899
900fn build_tcp_ipv4(
901 src_ip: [u8; 4],
902 src_port: u16,
903 dst_ip: [u8; 4],
904 dst_port: u16,
905 seq: u32,
906 ack: u32,
907 flags: u8,
908 payload: &[u8],
909 out: &mut [u8],
910) -> Result<usize, &'static str> {
911 let mut opt_len = 0;
912 if (flags & 0x02) != 0 {
913 opt_len = 4;
914 }
915 let tcp_hdr_len = 20usize + opt_len;
916 let tcp_len = tcp_hdr_len + payload.len();
917 let total_len = 20usize + tcp_len;
918 if total_len > out.len() {
919 return Err("buffer too small");
920 }
921
922 out[0] = 0x45;
923 out[1] = 0;
924 out[2] = ((total_len >> 8) & 0xFF) as u8;
925 out[3] = (total_len & 0xFF) as u8;
926 out[4] = 0x61;
927 out[5] = 0x22;
928 out[6] = 0;
929 out[7] = 0;
930 out[8] = 64;
931 out[9] = 6;
932 out[10] = 0;
933 out[11] = 0;
934 out[12..16].copy_from_slice(&src_ip);
935 out[16..20].copy_from_slice(&dst_ip);
936
937 let ip_checksum = super::ipv4_header_checksum(&out[0..20]);
938 out[10] = (ip_checksum >> 8) as u8;
939 out[11] = ip_checksum as u8;
940
941 out[20] = (src_port >> 8) as u8;
942 out[21] = src_port as u8;
943 out[22] = (dst_port >> 8) as u8;
944 out[23] = dst_port as u8;
945 out[24] = (seq >> 24) as u8;
946 out[25] = (seq >> 16) as u8;
947 out[26] = (seq >> 8) as u8;
948 out[27] = seq as u8;
949 out[28] = (ack >> 24) as u8;
950 out[29] = (ack >> 16) as u8;
951 out[30] = (ack >> 8) as u8;
952 out[31] = ack as u8;
953 out[32] = ((tcp_hdr_len / 4) << 4) as u8;
954 out[33] = flags;
955 out[34] = 0x20;
985 out[35] = 0x00;
986 out[36] = 0x00;
987 out[37] = 0x00;
988 out[38] = 0x00;
989 out[39] = 0x00;
990
991 let mut payload_start = 40;
992 if opt_len > 0 {
993 out[40] = 2;
994 out[41] = 4;
995 out[42] = 0x05;
996 out[43] = 0xB4;
997 payload_start += 4;
998 }
999 let payload_end = payload_start + payload.len();
1000 out[payload_start..payload_end].copy_from_slice(payload);
1001
1002 let mut tcp_csum_buf = alloc::vec![0u8; 12 + tcp_len];
1003 tcp_csum_buf[0..4].copy_from_slice(&src_ip);
1004 tcp_csum_buf[4..8].copy_from_slice(&dst_ip);
1005 tcp_csum_buf[8] = 0;
1006 tcp_csum_buf[9] = 6;
1007 tcp_csum_buf[10] = ((tcp_len >> 8) & 0xFF) as u8;
1008 tcp_csum_buf[11] = (tcp_len & 0xFF) as u8;
1009 tcp_csum_buf[12..12 + tcp_len].copy_from_slice(&out[20..total_len]);
1010
1011 let csum = super::ipv4_header_checksum(&tcp_csum_buf);
1012 out[36] = (csum >> 8) as u8;
1013 out[37] = csum as u8;
1014
1015 let sent = super::arp::transmit_nic_ipv4_packet(&out[..total_len])?;
1016 Ok(sent)
1017}
1018
1019fn tcp_state_name(state: super::TcpState) -> &'static str {
1020 super::tcp_state::tcp_state_name(state)
1021}