source: grub-pc/trunk/fuentes/grub-core/net/arp.c @ 22

Last change on this file since 22 was 22, checked in by mabarracus, 4 years ago

updated version and apply net.ifnames=0 into debian/rules

File size: 5.7 KB
Line 
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 */
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 arppkt {
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_uint8_t sender_mac[6];
47  grub_uint32_t sender_ip;
48  grub_uint8_t recv_mac[6];
49  grub_uint32_t recv_ip;
50} GRUB_PACKED;
51
52static int have_pending;
53static grub_uint32_t pending_req;
54
55grub_err_t
56grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
57                           const grub_net_network_level_address_t *proto_addr)
58{
59  struct grub_net_buff nb;
60  struct arppkt *arp_packet;
61  grub_net_link_level_address_t target_mac_addr;
62  grub_err_t err;
63  int i;
64  grub_uint8_t *nbd;
65  grub_uint8_t arp_data[128];
66
67  if (proto_addr->type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
68    return grub_error (GRUB_ERR_BUG, "unsupported address family");
69
70  /* Build a request packet.  */
71  nb.head = arp_data;
72  nb.end = arp_data + sizeof (arp_data);
73  grub_netbuff_clear (&nb);
74  grub_netbuff_reserve (&nb, 128);
75
76  err = grub_netbuff_push (&nb, sizeof (*arp_packet));
77  if (err)
78    return err;
79
80  arp_packet = (struct arppkt *) nb.data;
81  arp_packet->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
82  arp_packet->hln = 6;
83  arp_packet->pro = grub_cpu_to_be16 (GRUB_NET_ETHERTYPE_IP);
84  arp_packet->pln = 4;
85  arp_packet->op = grub_cpu_to_be16_compile_time (ARP_REQUEST);
86  /* Sender hardware address.  */
87  grub_memcpy (arp_packet->sender_mac, &inf->hwaddress.mac, 6);
88  arp_packet->sender_ip = inf->address.ipv4;
89  grub_memset (arp_packet->recv_mac, 0, 6);
90  arp_packet->recv_ip = proto_addr->ipv4;
91  /* Target protocol address */
92  grub_memset (&target_mac_addr.mac, 0xff, 6);
93
94  nbd = nb.data;
95  send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP);
96  for (i = 0; i < GRUB_NET_TRIES; i++)
97    {
98      if (grub_net_link_layer_resolve_check (inf, proto_addr))
99        return GRUB_ERR_NONE;
100      pending_req = proto_addr->ipv4;
101      have_pending = 0;
102      grub_net_poll_cards (GRUB_NET_INTERVAL + (i * GRUB_NET_INTERVAL_ADDITION),
103                           &have_pending);
104      if (grub_net_link_layer_resolve_check (inf, proto_addr))
105        return GRUB_ERR_NONE;
106      nb.data = nbd;
107      send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP);
108    }
109
110  return GRUB_ERR_NONE;
111}
112
113grub_err_t
114grub_net_arp_receive (struct grub_net_buff *nb,
115                      struct grub_net_card *card)
116{
117  struct arppkt *arp_packet = (struct arppkt *) nb->data;
118  grub_net_network_level_address_t sender_addr, target_addr;
119  grub_net_link_level_address_t sender_mac_addr;
120  struct grub_net_network_level_interface *inf;
121
122  if (arp_packet->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP)
123      || arp_packet->pln != 4 || arp_packet->hln != 6
124      || nb->tail - nb->data < (int) sizeof (*arp_packet))
125    return GRUB_ERR_NONE;
126
127  sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
128  target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
129  sender_addr.ipv4 = arp_packet->sender_ip;
130  target_addr.ipv4 = arp_packet->recv_ip;
131  if (arp_packet->sender_ip == pending_req)
132    have_pending = 1;
133
134  sender_mac_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
135  grub_memcpy (sender_mac_addr.mac, arp_packet->sender_mac,
136               sizeof (sender_mac_addr.mac));
137  grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1);
138
139  FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
140  {
141    /* Am I the protocol address target? */
142    if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
143        && arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST))
144      {
145        grub_net_link_level_address_t target;
146        struct grub_net_buff nb_reply;
147        struct arppkt *arp_reply;
148        grub_uint8_t arp_data[128];
149        grub_err_t err;
150
151        nb_reply.head = arp_data;
152        nb_reply.end = arp_data + sizeof (arp_data);
153        grub_netbuff_clear (&nb_reply);
154        grub_netbuff_reserve (&nb_reply, 128);
155
156        err = grub_netbuff_push (&nb_reply, sizeof (*arp_packet));
157        if (err)
158          return err;
159
160        arp_reply = (struct arppkt *) nb_reply.data;
161
162        arp_reply->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET);
163        arp_reply->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP);
164        arp_reply->pln = 4;
165        arp_reply->hln = 6;
166        arp_reply->op = grub_cpu_to_be16_compile_time (ARP_REPLY);
167        arp_reply->sender_ip = arp_packet->recv_ip;
168        arp_reply->recv_ip = arp_packet->sender_ip;
169        arp_reply->hln = 6;
170
171        target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
172        grub_memcpy (target.mac, arp_packet->sender_mac, 6);
173        grub_memcpy (arp_reply->sender_mac, inf->hwaddress.mac, 6);
174        grub_memcpy (arp_reply->recv_mac, arp_packet->sender_mac, 6);
175
176        /* Change operation to REPLY and send packet */
177        send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP);
178      }
179  }
180  return GRUB_ERR_NONE;
181}
Note: See TracBrowser for help on using the repository browser.