1#![no_std]
8#[cfg(feature = "alloc")]
9extern crate alloc;
10#[cfg(any(feature = "std", test))]
11extern crate std;
12
13use core::time::Duration;
14
15use num_enum::{IntoPrimitive, TryFromPrimitive};
16
17use bitflags::bitflags;
18use ffi::{csp_conn_s, csp_packet_s, csp_socket_s};
19pub use libcsp_sys as ffi;
20
21#[derive(Debug, PartialEq, Eq, Copy, Clone)]
22pub enum ReservedPort {
23 Cmp = 0,
24 Ping = 1,
25 Ps = 2,
26 Memfree = 3,
27 Reboot = 4,
28 BufFree = 5,
29 Uptime = 6,
30}
31
32#[derive(Debug, PartialEq, Eq, Copy, Clone, TryFromPrimitive, IntoPrimitive)]
33#[repr(i32)]
34pub enum CspError {
35 None = 0,
36 NoMem = -1,
37 Inval = -2,
38 TimedOut = -3,
39 Used = -4,
40 NotSup = -5,
41 Busy = -6,
42 Already = -7,
43 Reset = -8,
44 NoBufs = -9,
45 Tx = -10,
46 Driver = -11,
47 Again = -12,
48 NoSys = -38,
49 Hmac = -100,
50 Crc32 = -102,
51 Sfp = -103,
52}
53
54pub const CSP_ANY: u8 = 255;
56pub const CSP_LOOPBACK: u16 = 0;
57
58bitflags! {
59 pub struct SocketFlags: u32 {
60 const NONE = 0x0000;
61 const RDPREQ = 0x0001;
63 const RDPPROHIB = 0x0002;
65 const HMACREQ = 0x0004;
67 const HMACPROHIB = 0x0008;
69 const CRC32REQ = 0x0040;
71 const CRC32PROHIB = 0x0080;
72 const CONN_LESS = 0x0100;
73 const SAME = 0x8000;
75
76 const _ = !0;
78 }
79}
80
81bitflags! {
82 pub struct ConnectOpts: u32 {
83 const NONE = SocketFlags::NONE.bits();
84
85 const RDP = SocketFlags::RDPREQ.bits();
86 const NORDP = SocketFlags::RDPPROHIB.bits();
87 const HMAC = SocketFlags::HMACREQ.bits();
88 const NOHMAC = SocketFlags::HMACPROHIB.bits();
89 const CRC32 = SocketFlags::CRC32REQ.bits();
90 const NOCRC32 = SocketFlags::CRC32PROHIB.bits();
91 const SAME = SocketFlags::SAME.bits();
92
93 const _ = !0;
95 }
96}
97
98#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
99#[repr(u8)]
100pub enum ConnState {
101 Closed = 0,
102 Open = 1,
103}
104
105#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
106#[repr(u8)]
107pub enum ConnType {
108 Client = 0,
109 Server = 1,
110}
111
112#[derive(Debug, Copy, Clone, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
113#[repr(u32)]
114pub enum RdpState {
115 Closed = 0,
116 SynSent = 1,
117 SynRcvd = 2,
118 Open = 3,
119 CloseWait = 4,
120}
121
122#[derive(Debug, PartialEq, Eq, Copy, Clone, TryFromPrimitive, IntoPrimitive)]
123#[repr(u8)]
124pub enum MsgPriority {
125 Critical = 0,
126 High = 1,
127 Normal = 2,
128 Low = 3,
129}
130
131pub struct CspPacket(pub csp_packet_s);
132
133pub struct CspPacketRef(*mut csp_packet_s);
134
135pub struct CspPacketMut(*mut csp_packet_s);
136
137impl From<CspPacketMut> for CspPacketRef {
138 fn from(value: CspPacketMut) -> Self {
139 Self(value.0)
140 }
141}
142
143impl CspPacketRef {
144 pub fn packet_data(&self) -> &[u8] {
145 unsafe { &(*self.0).packet_data_union.data[..self.packet_length()] }
146 }
147
148 pub fn whole_data(&self) -> &[u8; ffi::CSP_BUFFER_SIZE] {
149 unsafe { &(*self.0).packet_data_union.data }
150 }
151
152 pub fn packet_length(&self) -> usize {
153 unsafe { (*self.0).length.into() }
154 }
155
156 pub fn inner(&self) -> *const csp_packet_s {
157 self.0
158 }
159}
160
161pub struct CspPacketRefGuard(Option<CspPacketRef>);
162
163impl Drop for CspPacketRefGuard {
164 fn drop(&mut self) {
165 if let Some(packet) = self.0.take() {
166 csp_buffer_free(packet)
167 }
168 }
169}
170
171impl CspPacketRefGuard {
172 pub fn take(mut self) -> CspPacketRef {
174 self.0.take().unwrap()
175 }
176}
177
178impl AsRef<CspPacketRef> for CspPacketRefGuard {
179 fn as_ref(&self) -> &CspPacketRef {
180 self.0.as_ref().unwrap()
181 }
182}
183
184impl CspPacketMut {
185 pub fn packet_data(&self) -> &[u8] {
186 unsafe { &(*self.0).packet_data_union.data[..self.packet_length()] }
187 }
188
189 pub fn whole_data(&self) -> &[u8; ffi::CSP_BUFFER_SIZE] {
190 unsafe { &(*self.0).packet_data_union.data }
191 }
192
193 pub fn packet_length(&self) -> usize {
194 unsafe { (*self.0).length.into() }
195 }
196
197 pub fn inner(&self) -> *const csp_packet_s {
198 self.0
199 }
200
201 pub fn whole_data_mut(&mut self) -> &mut [u8; ffi::CSP_BUFFER_SIZE] {
202 unsafe { &mut (*self.0).packet_data_union.data }
203 }
204
205 pub fn set_data(&mut self, data: &[u8]) -> bool {
206 if data.len() > self.whole_data().len() {
207 return false;
208 }
209 self.whole_data_mut()[0..data.len()].copy_from_slice(data);
210 unsafe {
211 (*self.0).length = data.len() as u16;
212 }
213 true
214 }
215
216 pub fn inner_mut(&self) -> *mut csp_packet_s {
217 self.0
218 }
219}
220
221impl CspPacket {
222 pub fn new() -> Self {
223 Self::default()
224 }
225}
226
227impl Default for CspPacket {
228 fn default() -> Self {
229 Self(csp_packet_s {
230 packet_info: Default::default(),
231 length: Default::default(),
232 id: Default::default(),
233 next: core::ptr::null_mut(),
234 header: Default::default(),
235 packet_data_union: Default::default(),
236 })
237 }
238}
239
240#[derive(Default)]
241pub struct CspSocket(pub csp_socket_s);
242
243impl CspSocket {
244 pub fn inner_as_mut_ptr(&mut self) -> *mut csp_socket_s {
245 &mut self.0
246 }
247}
248
249pub unsafe fn csp_init() {
255 unsafe {
257 ffi::csp_init();
258 }
259}
260
261pub fn csp_bind(socket: &mut CspSocket, port: u8) {
263 unsafe {
265 ffi::csp_bind(socket.inner_as_mut_ptr(), port);
266 }
267}
268
269pub fn csp_listen(socket: &mut CspSocket, backlog: usize) {
271 unsafe {
273 ffi::csp_listen(socket.inner_as_mut_ptr(), backlog);
274 }
275}
276
277pub fn csp_route_work_raw() -> i32 {
279 unsafe { ffi::csp_route_work() }
280}
281
282pub fn csp_route_work() -> Result<(), CspError> {
288 let result = unsafe { ffi::csp_route_work() };
289 if result == CspError::None as i32 {
290 return Ok(());
291 }
292 Err(CspError::try_from(result)
293 .unwrap_or_else(|_| panic!("unexpected error value {} from csp_route_work", result)))
294}
295
296#[derive(Debug, Copy, Clone)]
297pub struct CspConnRef(*mut csp_conn_s);
298
299impl CspConnRef {
300 pub fn inner(&mut self) -> Option<&csp_conn_s> {
301 unsafe { self.0.as_ref() }
303 }
304
305 pub fn inner_mut(&mut self) -> Option<&mut csp_conn_s> {
306 unsafe { self.0.as_mut() }
308 }
309}
310
311pub struct CspConnGuard(pub CspConnRef);
312
313impl Drop for CspConnGuard {
314 fn drop(&mut self) {
315 csp_close(self.0);
316 }
317}
318
319impl AsRef<CspConnRef> for CspConnGuard {
320 fn as_ref(&self) -> &CspConnRef {
321 &self.0
322 }
323}
324
325impl AsMut<CspConnRef> for CspConnGuard {
326 fn as_mut(&mut self) -> &mut CspConnRef {
327 &mut self.0
328 }
329}
330
331#[derive(Default)]
332pub struct CspInterface(pub ffi::csp_iface_t);
333
334impl CspInterface {
335 pub fn new(host_addr: u16, is_default: bool) -> Self {
336 Self(ffi::csp_iface_t {
337 addr: host_addr,
338 netmask: Default::default(),
339 name: core::ptr::null(),
340 interface_data: core::ptr::null_mut(),
341 driver_data: core::ptr::null_mut(),
342 nexthop: None,
343 is_default: is_default as u8,
344 tx: Default::default(),
345 rx: Default::default(),
346 tx_error: Default::default(),
347 rx_error: Default::default(),
348 drop: Default::default(),
349 autherr: Default::default(),
350 frame: Default::default(),
351 txbytes: Default::default(),
352 rxbytes: Default::default(),
353 irq: Default::default(),
354 next: core::ptr::null_mut(),
355 })
356 }
357}
358
359#[derive(Default)]
360pub struct CspUdpConf(pub ffi::csp_if_udp_conf_t);
361
362impl CspUdpConf {
363 pub fn new(addr: &'static str, lport: u16, rport: u16) -> Self {
364 Self(ffi::csp_if_udp_conf_t {
365 host: addr.as_ptr() as *mut i8,
366 lport: lport.into(),
367 rport: rport.into(),
368 server_handle: Default::default(),
369 peer_addr: libc::sockaddr_in {
370 sin_family: Default::default(),
371 sin_port: Default::default(),
372 sin_addr: libc::in_addr {
373 s_addr: Default::default(),
374 },
375 sin_zero: Default::default(),
376 },
377 sockfd: Default::default(),
378 })
379 }
380}
381
382pub fn csp_accept_guarded(socket: &mut CspSocket, timeout: Duration) -> Option<CspConnGuard> {
383 Some(CspConnGuard(csp_accept(socket, timeout)?))
384}
385
386pub fn csp_accept(socket: &mut CspSocket, timeout: Duration) -> Option<CspConnRef> {
388 let timeout_millis = timeout.as_millis();
389 if timeout_millis > u32::MAX as u128 {
390 return None;
391 }
392 Some(CspConnRef(unsafe {
393 let addr = ffi::csp_accept(socket.inner_as_mut_ptr(), timeout_millis as u32);
394 if addr.is_null() {
395 return None;
396 }
397 addr
398 }))
399}
400
401pub fn csp_read(conn: &mut CspConnRef, timeout: Duration) -> Option<CspPacketRef> {
403 let timeout_millis = timeout.as_millis();
404 if timeout_millis > u32::MAX as u128 {
405 return None;
406 }
407 let opt_packet = unsafe { ffi::csp_read(conn.0, timeout_millis as u32) };
408 if opt_packet.is_null() {
409 return None;
410 }
411 Some(CspPacketRef(unsafe { &mut *opt_packet }))
413}
414
415pub fn csp_read_guarded(conn: &mut CspConnRef, timeout: Duration) -> Option<CspPacketRefGuard> {
418 Some(CspPacketRefGuard(Some(csp_read(conn, timeout)?)))
419}
420
421pub fn csp_recvfrom(socket: &mut CspSocket, timeout: u32) -> Option<CspPacketRef> {
423 let opt_packet = unsafe { ffi::csp_recvfrom(&mut socket.0, timeout) };
424 if opt_packet.is_null() {
425 return None;
426 }
427 Some(CspPacketRef(unsafe { &mut *opt_packet }))
428}
429
430pub fn csp_recvfrom_guarded(socket: &mut CspSocket, timeout: u32) -> Option<CspPacketRefGuard> {
433 Some(CspPacketRefGuard(Some(csp_recvfrom(socket, timeout)?)))
434}
435
436pub fn csp_conn_dport(conn: &CspConnRef) -> i32 {
438 unsafe { ffi::csp_conn_dport(conn.0) }
440}
441
442pub fn csp_conn_sport(conn: &CspConnRef) -> i32 {
444 unsafe { ffi::csp_conn_sport(conn.0) }
446}
447
448pub fn csp_conn_dst(conn: &CspConnRef) -> i32 {
450 unsafe { ffi::csp_conn_dst(conn.0) }
452}
453
454pub fn csp_conn_src(conn: &CspConnRef) -> i32 {
456 unsafe { ffi::csp_conn_src(conn.0) }
458}
459
460pub fn csp_conn_flags(conn: &CspConnRef) -> i32 {
462 unsafe { ffi::csp_conn_flags(conn.0) }
464}
465
466pub fn csp_conn_flags_typed(conn: &CspConnRef) -> Option<ConnectOpts> {
469 let flags_raw = csp_conn_flags(conn);
470 if flags_raw < 0 {
471 return None;
472 }
473 ConnectOpts::from_bits(flags_raw as u32)
475}
476
477pub fn csp_service_handler(packet: CspPacketRef) {
478 unsafe { ffi::csp_service_handler(&mut *packet.0) }
480}
481
482pub fn csp_close(conn: CspConnRef) -> i32 {
484 unsafe { ffi::csp_close(conn.0) }
486}
487
488pub fn csp_ping_raw(node: u16, timeout: Duration, size: usize, opts: SocketFlags) -> i32 {
490 unsafe {
492 ffi::csp_ping(
493 node,
494 timeout.as_millis() as u32,
495 size as u32,
496 opts.bits() as u8,
497 )
498 }
499}
500
501#[derive(Debug, Copy, Clone, PartialEq, Eq)]
502pub struct PingError;
503
504pub fn csp_ping(
506 node: u16,
507 timeout: Duration,
508 size: usize,
509 opts: SocketFlags,
510) -> Result<Duration, PingError> {
511 let result = csp_ping_raw(node, timeout, size, opts);
512 if result < 0 {
513 return Err(PingError);
514 }
515 Ok(Duration::from_millis(result as u64))
516}
517
518pub fn csp_reboot(node: u16) {
520 unsafe { ffi::csp_reboot(node) }
522}
523
524pub fn csp_connect(
526 prio: MsgPriority,
527 dst: u16,
528 dst_port: u8,
529 timeout: Duration,
530 opts: ConnectOpts,
531) -> Option<CspConnRef> {
532 let conn = unsafe {
534 ffi::csp_connect(
535 prio as u8,
536 dst,
537 dst_port,
538 timeout.as_millis() as u32,
539 opts.bits(),
540 )
541 };
542 if conn.is_null() {
543 return None;
544 }
545 Some(CspConnRef(conn))
547}
548
549pub fn csp_connect_guarded(
552 prio: MsgPriority,
553 dst: u16,
554 dst_port: u8,
555 timeout: Duration,
556 opts: ConnectOpts,
557) -> Option<CspConnGuard> {
558 Some(CspConnGuard(csp_connect(
559 prio, dst, dst_port, timeout, opts,
560 )?))
561}
562
563pub fn csp_buffer_get() -> Option<CspPacketMut> {
565 let packet_ref = unsafe {
566 ffi::csp_buffer_get(0)
568 };
569 if packet_ref.is_null() {
570 return None;
571 }
572 Some(CspPacketMut(unsafe { &mut *packet_ref }))
574}
575
576pub fn csp_send(conn: &mut CspConnRef, packet: impl Into<CspPacketRef>) {
578 unsafe { ffi::csp_send(conn.0, packet.into().0) }
580}
581
582pub fn csp_conn_print_table() {
584 unsafe { ffi::csp_conn_print_table() }
586}
587
588pub fn csp_buffer_free(packet: impl Into<CspPacketRef>) {
590 unsafe { ffi::csp_buffer_free(packet.into().0 as *mut libc::c_void) }
593}
594
595pub fn csp_transaction_persistent(
605 conn: &mut CspConnRef,
606 timeout: Duration,
607 out_data: &[u8],
608 in_data: &mut [u8],
609 in_len: Option<usize>,
610) -> i32 {
611 unsafe {
612 ffi::csp_transaction_persistent(
613 conn.0,
614 timeout.as_millis() as u32,
615 out_data.as_ptr() as *const core::ffi::c_void,
616 out_data.len() as i32,
617 in_data.as_ptr() as *mut core::ffi::c_void,
618 in_len.map(|v| v as i32).unwrap_or(-1),
619 )
620 }
621}
622
623#[allow(clippy::too_many_arguments)]
633pub fn csp_transaction_w_opts(
634 prio: MsgPriority,
635 dst: u16,
636 dst_port: u8,
637 timeout: Duration,
638 out_data: &[u8],
639 in_data: &mut [u8],
640 in_len: Option<usize>,
641 opts: ConnectOpts,
642) -> i32 {
643 unsafe {
644 ffi::csp_transaction_w_opts(
645 prio as u8,
646 dst,
647 dst_port,
648 timeout.as_millis() as u32,
649 out_data.as_ptr() as *const core::ffi::c_void,
650 out_data.len() as i32,
651 in_data.as_ptr() as *mut core::ffi::c_void,
652 in_len.map(|v| v as i32).unwrap_or(-1),
653 opts.bits(),
654 )
655 }
656}
657
658pub fn csp_transaction(
660 prio: MsgPriority,
661 dst: u16,
662 dst_port: u8,
663 timeout: Duration,
664 out_data: &[u8],
665 in_data: &mut [u8],
666 in_len: Option<usize>,
667) -> i32 {
668 csp_transaction_w_opts(
669 prio,
670 dst,
671 dst_port,
672 timeout,
673 out_data,
674 in_data,
675 in_len,
676 ConnectOpts::NONE,
677 )
678}
679
680pub mod udp {
681 use super::*;
682
683 pub fn csp_if_udp_init(iface: &mut CspInterface, ifconf: &mut CspUdpConf) {
685 unsafe { ffi::udp::csp_if_udp_init(&mut iface.0, &mut ifconf.0) }
686 }
687}
688
689pub mod iflist {
690 use super::*;
691
692 pub fn csp_iflist_print() {
694 unsafe { ffi::iflist::csp_iflist_print() }
696 }
697
698 pub fn csp_iflist_add(iface: &mut CspInterface) -> i32 {
700 unsafe { ffi::iflist::csp_iflist_add(&mut iface.0) }
701 }
702}