]> git.proxmox.com Git - grub2.git/blob - grub-core/net/arp.c
cleanup: grub_cpu_to_XXX_compile_time for constants
[grub2.git] / grub-core / net / arp.c
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
19 #include <grub/net/arp.h>
20 #include <grub/net/netbuff.h>
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
27 /* ARP header operation codes */
28 enum
29 {
30 ARP_REQUEST = 1,
31 ARP_REPLY = 2
32 };
33
34 enum
35 {
36 /* IANA ARP constant to define hardware type as ethernet. */
37 GRUB_NET_ARPHRD_ETHERNET = 1
38 };
39
40 struct 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;
46 } GRUB_PACKED;
47
48 static int have_pending;
49 static grub_uint32_t pending_req;
50
51 grub_err_t
52 grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
53 const grub_net_network_level_address_t *proto_addr)
54 {
55 struct grub_net_buff nb;
56 struct arphdr *arp_header;
57 grub_net_link_level_address_t target_hw_addr;
58 grub_uint8_t *aux, arp_data[128];
59 grub_err_t err;
60 int i;
61 grub_size_t addrlen;
62 grub_uint16_t etherpro;
63 grub_uint8_t *nbd;
64
65 if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
66 {
67 addrlen = 4;
68 etherpro = GRUB_NET_ETHERTYPE_IP;
69 }
70 else
71 return grub_error (GRUB_ERR_BUG, "unsupported address family");
72
73 /* Build a request packet. */
74 nb.head = arp_data;
75 nb.end = arp_data + sizeof (arp_data);
76 grub_netbuff_clear (&nb);
77 grub_netbuff_reserve (&nb, 128);
78
79 err = grub_netbuff_push (&nb, sizeof (*arp_header) + 2 * (6 + addrlen));
80 if (err)
81 return err;
82
83 arp_header = (struct arphdr *) nb.data;
84 arp_header->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
85 arp_header->hln = 6;
86 arp_header->pro = grub_cpu_to_be16 (etherpro);
87 arp_header->pln = addrlen;
88 arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
89 aux = (grub_uint8_t *) arp_header + sizeof (*arp_header);
90 /* Sender hardware address. */
91 grub_memcpy (aux, &inf->hwaddress.mac, 6);
92
93 aux += 6;
94 /* Sender protocol address */
95 grub_memcpy (aux, &inf->address.ipv4, 4);
96 aux += addrlen;
97 /* Target hardware address */
98 for (i = 0; i < 6; i++)
99 aux[i] = 0x00;
100 aux += 6;
101 /* Target protocol address */
102 grub_memcpy (aux, &proto_addr->ipv4, 4);
103 grub_memset (&target_hw_addr.mac, 0xff, 6);
104
105 nbd = nb.data;
106 send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP);
107 for (i = 0; i < GRUB_NET_TRIES; i++)
108 {
109 if (grub_net_link_layer_resolve_check (inf, proto_addr))
110 return GRUB_ERR_NONE;
111 pending_req = proto_addr->ipv4;
112 have_pending = 0;
113 grub_net_poll_cards (GRUB_NET_INTERVAL + (i * GRUB_NET_INTERVAL_ADDITION),
114 &have_pending);
115 if (grub_net_link_layer_resolve_check (inf, proto_addr))
116 return GRUB_ERR_NONE;
117 nb.data = nbd;
118 send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP);
119 }
120
121 return GRUB_ERR_NONE;
122 }
123
124 grub_err_t
125 grub_net_arp_receive (struct grub_net_buff *nb,
126 struct grub_net_card *card)
127 {
128 struct arphdr *arp_header = (struct arphdr *) nb->data;
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;
132 grub_net_link_level_address_t sender_hw_addr;
133 struct grub_net_network_level_interface *inf;
134 grub_uint8_t *sender_protocol_address, *target_protocol_address;
135
136 sender_hardware_address =
137 (grub_uint8_t *) arp_header + sizeof (*arp_header);
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;
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);
148 if (grub_memcmp (sender_protocol_address, &pending_req, 4) == 0)
149 have_pending = 1;
150 }
151 else
152 return GRUB_ERR_NONE;
153
154 sender_hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
155 grub_memcpy (sender_hw_addr.mac, sender_hardware_address,
156 sizeof (sender_hw_addr.mac));
157 grub_net_link_layer_add_address (card, &sender_addr, &sender_hw_addr, 1);
158
159 FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
160 {
161 /* Am I the protocol address target? */
162 if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
163 && grub_be_to_cpu16 (arp_header->op) == ARP_REQUEST)
164 {
165 grub_net_link_level_address_t target;
166 /* We've already checked that pln is either 4 or 16. */
167 char tmp[16];
168 grub_size_t pln = arp_header->pln;
169
170 if (pln > 16)
171 pln = 16;
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);
176 grub_memcpy (sender_hardware_address, inf->hwaddress.mac, 6);
177
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);
181
182 /* Change operation to REPLY and send packet */
183 arp_header->op = grub_be_to_cpu16 (ARP_REPLY);
184 send_ethernet_packet (inf, nb, target, GRUB_NET_ETHERTYPE_ARP);
185 }
186 }
187 return GRUB_ERR_NONE;
188 }