summaryrefslogtreecommitdiff
path: root/libhw_generic/include/libhw/generic/net.h
blob: 150d199cb52f52e8302bf3e61f75a6a2a43c5c55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/* libhw/generic/net.h - Device-independent network definitions
 *
 * Copyright (C) 2024  Luke T. Shumaker <lukeshu@lukeshu.com>
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

#ifndef _LIBHW_GENERIC_NET_H_
#define _LIBHW_GENERIC_NET_H_

#include <stdbool.h>   /* for bool */
#include <stddef.h>    /* for size_t */
#include <stdint.h>    /* for uint{n}_t} */
#include <sys/types.h> /* for ssize_t */

/* Errnos *********************************************************************/

#define NET_EOTHER              1
#define NET_EARP_TIMEOUT        2
#define NET_EACK_TIMEOUT        3
#define NET_ERECV_TIMEOUT       4
#define NET_ETHREAD             5
#define NET_ECLOSED             6
#define NET_EMSGSIZE            7

/* Address types **************************************************************/

struct net_ip4_addr {
	unsigned char   octets[4];
};

static const struct net_ip4_addr net_ip4_addr_broadcast = {{255, 255, 255, 255}};
static const struct net_ip4_addr net_ip4_addr_zero      = {{0, 0, 0, 0}};

struct net_eth_addr {
	unsigned char   octets[6];
};

/* Streams (e.g. TCP) *********************************************************/

struct net_stream_listener_vtable;
struct net_stream_conn_vtable;

typedef struct {
	struct net_stream_listener_vtable       *vtable;
} implements_net_stream_listener;

typedef struct {
	struct net_stream_conn_vtable           *vtable;
} implements_net_stream_conn;

struct net_stream_listener_vtable {
	/**
	 * It is invalid to accept() a new connection if an existing
	 * connection is still open.
	 */
	implements_net_stream_conn *(*accept)(implements_net_stream_listener *self);

	/**
	 * The net_stream_conn returned from accept() may still be
	 * valid after the listener is closed.
	 *
	 * Return 0 on success, -errno on error.
	 */
	int                         (*close)(implements_net_stream_listener *self);
};

struct net_stream_conn_vtable {
	/**
	 * Return bytes-read on success, 0 on EOF, -errno on error; a
	 * short read is *not* an error.
	 */
	ssize_t                  (*read)(implements_net_stream_conn *self,
	                                 void *buf, size_t count);

	/**
	 * Set a timestamp after which calls to read() will return
	 * NET_ETIMEDOUT.  The timestamp is in nanoseconds on the
	 * system monotonic clock, which is usually (on pico-sdk and
	 * on the Linux kernel) nanoseconds-since-boot.
	 *
	 * A zero value disables the deadline.
	 *
	 * (2⁶⁴-1 nanoseconds is more than 500 years; there is little
	 * risk of this overflowing)
	 */
	void                     (*set_read_deadline)(implements_net_stream_conn *self,
	                                              uint64_t ns_since_boot);

	/**
	 * Return `count` on success, -errno on error; a short write *is* an
	 * error.
	 *
	 * Writes are *not* guaranteed to be atomic (as this would be
	 * expensive to implement), so if you have concurrent writers then you
	 * should arrange for a mutex to protect the connection.
	 */
	ssize_t                  (*write)(implements_net_stream_conn *self,
	                                  void *buf, size_t count);

	/**
	 * Return 0 on success, -errno on error.
	 */
	int                      (*close)(implements_net_stream_conn *self,
	                                  bool rd, bool wr);
};

/* Packets (e.g. UDP) *********************************************************/

struct net_packet_conn_vtable;

typedef struct {
	struct net_packet_conn_vtable           *vtable;
} implements_net_packet_conn;

struct net_packet_conn_vtable {
	ssize_t (*sendto  )(implements_net_packet_conn *self,
	                    void *buf, size_t len,
	                    struct net_ip4_addr node, uint16_t port);
	/**
	 * @return The full length of the message, which may be more
	 * than the given `len` (as if the Linux MSG_TRUNC flag were
	 * given).
	 */
	ssize_t (*recvfrom)(implements_net_packet_conn *self,
	                    void *buf, size_t len,
	                    struct net_ip4_addr *ret_node, uint16_t *ret_port);
	void    (*set_read_deadline)(implements_net_packet_conn *self,
	                             uint64_t ns_since_boot);
	int     (*close   )(implements_net_packet_conn *self);
};

/* Interfaces *****************************************************************/

struct net_iface_config {
	struct net_ip4_addr addr;
	struct net_ip4_addr gateway_addr;
	struct net_ip4_addr subnet_mask;
};

struct net_iface_vtable;

typedef struct {
	struct net_iface_vtable        *vtable;
} implements_net_iface;

struct net_iface_vtable {
	struct net_eth_addr             (*hwaddr    )(implements_net_iface *);
	void                            (*ifup      )(implements_net_iface *, struct net_iface_config);
	void                            (*ifdown    )(implements_net_iface *);

	implements_net_stream_listener *(*tcp_listen)(implements_net_iface *, uint16_t local_port);
	implements_net_stream_conn     *(*tcp_dial  )(implements_net_iface *, struct net_ip4_addr remote_node, uint16_t remote_port);
	implements_net_packet_conn     *(*udp_conn  )(implements_net_iface *, uint16_t local_port);
};

#endif /* _LIBHW_GENERIC_NET_H_ */