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 super::TCP_SOCKETS[idx].snd_una = 1000;
81 }
82 build_tcp_ipv4(
83 super::status().ip,
84 local_port,
85 remote_ip,
86 remote_port,
87 1000,
88 0,
89 0x02, &[],
91 &mut syn_pkt,
92 )?
93 };
94 let my_ip = super::status().ip;
95 crate::info!(
96 "TCP CONNECT: {}.{}.{}.{} -> {}.{}.{}.{}:{} (SYN, src_ip valid={})",
97 my_ip[0],
98 my_ip[1],
99 my_ip[2],
100 my_ip[3],
101 remote_ip[0],
102 remote_ip[1],
103 remote_ip[2],
104 remote_ip[3],
105 remote_port,
106 my_ip != [0, 0, 0, 0]
107 );
108 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&syn_pkt[..syn_len]) {
114 crate::warn!("[NET] TCP CONNECT: SYN transmit failed: {}", e);
115 let _lock = super::NET_LOCK.lock();
116 unsafe {
117 super::TCP_SOCKETS[idx] = super::TcpSocket::empty();
118 REASSEMBLERS[idx].clear();
121 }
122 return Err(e);
123 }
124
125 let start_time = crate::kernel::timer::get_system_time_ms();
132 let mut last_retx = start_time;
133 while crate::kernel::timer::get_system_time_ms() - start_time < 6000 {
134 let state = {
135 let _lock = super::NET_LOCK.lock();
136 unsafe { super::TCP_SOCKETS[idx].state }
137 };
138 if state == super::TcpState::Established {
139 crate::info!("[NET] TCP CONNECT: established on local_port={}", local_port);
140 return Ok(local_port);
141 }
142 if state == super::TcpState::Closed {
143 let _lock = super::NET_LOCK.lock();
151 unsafe {
152 super::TCP_SOCKETS[idx] = super::TcpSocket::empty();
153 REASSEMBLERS[idx].clear();
156 }
157 return Err("tcp connection refused (RST received)");
158 }
159 let now = crate::kernel::timer::get_system_time_ms();
160 if now - last_retx >= 500 {
161 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&syn_pkt[..syn_len]) {
165 crate::warn!("[NET] TCP CONNECT: SYN retransmit failed: {}", e);
166 }
167 last_retx = now;
168 }
169 crate::kernel::scheduler::sleep(1);
172 }
173
174 {
175 let _lock = super::NET_LOCK.lock();
176 unsafe {
177 super::TCP_SOCKETS[idx] = super::TcpSocket::empty();
178 REASSEMBLERS[idx].clear();
181 }
182 }
183 crate::warn!(
187 "[NET][SYNDIAG] connect timeout dst={}.{}.{}.{}:{} local_port={}",
188 remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3],
189 remote_port,
190 local_port
191 );
192 Err("tcp connect timeout")
193}
194
195pub fn tcp_send_real(local_port: u16, data: &[u8]) -> Result<(), &'static str> {
196 let _lock = super::NET_LOCK.lock();
197 let idx = tcp_find_socket_by_local(local_port).ok_or("socket not found")?;
198 let (remote_ip, remote_port, seq, ack) = unsafe {
199 let s = &super::TCP_SOCKETS[idx];
200 if s.state != super::TcpState::Established {
201 return Err("socket not established");
202 }
203 (s.remote_ip, s.remote_port, s.snd_nxt, s.rcv_nxt)
204 };
205
206 let mut pkt = alloc::vec![0u8; 128 + data.len()];
207 let pkt_len = build_tcp_ipv4(
208 super::status().ip,
209 local_port,
210 remote_ip,
211 remote_port,
212 seq,
213 ack,
214 0x18,
215 data,
216 &mut pkt,
217 )?;
218 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&pkt[..pkt_len]) {
224 crate::warn!(
225 "[NET] TCP SEND failed on local_port={} len={}: {}",
226 local_port,
227 data.len(),
228 e
229 );
230 return Err(e);
231 }
232 unsafe {
233 super::TCP_SOCKETS[idx].snd_nxt = super::TCP_SOCKETS[idx]
234 .snd_nxt
235 .wrapping_add(data.len() as u32);
236 }
237 Ok(())
238}
239
240pub fn tcp_retransmit_real(local_port: u16, data: &[u8], seq: u32) -> Result<(), &'static str> {
248 let _lock = super::NET_LOCK.lock();
249 let idx = tcp_find_socket_by_local(local_port).ok_or("socket not found")?;
250 let (remote_ip, remote_port, ack) = unsafe {
251 let s = &super::TCP_SOCKETS[idx];
252 if s.state != super::TcpState::Established {
253 return Err("socket not established");
254 }
255 (s.remote_ip, s.remote_port, s.rcv_nxt)
256 };
257
258 let mut pkt = alloc::vec![0u8; 128 + data.len()];
259 let pkt_len = build_tcp_ipv4(
260 super::status().ip,
261 local_port,
262 remote_ip,
263 remote_port,
264 seq,
265 ack,
266 0x18,
267 data,
268 &mut pkt,
269 )?;
270 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&pkt[..pkt_len]) {
272 crate::warn!(
273 "[NET] TCP RETRANSMIT failed on local_port={} seq={}: {}",
274 local_port,
275 seq,
276 e
277 );
278 return Err(e);
279 }
280 Ok(())
281}
282
283pub fn tcp_current_snd_seq(local_port: u16) -> Option<u32> {
287 let _lock = super::NET_LOCK.lock();
288 unsafe {
289 tcp_find_socket_by_local(local_port).map(|idx| super::TCP_SOCKETS[idx].snd_nxt)
290 }
291}
292
293pub fn tcp_recv_real(
294 local_port: u16,
295 timeout_iters: usize,
296) -> Result<alloc::vec::Vec<u8>, &'static str> {
297 let idx = tcp_find_socket_by_local(local_port).ok_or("socket not found")?;
298
299 let max_timeout_ms = if timeout_iters <= 1 {
300 0
301 } else {
302 (timeout_iters as u32 * 5).min(5000)
303 };
304
305 let start_time = crate::kernel::timer::get_system_time_ms();
306 loop {
307 RECV_POLLS.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
311 crate::kernel::usb::poll_ethernet_data_plane_only();
312
313 let buf_opt = {
314 let _lock = super::NET_LOCK.lock();
315 unsafe {
316 if !super::TCP_SOCKETS[idx].rx_buffer.is_empty()
317 || super::TCP_SOCKETS[idx].state == super::TcpState::CloseWait
318 || super::TCP_SOCKETS[idx].fin_received
319 {
320 Some(core::mem::take(&mut super::TCP_SOCKETS[idx].rx_buffer))
341 } else {
342 None
343 }
344 }
345 };
346
347 if let Some(buf) = buf_opt {
348 return Ok(buf);
349 }
350
351 if max_timeout_ms == 0
352 || crate::kernel::timer::get_system_time_ms() - start_time >= max_timeout_ms as u64
353 {
354 break;
355 }
356 crate::kernel::scheduler::sleep(1);
359 }
360
361 Ok(alloc::vec::Vec::new())
362}
363
364pub fn wait_for_first_byte(local_port: u16, max_ticks: usize) {
382 let _p = crate::os_lib::web_engine::perf::start();
383 wait_for_first_byte_inner(local_port, max_ticks);
384 crate::os_lib::web_engine::perf::add(
385 crate::os_lib::web_engine::perf::Slot::FirstByte,
386 _p,
387 );
388}
389
390fn wait_for_first_byte_inner(local_port: u16, max_ticks: usize) {
391 let start = crate::kernel::timer::get_ticks();
392 while crate::kernel::timer::get_ticks().wrapping_sub(start) < max_ticks {
393 crate::kernel::usb::poll_ethernet_data_plane_only();
394 if tcp_recv_peek_nonempty(local_port) || tcp_is_socket_closed(local_port) {
395 return;
396 }
397 crate::kernel::scheduler::sleep(1);
398 }
399}
400
401pub fn tcp_acked_through(local_port: u16, pos: u32) -> bool {
404 let _lock = super::NET_LOCK.lock();
405 unsafe {
406 match tcp_find_socket_by_local(local_port) {
407 Some(idx) => super::tcp_state::acked_through(super::TCP_SOCKETS[idx].snd_una, pos),
408 None => true,
409 }
410 }
411}
412
413pub fn tcp_recv_peek_nonempty(local_port: u16) -> bool {
414 let _lock = super::NET_LOCK.lock();
415 unsafe {
416 if let Some(idx) = tcp_find_socket_by_local(local_port) {
417 !super::TCP_SOCKETS[idx].rx_buffer.is_empty()
418 } else {
419 false
420 }
421 }
422}
423
424pub fn tcp_close_diag(local_port: u16) -> alloc::string::String {
427 let _lock = super::NET_LOCK.lock();
428 unsafe {
429 match tcp_find_socket_by_local(local_port) {
430 Some(idx) => {
431 let s = &super::TCP_SOCKETS[idx];
432 alloc::format!(
433 "state={} fin={} rx_left={} rcv_nxt={} reasm_segs={}",
434 tcp_state_name(s.state),
435 s.fin_received,
436 s.rx_buffer.len(),
437 s.rcv_nxt,
438 REASSEMBLERS[idx].len()
439 )
440 }
441 None => alloc::string::String::from("socket-missing"),
442 }
443 }
444}
445
446pub fn tcp_is_socket_closed(local_port: u16) -> bool {
447 let _lock = super::NET_LOCK.lock();
448 unsafe {
449 if let Some(idx) = tcp_find_socket_by_local(local_port) {
450 let s = &super::TCP_SOCKETS[idx];
451 s.state == super::TcpState::CloseWait
452 || s.state == super::TcpState::Closed
453 || s.state == super::TcpState::TimeWait
454 || s.fin_received
455 } else {
456 true
457 }
458 }
459}
460
461static mut REASSEMBLERS: [super::reassembly::Reassembler; super::TCP_SOCKET_TABLE_SIZE] =
464 [const { super::reassembly::Reassembler::new_const() }; super::TCP_SOCKET_TABLE_SIZE];
465
466pub static SEG_ACCEPTED: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
468pub static SEG_DROPPED: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
469
470pub static RECV_POLLS: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
475
476pub fn tcp_close_real(local_port: u16) -> Result<(), &'static str> {
493 let idx = {
494 let _lock = super::NET_LOCK.lock();
495 tcp_find_socket_by_local(local_port).ok_or("socket not found")?
496 };
497
498 let (remote_ip, remote_port, seq, ack, prev_state) = {
499 let _lock = super::NET_LOCK.lock();
500 unsafe {
501 let s = &super::TCP_SOCKETS[idx];
502 if s.state != super::TcpState::Established && s.state != super::TcpState::CloseWait {
503 super::TCP_SOCKETS[idx] = super::TcpSocket::empty();
515 REASSEMBLERS[idx].clear();
518 return Ok(());
519 }
520 (s.remote_ip, s.remote_port, s.snd_nxt, s.rcv_nxt, s.state)
521 }
522 };
523
524 {
525 let _lock = super::NET_LOCK.lock();
526 unsafe {
527 super::TCP_SOCKETS[idx].state = super::TcpState::FinWait1;
528 super::TCP_SOCKETS[idx].snd_nxt = super::TCP_SOCKETS[idx].snd_nxt.wrapping_add(1);
529 }
530 }
531
532 let mut fin_pkt = [0u8; 128];
533 let len = build_tcp_ipv4(
534 super::status().ip,
535 local_port,
536 remote_ip,
537 remote_port,
538 seq,
539 ack,
540 0x11, &[],
542 &mut fin_pkt,
543 )?;
544 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&fin_pkt[..len]) {
548 crate::warn!(
549 "[NET] TCP CLOSE: FIN transmit failed on local_port={}: {}",
550 local_port,
551 e
552 );
553 }
554
555 {
556 let _lock = super::NET_LOCK.lock();
557 unsafe {
558 super::NET_STATE.tx_packets = super::NET_STATE.tx_packets.saturating_add(1);
559 }
560 }
561
562 let budget = super::tcp_state::close_wait_budget_ms(prev_state);
564 let start_time = crate::kernel::timer::get_system_time_ms();
565 while crate::kernel::timer::get_system_time_ms() - start_time < budget {
566 crate::kernel::usb::poll_ethernet_data_plane_only();
567
568 let state = {
569 let _lock = super::NET_LOCK.lock();
570 unsafe { super::TCP_SOCKETS[idx].state }
571 };
572
573 if state == super::TcpState::TimeWait || state == super::TcpState::Closed {
574 break;
575 }
576 crate::kernel::scheduler::yield_now();
579 }
580
581 {
582 let _lock = super::NET_LOCK.lock();
583 unsafe {
584 super::TCP_SOCKETS[idx] = super::TcpSocket::empty();
585 REASSEMBLERS[idx].clear();
588 }
589 }
590
591 Ok(())
592}
593
594pub(crate) fn parse_tcp_ipv4_packet(packet: &[u8]) -> Result<(), &'static str> {
595 if packet.len() < 20 {
600 return Err("tcp packet too short");
601 }
602 let ihl = ((packet[0] & 0x0F) as usize) * 4;
603 if ihl < 20 || packet.len() < ihl + 20 {
604 return Err("tcp packet too short");
605 }
606
607 let total_len = (((packet[2] as u16) << 8) | packet[3] as u16) as usize;
608 if total_len < ihl + 20 || total_len > packet.len() {
609 return Err("invalid ipv4 total length");
610 }
611
612 let tcp = &packet[ihl..total_len];
613 let src_port = ((tcp[0] as u16) << 8) | tcp[1] as u16;
614 let dst_port = ((tcp[2] as u16) << 8) | tcp[3] as u16;
615 let seq =
616 ((tcp[4] as u32) << 24) | ((tcp[5] as u32) << 16) | ((tcp[6] as u32) << 8) | tcp[7] as u32;
617 let ack = ((tcp[8] as u32) << 24)
618 | ((tcp[9] as u32) << 16)
619 | ((tcp[10] as u32) << 8)
620 | tcp[11] as u32;
621 let data_offset = ((tcp[12] >> 4) as usize) * 4;
622 if data_offset < 20 || data_offset > tcp.len() {
623 return Err("invalid tcp data offset");
624 }
625
626 let flags = tcp[13];
627 let payload_len = tcp.len() - data_offset;
628 let src_ip = [packet[12], packet[13], packet[14], packet[15]];
629
630 if dst_port > 1024 {
631 crate::debug!(
632 "TCP RX: src_port={} dst_port={} flags=0x{:02x} payload_len={}",
633 src_port,
634 dst_port,
635 flags,
636 payload_len
637 );
638 }
639
640 let mut ack_pkt = [0u8; 128];
645 let mut ack_len = 0usize;
646
647 {
648 let _lock = super::NET_LOCK.lock();
649 let idx = tcp_find_socket(dst_port, src_ip, src_port).ok_or("tcp socket not found")?;
650
651 unsafe {
652 let s = &mut super::TCP_SOCKETS[idx];
668
669 let mut rs = super::tcp_state::RecvState {
673 state: s.state,
674 snd_nxt: s.snd_nxt,
675 rcv_nxt: s.rcv_nxt,
676 fin_received: s.fin_received,
677 };
678 let seg = super::tcp_state::Segment {
679 seq,
680 ack,
681 flags,
682 payload_len: payload_len as u32,
683 };
684 let prev_fin = rs.fin_received;
685 let outcome = super::tcp_state::on_segment(&mut rs, &seg);
686 if payload_len > 0 {
689 if outcome.accept_payload {
690 SEG_ACCEPTED.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
691 } else {
692 SEG_DROPPED.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
693 }
694 }
695
696 if outcome.accept_payload {
697 let start = data_offset
699 .saturating_add(outcome.payload_skip as usize)
700 .min(tcp.len());
701 s.rx_buffer.extend_from_slice(&tcp[start..]);
702 let reasm = &mut REASSEMBLERS[idx];
705 reasm.drop_before(rs.rcv_nxt);
706 let (new_nxt, more) = reasm.pop_contiguous(rs.rcv_nxt);
707 if !more.is_empty() {
708 s.rx_buffer.extend_from_slice(&more);
709 rs.rcv_nxt = new_nxt;
710 }
711 } else if payload_len > 0
712 && (flags & super::tcp_state::FLAG_SYN) == 0
713 && rs.state == super::TcpState::Established
714 {
715 let _ = REASSEMBLERS[idx].insert(seq, &tcp[data_offset..]);
719 }
720 if (flags & super::tcp_state::FLAG_RST) != 0 {
722 crate::warn!(
723 "[NET][DIAG] RST seg on local_port={} prev_state={} seq={} rcv_nxt={} rx_buffer_len={}",
724 s.local_port,
725 tcp_state_name(s.state),
726 seq,
727 s.rcv_nxt,
728 s.rx_buffer.len()
729 );
730 }
731 if (flags & super::tcp_state::FLAG_FIN) != 0 && !prev_fin {
732 crate::warn!(
733 "[NET][DIAG] FIN seg on local_port={} state={} accepted={} rx_buffer_len={}",
734 s.local_port,
735 tcp_state_name(s.state),
736 rs.fin_received,
737 s.rx_buffer.len()
738 );
739 }
740
741 s.state = rs.state;
742 s.snd_nxt = rs.snd_nxt;
743 if flags & super::tcp_state::FLAG_ACK != 0 {
744 s.snd_una = super::tcp_state::advance_snd_una(s.snd_una, s.snd_nxt, ack);
745 }
746 s.rcv_nxt = rs.rcv_nxt;
747 s.fin_received = rs.fin_received;
748
749 if outcome.send_ack {
750 if let Ok(n) = build_tcp_ack_packet(idx, &mut ack_pkt) {
751 ack_len = n;
752 }
753 }
754
755 super::NET_STATE.rx_packets = super::NET_STATE.rx_packets.saturating_add(1);
756 }
757 } if ack_len > 0 {
760 if let Err(e) = super::arp::transmit_nic_ipv4_packet(&ack_pkt[..ack_len]) {
764 crate::warn!("[NET] TCP: ACK transmit failed: {}", e);
765 }
766 }
767
768 Ok(())
769}
770
771fn build_tcp_ack_packet(idx: usize, out: &mut [u8]) -> Result<usize, &'static str> {
787 unsafe {
788 let s = &super::TCP_SOCKETS[idx];
797 build_tcp_ipv4(
798 super::status().ip,
799 s.local_port,
800 s.remote_ip,
801 s.remote_port,
802 s.snd_nxt,
803 s.rcv_nxt,
804 0x10, &[],
806 out,
807 )
808 }
809}
810
811fn tcp_alloc_socket(
812 local_port: u16,
813 remote_ip: [u8; 4],
814 remote_port: u16,
815) -> Result<usize, &'static str> {
816 unsafe {
817 let idx = super::tcp_state::find_free_slot(super::TCP_SOCKET_TABLE_SIZE, |i| {
820 super::TCP_SOCKETS[i].valid
821 })?;
822 REASSEMBLERS[idx].clear();
824 super::TCP_SOCKETS[idx] = super::TcpSocket {
825 valid: true,
826 local_port,
827 remote_ip,
828 remote_port,
829 state: super::TcpState::Closed,
830 snd_nxt: 0,
831 snd_una: 0,
832 rcv_nxt: 0,
833 rx_buffer: alloc::vec::Vec::new(),
834 fin_received: false,
835 };
836 Ok(idx)
837 }
838}
839
840#[cfg(test)]
850pub fn tcp_fill_socket_table_for_test() -> usize {
851 let _lock = super::NET_LOCK.lock();
852 let mut occupied = 0usize;
853 unsafe {
854 for i in 0..super::TCP_SOCKET_TABLE_SIZE {
855 if super::TCP_SOCKETS[i].valid {
856 continue;
857 }
858 super::TCP_SOCKETS[i] = super::TcpSocket {
859 valid: true,
860 local_port: 40000 + i as u16,
862 remote_ip: [203, 0, 113, 1],
863 remote_port: 9,
864 state: super::TcpState::Closed,
865 snd_nxt: 0,
866 snd_una: 0,
867 rcv_nxt: 0,
868 rx_buffer: alloc::vec::Vec::new(),
869 fin_received: false,
870 };
871 occupied += 1;
872 }
873 }
874 occupied
875}
876
877#[cfg(test)]
882pub fn tcp_clear_socket_table_for_test() {
883 let _lock = super::NET_LOCK.lock();
884 unsafe {
885 for i in 0..super::TCP_SOCKET_TABLE_SIZE {
886 super::TCP_SOCKETS[i] = super::TcpSocket::empty();
887 }
888 }
889}
890
891fn tcp_find_socket(local_port: u16, remote_ip: [u8; 4], remote_port: u16) -> Option<usize> {
892 unsafe {
893 for i in 0..super::TCP_SOCKET_TABLE_SIZE {
894 let s = &super::TCP_SOCKETS[i];
895 if !s.valid {
896 continue;
897 }
898 if s.local_port == local_port
899 && s.remote_port == remote_port
900 && s.remote_ip == remote_ip
901 {
902 return Some(i);
903 }
904 }
905 }
906 None
907}
908
909pub(crate) fn tcp_find_socket_by_local(local_port: u16) -> Option<usize> {
910 unsafe {
911 for i in 0..super::TCP_SOCKET_TABLE_SIZE {
912 if super::TCP_SOCKETS[i].valid && super::TCP_SOCKETS[i].local_port == local_port {
913 return Some(i);
914 }
915 }
916 }
917 None
918}
919
920fn build_tcp_ipv4(
921 src_ip: [u8; 4],
922 src_port: u16,
923 dst_ip: [u8; 4],
924 dst_port: u16,
925 seq: u32,
926 ack: u32,
927 flags: u8,
928 payload: &[u8],
929 out: &mut [u8],
930) -> Result<usize, &'static str> {
931 let mut opt_len = 0;
932 if (flags & 0x02) != 0 {
933 opt_len = 4;
934 }
935 let tcp_hdr_len = 20usize + opt_len;
936 let tcp_len = tcp_hdr_len + payload.len();
937 let total_len = 20usize + tcp_len;
938 if total_len > out.len() {
939 return Err("buffer too small");
940 }
941
942 out[0] = 0x45;
943 out[1] = 0;
944 out[2] = ((total_len >> 8) & 0xFF) as u8;
945 out[3] = (total_len & 0xFF) as u8;
946 out[4] = 0x61;
947 out[5] = 0x22;
948 out[6] = 0;
949 out[7] = 0;
950 out[8] = 64;
951 out[9] = 6;
952 out[10] = 0;
953 out[11] = 0;
954 out[12..16].copy_from_slice(&src_ip);
955 out[16..20].copy_from_slice(&dst_ip);
956
957 let ip_checksum = super::ipv4_header_checksum(&out[0..20]);
958 out[10] = (ip_checksum >> 8) as u8;
959 out[11] = ip_checksum as u8;
960
961 out[20] = (src_port >> 8) as u8;
962 out[21] = src_port as u8;
963 out[22] = (dst_port >> 8) as u8;
964 out[23] = dst_port as u8;
965 out[24] = (seq >> 24) as u8;
966 out[25] = (seq >> 16) as u8;
967 out[26] = (seq >> 8) as u8;
968 out[27] = seq as u8;
969 out[28] = (ack >> 24) as u8;
970 out[29] = (ack >> 16) as u8;
971 out[30] = (ack >> 8) as u8;
972 out[31] = ack as u8;
973 out[32] = ((tcp_hdr_len / 4) << 4) as u8;
974 out[33] = flags;
975 out[34] = 0x20;
1005 out[35] = 0x00;
1006 out[36] = 0x00;
1007 out[37] = 0x00;
1008 out[38] = 0x00;
1009 out[39] = 0x00;
1010
1011 let mut payload_start = 40;
1012 if opt_len > 0 {
1013 out[40] = 2;
1014 out[41] = 4;
1015 out[42] = 0x05;
1016 out[43] = 0xB4;
1017 payload_start += 4;
1018 }
1019 let payload_end = payload_start + payload.len();
1020 out[payload_start..payload_end].copy_from_slice(payload);
1021
1022 let mut tcp_csum_buf = alloc::vec![0u8; 12 + tcp_len];
1023 tcp_csum_buf[0..4].copy_from_slice(&src_ip);
1024 tcp_csum_buf[4..8].copy_from_slice(&dst_ip);
1025 tcp_csum_buf[8] = 0;
1026 tcp_csum_buf[9] = 6;
1027 tcp_csum_buf[10] = ((tcp_len >> 8) & 0xFF) as u8;
1028 tcp_csum_buf[11] = (tcp_len & 0xFF) as u8;
1029 tcp_csum_buf[12..12 + tcp_len].copy_from_slice(&out[20..total_len]);
1030
1031 let csum = super::ipv4_header_checksum(&tcp_csum_buf);
1032 out[36] = (csum >> 8) as u8;
1033 out[37] = csum as u8;
1034
1035 let sent = super::arp::transmit_nic_ipv4_packet(&out[..total_len])?;
1036 Ok(sent)
1037}
1038
1039fn tcp_state_name(state: super::TcpState) -> &'static str {
1040 super::tcp_state::tcp_state_name(state)
1041}