]> git.proxmox.com Git - grub2.git/blame - grub-core/net/arp.c
cleanup: grub_cpu_to_XXX_compile_time for constants
[grub2.git] / grub-core / net / arp.c
CommitLineData
9aad3cd9
VS
1/*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2010,2011 Free Software Foundation, Inc.
4 *
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
17 */
18
7bb47706
MA
19#include <grub/net/arp.h>
20#include <grub/net/netbuff.h>
7bb47706
MA
21#include <grub/mm.h>
22#include <grub/net.h>
23#include <grub/net/ethernet.h>
24#include <grub/net/ip.h>
25#include <grub/time.h>
26
9aad3cd9
VS
27/* ARP header operation codes */
28enum
29 {
30 ARP_REQUEST = 1,
31 ARP_REPLY = 2
32 };
33
34enum
35 {
36 /* IANA ARP constant to define hardware type as ethernet. */
37 GRUB_NET_ARPHRD_ETHERNET = 1
38 };
39
40struct arphdr {
41 grub_uint16_t hrd;
42 grub_uint16_t pro;
43 grub_uint8_t hln;
44 grub_uint8_t pln;
45 grub_uint16_t op;
7e47e27b 46} GRUB_PACKED;
9aad3cd9 47
96f7e60e
VS
48static int have_pending;
49static grub_uint32_t pending_req;
9aad3cd9 50
7bb47706 51grub_err_t
7c006811
VS
52grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
53 const grub_net_network_level_address_t *proto_addr)
7bb47706 54{
25f1579b 55 struct grub_net_buff nb;
7bb47706
MA
56 struct arphdr *arp_header;
57 grub_net_link_level_address_t target_hw_addr;
fecdbd6b 58 grub_uint8_t *aux, arp_data[128];
d855fbcf 59 grub_err_t err;
25f1579b 60 int i;
9aad3cd9
VS
61 grub_size_t addrlen;
62 grub_uint16_t etherpro;
da1b289a 63 grub_uint8_t *nbd;
7bb47706 64
9aad3cd9
VS
65 if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
66 {
67 addrlen = 4;
68 etherpro = GRUB_NET_ETHERTYPE_IP;
69 }
9aad3cd9 70 else
9c4b5c13 71 return grub_error (GRUB_ERR_BUG, "unsupported address family");
9aad3cd9 72
25f1579b
MRA
73 /* Build a request packet. */
74 nb.head = arp_data;
75 nb.end = arp_data + sizeof (arp_data);
4700d08b 76 grub_netbuff_clear (&nb);
4700d08b 77 grub_netbuff_reserve (&nb, 128);
d855fbcf 78
9aad3cd9 79 err = grub_netbuff_push (&nb, sizeof (*arp_header) + 2 * (6 + addrlen));
a057797f 80 if (err)
d855fbcf
MA
81 return err;
82
25f1579b 83 arp_header = (struct arphdr *) nb.data;
954fe771 84 arp_header->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
7bb47706 85 arp_header->hln = 6;
9aad3cd9
VS
86 arp_header->pro = grub_cpu_to_be16 (etherpro);
87 arp_header->pln = addrlen;
954fe771 88 arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
fecdbd6b 89 aux = (grub_uint8_t *) arp_header + sizeof (*arp_header);
25f1579b
MRA
90 /* Sender hardware address. */
91 grub_memcpy (aux, &inf->hwaddress.mac, 6);
92
7bb47706
MA
93 aux += 6;
94 /* Sender protocol address */
7c006811 95 grub_memcpy (aux, &inf->address.ipv4, 4);
9aad3cd9 96 aux += addrlen;
7bb47706 97 /* Target hardware address */
4700d08b 98 for (i = 0; i < 6; i++)
7bb47706
MA
99 aux[i] = 0x00;
100 aux += 6;
101 /* Target protocol address */
7c006811 102 grub_memcpy (aux, &proto_addr->ipv4, 4);
7bb47706
MA
103 grub_memset (&target_hw_addr.mac, 0xff, 6);
104
da1b289a 105 nbd = nb.data;
25f1579b 106 send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP);
9aad3cd9 107 for (i = 0; i < GRUB_NET_TRIES; i++)
7bb47706 108 {
7c006811
VS
109 if (grub_net_link_layer_resolve_check (inf, proto_addr))
110 return GRUB_ERR_NONE;
96f7e60e
VS
111 pending_req = proto_addr->ipv4;
112 have_pending = 0;
6f65e36c
PFS
113 grub_net_poll_cards (GRUB_NET_INTERVAL + (i * GRUB_NET_INTERVAL_ADDITION),
114 &have_pending);
7c006811
VS
115 if (grub_net_link_layer_resolve_check (inf, proto_addr))
116 return GRUB_ERR_NONE;
da1b289a 117 nb.data = nbd;
7c006811 118 send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP);
eea84144 119 }
25f1579b 120
7c006811 121 return GRUB_ERR_NONE;
7bb47706
MA
122}
123
124grub_err_t
7c006811
VS
125grub_net_arp_receive (struct grub_net_buff *nb,
126 struct grub_net_card *card)
7bb47706 127{
4700d08b 128 struct arphdr *arp_header = (struct arphdr *) nb->data;
9aad3cd9
VS
129 grub_uint8_t *sender_hardware_address;
130 grub_uint8_t *target_hardware_address;
131 grub_net_network_level_address_t sender_addr, target_addr;
7c006811 132 grub_net_link_level_address_t sender_hw_addr;
25f1579b 133 struct grub_net_network_level_interface *inf;
9aad3cd9 134 grub_uint8_t *sender_protocol_address, *target_protocol_address;
7bb47706 135
4700d08b
MRA
136 sender_hardware_address =
137 (grub_uint8_t *) arp_header + sizeof (*arp_header);
7bb47706
MA
138 sender_protocol_address = sender_hardware_address + arp_header->hln;
139 target_hardware_address = sender_protocol_address + arp_header->pln;
140 target_protocol_address = target_hardware_address + arp_header->hln;
9aad3cd9
VS
141 if (grub_be_to_cpu16 (arp_header->pro) == GRUB_NET_ETHERTYPE_IP
142 && arp_header->pln == 4)
143 {
144 sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
145 target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
146 grub_memcpy (&sender_addr.ipv4, sender_protocol_address, 4);
147 grub_memcpy (&target_addr.ipv4, target_protocol_address, 4);
96f7e60e
VS
148 if (grub_memcmp (sender_protocol_address, &pending_req, 4) == 0)
149 have_pending = 1;
9aad3cd9 150 }
9aad3cd9
VS
151 else
152 return GRUB_ERR_NONE;
7c006811
VS
153
154 sender_hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
da1b289a 155 grub_memcpy (sender_hw_addr.mac, sender_hardware_address,
7c006811
VS
156 sizeof (sender_hw_addr.mac));
157 grub_net_link_layer_add_address (card, &sender_addr, &sender_hw_addr, 1);
04d22ddd 158
4700d08b
MRA
159 FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
160 {
161 /* Am I the protocol address target? */
9aad3cd9 162 if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
4700d08b
MRA
163 && grub_be_to_cpu16 (arp_header->op) == ARP_REQUEST)
164 {
9aad3cd9
VS
165 grub_net_link_level_address_t target;
166 /* We've already checked that pln is either 4 or 16. */
28153eb8
VS
167 char tmp[16];
168 grub_size_t pln = arp_header->pln;
169
170 if (pln > 16)
171 pln = 16;
9aad3cd9
VS
172
173 target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
174 grub_memcpy (target.mac, sender_hardware_address, 6);
175 grub_memcpy (target_hardware_address, target.mac, 6);
4700d08b 176 grub_memcpy (sender_hardware_address, inf->hwaddress.mac, 6);
9aad3cd9 177
28153eb8
VS
178 grub_memcpy (tmp, sender_protocol_address, pln);
179 grub_memcpy (sender_protocol_address, target_protocol_address, pln);
180 grub_memcpy (target_protocol_address, tmp, pln);
9aad3cd9 181
4700d08b
MRA
182 /* Change operation to REPLY and send packet */
183 arp_header->op = grub_be_to_cpu16 (ARP_REPLY);
9aad3cd9 184 send_ethernet_packet (inf, nb, target, GRUB_NET_ETHERTYPE_ARP);
4700d08b
MRA
185 }
186 }
7bb47706
MA
187 return GRUB_ERR_NONE;
188}