AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
arp.c
Go to the documentation of this file.
1
12
13#include <core/system.h>
14#include <core/string.h>
15#include <net/byteorder.h>
16#include <net/inet.h>
17#include <sys/callout.h>
18#include <core/arch.h>
19
20#include <aquila/errno.h>
21
22#define ARP_ENTRIES 32
23
24/* how long an entry is good for after it was last heard from, as on the
25 * BSDs */
26#define ARP_EXPIRE (20 * 60 * 1000ULL) /* ms */
27
28/* The table: an IPv4 address's hardware address, on an interface. */
29static struct arp_entry {
30 struct netif *netif;
33 uint32_t used; /* when it was last updated (clock), to replace the oldest */
34 uint64_t heard; /* the same, in ms since boot, to expire it */
36
38
39#define ARP_PENDING 8
40#define ARP_HOLD 3
41#define ARP_TRIES 3
42
43/* The addresses being asked for, with the packets waiting for them. */
52
53static const uint8_t ether_broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
54
56static void arp_request(struct netif *netif, uint32_t ip)
57{
58 struct netbuf *nb = netbuf_alloc();
59
60 if (!nb)
61 return;
62
63 struct arp_hdr *ah = netbuf_put(nb, sizeof(*ah));
64
65 ah->htype = htons(1);
67 ah->hlen = 6;
68 ah->plen = 4;
69 ah->op = htons(1);
70 memcpy(ah->sha, netif->mac, 6);
71 ah->spa = netif->ip;
72 memset(ah->tha, 0, 6);
73 ah->tpa = ip;
74
76}
77
80static void pending_drop(struct arp_pending *p)
81{
82 for (int i = 0; i < p->nheld; ++i) {
83 p->netif->stats.tx_dropped++;
84 netbuf_free(p->held[i]);
85 }
86
88 p->netif = NULL;
89 p->nheld = 0;
90}
91
94static void arp_retry(void *arg)
95{
96 struct arp_pending *p = arg;
97
98 if (++p->tries >= ARP_TRIES) {
99 pending_drop(p);
100 return;
101 }
102
103 arp_request(p->netif, p->ip);
104 net_callout_set(&p->retry, 1000000000ULL, arp_retry, p);
105}
106
118int arp_resolve(struct netif *netif, uint32_t ip, struct netbuf *nb)
119{
120 struct arp_pending *p = NULL, *free = NULL;
121
122 for (int i = 0; i < ARP_PENDING; ++i) {
123 if (pending[i].netif == netif && pending[i].ip == ip)
124 p = &pending[i];
125 else if (!pending[i].netif && !free)
126 free = &pending[i];
127 }
128
129 if (!p) {
130 if (!free) {
131 netif->stats.tx_dropped++;
132 netbuf_free(nb);
133 return -ENOBUFS;
134 }
135
136 p = free;
137 p->netif = netif;
138 p->ip = ip;
139 p->nheld = 0;
140 p->tries = 0;
141
143 net_callout_set(&p->retry, 1000000000ULL, arp_retry, p);
144 }
145
146 /* drop the oldest packet if too many wait */
147 if (p->nheld == ARP_HOLD) {
148 netif->stats.tx_dropped++;
149 netbuf_free(p->held[0]);
150 memmove(&p->held[0], &p->held[1], (ARP_HOLD - 1) * sizeof(p->held[0]));
151 p->nheld--;
152 }
153
154 p->held[p->nheld++] = nb;
155 return 0;
156}
157
159static void pending_flush(struct netif *netif, uint32_t ip, const uint8_t mac[6])
160{
161 for (int i = 0; i < ARP_PENDING; ++i) {
162 struct arp_pending *p = &pending[i];
163
164 if (p->netif != netif || p->ip != ip)
165 continue;
166
167 callout_stop(&p->retry);
168 p->netif = NULL;
169
170 for (int j = 0; j < p->nheld; ++j)
172
173 p->nheld = 0;
174 }
175}
176
185void arp_update(struct netif *netif, uint32_t ip, const uint8_t mac[6])
186{
187 struct arp_entry *slot = &table[0];
188
189 for (int i = 0; i < ARP_ENTRIES; ++i) {
190 if (table[i].netif == netif && table[i].ip == ip) {
191 slot = &table[i];
192 break;
193 }
194
195 /* otherwise, use the oldest entry */
197 slot = &table[i];
198 }
199
200 slot->netif = netif;
201 slot->ip = ip;
202 slot->used = ++clock;
203 slot->heard = arch_rtime_ms();
204 memcpy(slot->mac, mac, 6);
205
207}
208
219{
220 for (int i = 0; i < ARP_ENTRIES; ++i) {
221 if (table[i].netif == netif && table[i].ip == ip) {
222 /* too old: drop the entry, so that the address is asked for
223 * again */
224 if (arch_rtime_ms() - table[i].heard > ARP_EXPIRE) {
225 table[i].netif = NULL;
226 return -1;
227 }
228
229 memcpy(mac, table[i].mac, 6);
230 return 0;
231 }
232 }
233
234 return -1;
235}
236
244void arp_input(struct netif *netif, struct netbuf *nb)
245{
246 struct arp_hdr *ah = (struct arp_hdr *) nb->data;
247
248 if (nb->len < sizeof(*ah) || ntohs(ah->htype) != 1 ||
249 ntohs(ah->ptype) != ETHER_TYPE_IPV4 || ah->hlen != 6 || ah->plen != 4) {
250 netif->stats.rx_errors++;
251 netbuf_free(nb);
252 return;
253 }
254
255 if (ah->spa)
256 arp_update(netif, ah->spa, ah->sha);
257
258 /* a request for our address: turn it into the reply */
259 if (ntohs(ah->op) == 1 && netif->ip && ah->tpa == netif->ip) {
260 uint8_t requester[6];
261 memcpy(requester, ah->sha, 6);
262
263 ah->op = htons(2);
264 memcpy(ah->tha, ah->sha, 6);
265 ah->tpa = ah->spa;
266 memcpy(ah->sha, netif->mac, 6);
267 ah->spa = netif->ip;
268
269 nb->len = sizeof(*ah);
270 ether_output(netif, requester, ETHER_TYPE_ARP, nb);
271 return;
272 }
273
274 netbuf_free(nb);
275}
#define ARP_PENDING
Definition arp.c:39
#define ARP_TRIES
Definition arp.c:41
#define ARP_EXPIRE
Definition arp.c:26
static void arp_request(struct netif *netif, uint32_t ip)
Broadcasts a request: who has ip?
Definition arp.c:56
#define ARP_HOLD
Definition arp.c:40
static void pending_drop(struct arp_pending *p)
Gives up on an address being asked for: its waiting packets are dropped.
Definition arp.c:80
static void arp_retry(void *arg)
Asks again for an address that hasn't answered, a second after the last request, or gives up after AR...
Definition arp.c:94
static uint32_t clock
Definition arp.c:37
static void pending_flush(struct netif *netif, uint32_t ip, const uint8_t mac[6])
Sends the packets that waited for an address, now that it is known.
Definition arp.c:159
#define ARP_ENTRIES
Definition arp.c:22
static const uint8_t ether_broadcast[6]
Definition arp.c:53
static size_t used
Definition blkcache.c:68
#define htons(x)
Definition byteorder.h:10
#define ntohs(x)
Definition byteorder.h:17
void callout_stop(struct callout *c)
Cancels a callout, if it is pending.
Definition callout.c:23
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
#define ETHER_TYPE_ARP
Definition inet.h:18
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
#define ETHER_TYPE_IPV4
Definition inet.h:17
int arp_lookup(struct netif *netif, uint32_t ip, uint8_t mac[6])
Looks up an address's hardware address.
Definition arp.c:218
void arp_input(struct netif *netif, struct netbuf *nb)
Takes in an ARP packet: the sender's address is recorded, and a request for our address is answered.
Definition arp.c:244
void * memmove(void *dst, const void *src, size_t n)
Copies n bytes; dst and src may overlap.
Definition libc.c:34
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition libc.c:23
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
void netbuf_free(struct netbuf *nb)
Frees a netbuf.
Definition netbuf.c:99
struct netbuf * netbuf_alloc(void)
Allocates a netbuf, empty, with room for the headers that will be put in front of its data.
Definition netbuf.c:58
void net_callout_set(struct callout *c, uint64_t ns, void(*fn)(void *), void *arg)
Sets a callout that the network's thread runs: fn(arg) is called once ns ns have passed.
Definition netif.c:137
static uint64_t * table(paddr_t paddr)
Returns a page table, through the direct map.
Definition pmap.c:72
#define NULL
Definition stddef.h:27
unsigned int uint32_t
Definition stddef.h:22
unsigned char uint8_t
Definition stddef.h:20
unsigned long long int uint64_t
Definition stddef.h:23
Definition arp.c:29
uint32_t used
Definition arp.c:33
uint32_t ip
Definition arp.c:31
uint64_t heard
Definition arp.c:34
struct netif * netif
Definition arp.c:30
uint8_t mac[6]
Definition arp.c:32
An ARP packet, for IPv4 over Ethernet.
Definition inet.h:28
uint16_t ptype
Definition inet.h:30
uint16_t op
Definition inet.h:33
uint32_t tpa
Definition inet.h:37
uint8_t hlen
Definition inet.h:31
uint32_t spa
Definition inet.h:35
uint8_t plen
Definition inet.h:32
uint8_t sha[6]
Definition inet.h:34
uint16_t htype
Definition inet.h:29
uint8_t tha[6]
Definition inet.h:36
struct callout retry
Definition arp.c:50
int nheld
Definition arp.c:48
int tries
Definition arp.c:49
uint32_t ip
Definition arp.c:46
struct netbuf * held[ARP_HOLD]
Definition arp.c:47
struct netif * netif
Definition arp.c:45
A function to call later, with its argument.
Definition callout.h:13
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
uint32_t ip
Definition netif.h:24
struct netif::@020302303320120142126121344055047003105154122231 stats
uint8_t mac[6]
Definition netif.h:18
uint64_t arch_rtime_ms(void)
Reads the monotonic clock, in milliseconds.
Definition timer.c:73
static int pending
Definition vt.c:55