AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
ipv4.c
Go to the documentation of this file.
1
10
11#include <core/system.h>
12#include <core/string.h>
13#include <net/byteorder.h>
14#include <net/inet.h>
15#include <net/tcp.h>
16
17#include <aquila/errno.h>
18
20
21static const uint8_t ether_broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
22
24static int on_link(struct netif *netif, uint32_t ip)
25{
26 return (ip & netif->netmask) == (netif->ip & netif->netmask);
27}
28
30static int is_broadcast(struct netif *netif, uint32_t ip)
31{
32 return ip == 0xffffffff || ip == (netif->ip | ~netif->netmask);
33}
34
37{
38 return (ntohl(ip) >> 24) == 127;
39}
40
49{
50 if (is_loopback(ip))
51 return 1;
52
53 for (struct netif *netif = netifs; netif; netif = netif->next)
54 if (netif->ip && netif->ip == ip)
55 return 1;
56
57 return 0;
58}
59
70{
71 return ipv4_is_local(dst) ? dst : netif->ip;
72}
73
84void ipv4_input(struct netif *netif, struct netbuf *nb, const uint8_t src_mac[6])
85{
86 struct ipv4_hdr *ih = (struct ipv4_hdr *) nb->data;
87 size_t hlen = (ih->ver_ihl & 0xf) * 4;
88
89 if (nb->len < sizeof(*ih) || (ih->ver_ihl >> 4) != 4 || hlen < sizeof(*ih) ||
90 hlen > nb->len || ntohs(ih->len) < hlen || ntohs(ih->len) > nb->len ||
91 inet_checksum(ih, hlen)) {
92 netif->stats.rx_errors++;
93 goto drop;
94 }
95
96 /* keep it only if it is for us (the interface's address, another of
97 * ours, or a broadcast), and not a fragment */
98 if (ih->dst != netif->ip && !ipv4_is_local(ih->dst) && !is_broadcast(netif, ih->dst))
99 goto drop;
100
101 if (ntohs(ih->frag) & 0x3fff) /* more fragments, or an offset */
102 goto drop;
103
104 /* learn the sender's hardware address, if it is on the link (lo has
105 * none) */
106 if (!(netif->flags & NETIF_LOOPBACK) && on_link(netif, ih->src))
107 arp_update(netif, ih->src, src_mac);
108
109 /* pass on the payload: take off the header (it stays in the buffer
110 * before the payload, for ICMP errors) and the frame's padding */
111 nb->len = ntohs(ih->len);
112 netbuf_pull(nb, hlen);
113
114 switch (ih->proto) {
115 case IP_PROTO_ICMP:
116 icmp_input(netif, nb, ih->src, ih->dst);
117 return;
118 case IP_PROTO_UDP:
119 udp_input(netif, nb, ih);
120 return;
121 case IP_PROTO_TCP:
122 tcp_input(netif, nb, ih);
123 return;
124 }
125
126 /* no such protocol */
127 if (!is_broadcast(netif, ih->dst))
128 icmp_unreachable(netif, ih, 2);
129
130drop:
131 netif->stats.rx_dropped++;
132 netbuf_free(nb);
133}
134
143{
144 struct netif *gw = NULL;
145
146 for (struct netif *netif = netifs; netif; netif = netif->next) {
147 if (!(netif->flags & NETIF_UP))
148 continue;
149
150 /* lo takes 127.0.0.0/8, and nothing else */
151 if (netif->flags & NETIF_LOOPBACK) {
152 if (is_loopback(dst))
153 return netif;
154 continue;
155 }
156
157 /* a broadcast can go out of an interface that has no address yet
158 * (a DHCP client's, from 0.0.0.0) */
159 if (dst == 0xffffffff)
160 return netif;
161
162 if (!netif->ip)
163 continue;
164
165 /* on its link, or the interface's own address */
166 if (on_link(netif, dst) || dst == netif->ip)
167 return netif;
168
169 if (!gw && netif->gateway)
170 gw = netif;
171 }
172
173 return gw;
174}
175
190int ipv4_output(struct netif *netif, uint32_t src, uint32_t dst, uint8_t proto, struct netbuf *nb)
191{
192 struct ipv4_hdr *ih = netbuf_push(nb, sizeof(*ih));
193
194 ih->ver_ihl = 0x45;
195 ih->tos = 0;
196 ih->len = htons(nb->len);
197 ih->id = htons(ip_id++);
198 ih->frag = htons(0x4000); /* don't fragment */
199 ih->ttl = 64;
200 ih->proto = proto;
201 ih->checksum = 0;
202 ih->src = src ? src : ipv4_source(netif, dst);
203 ih->dst = dst;
204 ih->checksum = inet_checksum(ih, sizeof(*ih));
205
206 /* a packet to ourselves comes back in without going on the wire. It
207 * comes in from the network's thread, not from here: otherwise TCP's
208 * answer would come back into the connection while it is sending */
209 if (ipv4_is_local(dst)) {
210 netif->stats.tx_packets++;
212 return 0;
213 }
214
215 if (is_broadcast(netif, dst))
217
219 uint8_t mac[6];
220
221 if (!hop) {
222 netif->stats.tx_dropped++;
223 netbuf_free(nb);
224 return -ENETUNREACH;
225 }
226
227 /* if the hardware address isn't known yet, the packet waits for ARP's
228 * answer */
229 if (arp_lookup(netif, hop, mac))
230 return arp_resolve(netif, hop, nb);
231
232 return ether_output(netif, mac, ETHER_TYPE_IPV4, nb);
233}
234
245{
246 struct netif *netif = ipv4_route(dst);
247
248 if (!netif) {
249 netbuf_free(nb);
250 return -ENETUNREACH;
251 }
252
253 return ipv4_output(netif, 0, dst, proto, nb);
254}
static const uint8_t ether_broadcast[6]
Definition arp.c:53
#define htons(x)
Definition byteorder.h:10
#define ntohl(x)
Definition byteorder.h:18
#define ntohs(x)
Definition byteorder.h:17
int ether_output(struct netif *netif, const uint8_t dst[6], uint16_t type, struct netbuf *nb)
Sends a frame: adds its Ethernet header and gives it to the interface.
Definition ether.c:54
uint16_t inet_checksum(const void *data, size_t len)
Computes the Internet checksum (RFC 1071): the ones' complement of the ones' complement sum of the da...
Definition ether.c:76
void icmp_input(struct netif *netif, struct netbuf *nb, uint32_t src, uint32_t dst)
Takes in an ICMP message that IPv4 received.
Definition icmp.c:50
struct netif * ipv4_route(uint32_t dst)
Chooses the interface to send a packet to dst through: the one whose link it is on,...
Definition ipv4.c:142
void arp_update(struct netif *netif, uint32_t ip, const uint8_t mac[6])
Records an address's hardware address, replacing the oldest entry if the table is full,...
Definition arp.c:185
int arp_resolve(struct netif *netif, uint32_t ip, struct netbuf *nb)
Holds a packet until the hardware address of its next hop is known, and asks for it.
Definition arp.c:118
void ipv4_input(struct netif *netif, struct netbuf *nb, const uint8_t src_mac[6])
Takes in an IPv4 packet that an interface received, and passes it to its protocol.
Definition ipv4.c:84
#define IP_PROTO_TCP
Definition inet.h:42
int ipv4_send(uint32_t dst, uint8_t proto, struct netbuf *nb)
Sends a packet to dst, through the interface its route says.
Definition ipv4.c:244
#define IP_PROTO_UDP
Definition inet.h:43
int ipv4_is_local(uint32_t ip)
Says whether an address is one of ours: a loopback address, or an interface's.
Definition ipv4.c:48
void icmp_unreachable(struct netif *netif, const struct ipv4_hdr *ih, int code)
Tells the sender of a datagram that it couldn't get where it was sent.
Definition icmp.c:105
#define IP_PROTO_ICMP
Definition inet.h:41
uint32_t ipv4_source(struct netif *netif, uint32_t dst)
Chooses the source address of a packet to dst sent through netif.
Definition ipv4.c:69
#define ETHER_TYPE_IPV4
Definition inet.h:17
int ipv4_output(struct netif *netif, uint32_t src, uint32_t dst, uint8_t proto, struct netbuf *nb)
Sends a packet through an interface: adds its IPv4 header and sends it to dst, or to the gateway if d...
Definition ipv4.c:190
void udp_input(struct netif *netif, struct netbuf *nb, const struct ipv4_hdr *ih)
Takes in a UDP datagram that IPv4 received, and delivers it to its socket.
Definition udp.c:24
int arp_lookup(struct netif *netif, uint32_t ip, uint8_t mac[6])
Looks up an address's hardware address.
Definition arp.c:218
static uint16_t ip_id
Definition ipv4.c:19
static int is_loopback(uint32_t ip)
Returns whether ip is a loopback address (127.0.0.0/8).
Definition ipv4.c:36
static int is_broadcast(struct netif *netif, uint32_t ip)
Returns whether ip is a broadcast address on netif's link.
Definition ipv4.c:30
static int on_link(struct netif *netif, uint32_t ip)
Returns whether ip is on netif's link (its network).
Definition ipv4.c:24
static void * netbuf_push(struct netbuf *nb, size_t size)
Makes room for a header of size bytes before the data, and returns it.
Definition netbuf.h:52
static void * netbuf_pull(struct netbuf *nb, size_t size)
Takes the header of size bytes off the front of the packet, and returns it, or NULL if the packet is ...
Definition netbuf.h:64
void netbuf_free(struct netbuf *nb)
Frees a netbuf.
Definition netbuf.c:99
#define NETIF_LOOPBACK
Definition netif.h:10
#define NETIF_UP
Definition netif.h:8
struct netif * netifs
Definition netif.c:34
void netif_loopback(struct netif *netif, struct netbuf *nb)
Hands the stack an IPv4 packet sent to one of our own addresses, as if it had come in through an inte...
Definition netif.c:340
#define NULL
Definition stddef.h:27
unsigned int uint32_t
Definition stddef.h:22
unsigned char uint8_t
Definition stddef.h:20
unsigned short int uint16_t
Definition stddef.h:21
An IPv4 packet's header.
Definition inet.h:46
uint16_t len
Definition inet.h:49
uint8_t ttl
Definition inet.h:52
uint16_t id
Definition inet.h:50
uint8_t tos
Definition inet.h:48
uint32_t dst
Definition inet.h:56
uint16_t checksum
Definition inet.h:54
uint8_t ver_ihl
Definition inet.h:47
uint8_t proto
Definition inet.h:53
uint16_t frag
Definition inet.h:51
uint32_t src
Definition inet.h:55
A packet (net/netbuf.c).
Definition netbuf.h:16
uint8_t * data
Definition netbuf.h:19
size_t len
Definition netbuf.h:20
A network interface (net/netif.c): a device that sends and receives Ethernet frames,...
Definition netif.h:16
int flags
Definition netif.h:20
uint32_t ip
Definition netif.h:24
uint32_t netmask
Definition netif.h:24
struct netif::@020302303320120142126121344055047003105154122231 stats
uint32_t gateway
Definition netif.h:24
struct netif * next
Definition netif.h:37
void tcp_input(struct netif *netif, struct netbuf *nb, const struct ipv4_hdr *ih)
Takes in a TCP segment that IPv4 received, and passes it to its connection or listener.
Definition tcp_input.c:585