| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| From: Andrzej Kacprowski <andrzej.kacprowski@intel.com> |
| Date: Fri, 21 Apr 2017 10:06:20 +0200 |
| Subject: [PATCH] Add support for non-Ethernet network cards |
| |
| This patch replaces fixed 6-byte link layer address with |
| up to 32-byte variable sized address. |
| This allows supporting Infiniband and Omni-Path fabric |
| which use 20-byte address, but other network card types |
| can also take advantage of this change. |
| The network card driver is responsible for replacing L2 |
| header provided by grub2 if needed. |
| This approach is compatible with UEFI network stack which |
| also allows up to 32-byte variable size link address. |
| |
| The BOOTP/DHCP packet format is limited to 16 byte client |
| hardware address, if link address is more that 16-bytes |
| then chaddr field in BOOTP it will be set to 0 as per rfc4390. |
| |
| Resolves: rhbz#1370642 |
| |
| Signed-off-by: Andrzej Kacprowski <andrzej.kacprowski@intel.com> |
| |
| Conflicts: |
| grub-core/net/ip.c |
| |
| grub-core/net/arp.c | 155 ++++++++++++++++++++++----------- |
| grub-core/net/bootp.c | 14 ++- |
| grub-core/net/drivers/efi/efinet.c | 8 +- |
| grub-core/net/drivers/emu/emunet.c | 1 + |
| grub-core/net/drivers/i386/pc/pxe.c | 13 +-- |
| grub-core/net/drivers/ieee1275/ofnet.c | 2 + |
| grub-core/net/drivers/uboot/ubootnet.c | 1 + |
| grub-core/net/ethernet.c | 88 +++++++++---------- |
| grub-core/net/icmp6.c | 15 ++-- |
| grub-core/net/ip.c | 4 +- |
| grub-core/net/net.c | 48 +++++----- |
| include/grub/net.h | 19 ++-- |
| 12 files changed, 216 insertions(+), 152 deletions(-) |
| |
| diff --git a/grub-core/net/arp.c b/grub-core/net/arp.c |
| index 54306e3b1..67b409a8a 100644 |
| |
| |
| @@ -31,22 +31,12 @@ enum |
| ARP_REPLY = 2 |
| }; |
| |
| -enum |
| - { |
| - /* IANA ARP constant to define hardware type as ethernet. */ |
| - GRUB_NET_ARPHRD_ETHERNET = 1 |
| - }; |
| - |
| -struct arppkt { |
| +struct arphdr { |
| grub_uint16_t hrd; |
| grub_uint16_t pro; |
| grub_uint8_t hln; |
| grub_uint8_t pln; |
| grub_uint16_t op; |
| - grub_uint8_t sender_mac[6]; |
| - grub_uint32_t sender_ip; |
| - grub_uint8_t recv_mac[6]; |
| - grub_uint32_t recv_ip; |
| } GRUB_PACKED; |
| |
| static int have_pending; |
| @@ -57,12 +47,16 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf, |
| const grub_net_network_level_address_t *proto_addr) |
| { |
| struct grub_net_buff nb; |
| - struct arppkt *arp_packet; |
| + struct arphdr *arp_header; |
| grub_net_link_level_address_t target_mac_addr; |
| grub_err_t err; |
| int i; |
| grub_uint8_t *nbd; |
| grub_uint8_t arp_data[128]; |
| + grub_uint8_t hln; |
| + grub_uint8_t pln; |
| + grub_uint8_t arp_packet_len; |
| + grub_uint8_t *tmp_ptr; |
| |
| if (proto_addr->type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4) |
| return grub_error (GRUB_ERR_BUG, "unsupported address family"); |
| @@ -73,23 +67,39 @@ grub_net_arp_send_request (struct grub_net_network_level_interface *inf, |
| grub_netbuff_clear (&nb); |
| grub_netbuff_reserve (&nb, 128); |
| |
| - err = grub_netbuff_push (&nb, sizeof (*arp_packet)); |
| + hln = inf->card->default_address.len; |
| + pln = sizeof (proto_addr->ipv4); |
| + arp_packet_len = sizeof (*arp_header) + 2 * (hln + pln); |
| + |
| + err = grub_netbuff_push (&nb, arp_packet_len); |
| if (err) |
| return err; |
| |
| - arp_packet = (struct arppkt *) nb.data; |
| - arp_packet->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET); |
| - arp_packet->hln = 6; |
| - arp_packet->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); |
| - arp_packet->pln = 4; |
| - arp_packet->op = grub_cpu_to_be16_compile_time (ARP_REQUEST); |
| - /* Sender hardware address. */ |
| - grub_memcpy (arp_packet->sender_mac, &inf->hwaddress.mac, 6); |
| - arp_packet->sender_ip = inf->address.ipv4; |
| - grub_memset (arp_packet->recv_mac, 0, 6); |
| - arp_packet->recv_ip = proto_addr->ipv4; |
| - /* Target protocol address */ |
| - grub_memset (&target_mac_addr.mac, 0xff, 6); |
| + arp_header = (struct arphdr *) nb.data; |
| + arp_header->hrd = grub_cpu_to_be16 (inf->card->default_address.type); |
| + arp_header->hln = hln; |
| + arp_header->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); |
| + arp_header->pln = pln; |
| + arp_header->op = grub_cpu_to_be16_compile_time (ARP_REQUEST); |
| + tmp_ptr = nb.data + sizeof (*arp_header); |
| + |
| + /* The source hardware address. */ |
| + grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln); |
| + tmp_ptr += hln; |
| + |
| + /* The source protocol address. */ |
| + grub_memcpy (tmp_ptr, &inf->address.ipv4, pln); |
| + tmp_ptr += pln; |
| + |
| + /* The target hardware address. */ |
| + grub_memset (tmp_ptr, 0, hln); |
| + tmp_ptr += hln; |
| + |
| + /* The target protocol address */ |
| + grub_memcpy (tmp_ptr, &proto_addr->ipv4, pln); |
| + tmp_ptr += pln; |
| + |
| + grub_memset (&target_mac_addr.mac, 0xff, hln); |
| |
| nbd = nb.data; |
| send_ethernet_packet (inf, &nb, target_mac_addr, GRUB_NET_ETHERTYPE_ARP); |
| @@ -114,28 +124,53 @@ grub_err_t |
| grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, |
| grub_uint16_t *vlantag) |
| { |
| - struct arppkt *arp_packet = (struct arppkt *) nb->data; |
| + struct arphdr *arp_header = (struct arphdr *) nb->data; |
| grub_net_network_level_address_t sender_addr, target_addr; |
| grub_net_link_level_address_t sender_mac_addr; |
| struct grub_net_network_level_interface *inf; |
| + grub_uint16_t hw_type; |
| + grub_uint8_t hln; |
| + grub_uint8_t pln; |
| + grub_uint8_t arp_packet_len; |
| + grub_uint8_t *tmp_ptr; |
| |
| - if (arp_packet->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP) |
| - || arp_packet->pln != 4 || arp_packet->hln != 6 |
| - || nb->tail - nb->data < (int) sizeof (*arp_packet)) |
| + hw_type = card->default_address.type; |
| + hln = card->default_address.len; |
| + pln = sizeof(sender_addr.ipv4); |
| + arp_packet_len = sizeof (*arp_header) + 2 * (pln + hln); |
| + |
| + if (arp_header->pro != grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP) |
| + || arp_header->hrd != grub_cpu_to_be16 (hw_type) |
| + || arp_header->hln != hln || arp_header->pln != pln |
| + || nb->tail - nb->data < (int) arp_packet_len) { |
| return GRUB_ERR_NONE; |
| + } |
| |
| + tmp_ptr = nb->data + sizeof (*arp_header); |
| + |
| + /* The source hardware address. */ |
| + sender_mac_addr.type = hw_type; |
| + sender_mac_addr.len = hln; |
| + grub_memcpy (sender_mac_addr.mac, tmp_ptr, hln); |
| + tmp_ptr += hln; |
| + |
| + /* The source protocol address. */ |
| sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; |
| + grub_memcpy(&sender_addr.ipv4, tmp_ptr, pln); |
| + tmp_ptr += pln; |
| + |
| + grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1); |
| + |
| + /* The target hardware address. */ |
| + tmp_ptr += hln; |
| + |
| + /* The target protocol address. */ |
| target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; |
| - sender_addr.ipv4 = arp_packet->sender_ip; |
| - target_addr.ipv4 = arp_packet->recv_ip; |
| - if (arp_packet->sender_ip == pending_req) |
| + grub_memcpy(&target_addr.ipv4, tmp_ptr, pln); |
| + |
| + if (sender_addr.ipv4 == pending_req) |
| have_pending = 1; |
| |
| - sender_mac_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| - grub_memcpy (sender_mac_addr.mac, arp_packet->sender_mac, |
| - sizeof (sender_mac_addr.mac)); |
| - grub_net_link_layer_add_address (card, &sender_addr, &sender_mac_addr, 1); |
| - |
| FOR_NET_NETWORK_LEVEL_INTERFACES (inf) |
| { |
| /* Verify vlantag id */ |
| @@ -148,11 +183,11 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, |
| |
| /* Am I the protocol address target? */ |
| if (grub_net_addr_cmp (&inf->address, &target_addr) == 0 |
| - && arp_packet->op == grub_cpu_to_be16_compile_time (ARP_REQUEST)) |
| + && arp_header->op == grub_cpu_to_be16_compile_time (ARP_REQUEST)) |
| { |
| grub_net_link_level_address_t target; |
| struct grub_net_buff nb_reply; |
| - struct arppkt *arp_reply; |
| + struct arphdr *arp_reply; |
| grub_uint8_t arp_data[128]; |
| grub_err_t err; |
| |
| @@ -161,25 +196,39 @@ grub_net_arp_receive (struct grub_net_buff *nb, struct grub_net_card *card, |
| grub_netbuff_clear (&nb_reply); |
| grub_netbuff_reserve (&nb_reply, 128); |
| |
| - err = grub_netbuff_push (&nb_reply, sizeof (*arp_packet)); |
| + err = grub_netbuff_push (&nb_reply, arp_packet_len); |
| if (err) |
| return err; |
| |
| - arp_reply = (struct arppkt *) nb_reply.data; |
| + arp_reply = (struct arphdr *) nb_reply.data; |
| |
| - arp_reply->hrd = grub_cpu_to_be16_compile_time (GRUB_NET_ARPHRD_ETHERNET); |
| + arp_reply->hrd = grub_cpu_to_be16 (hw_type); |
| arp_reply->pro = grub_cpu_to_be16_compile_time (GRUB_NET_ETHERTYPE_IP); |
| - arp_reply->pln = 4; |
| - arp_reply->hln = 6; |
| + arp_reply->pln = pln; |
| + arp_reply->hln = hln; |
| arp_reply->op = grub_cpu_to_be16_compile_time (ARP_REPLY); |
| - arp_reply->sender_ip = arp_packet->recv_ip; |
| - arp_reply->recv_ip = arp_packet->sender_ip; |
| - arp_reply->hln = 6; |
| - |
| - target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| - grub_memcpy (target.mac, arp_packet->sender_mac, 6); |
| - grub_memcpy (arp_reply->sender_mac, inf->hwaddress.mac, 6); |
| - grub_memcpy (arp_reply->recv_mac, arp_packet->sender_mac, 6); |
| + |
| + tmp_ptr = nb_reply.data + sizeof (*arp_reply); |
| + |
| + /* The source hardware address. */ |
| + grub_memcpy (tmp_ptr, inf->hwaddress.mac, hln); |
| + tmp_ptr += hln; |
| + |
| + /* The source protocol address. */ |
| + grub_memcpy (tmp_ptr, &target_addr.ipv4, pln); |
| + tmp_ptr += pln; |
| + |
| + /* The target hardware address. */ |
| + grub_memcpy (tmp_ptr, sender_mac_addr.mac, hln); |
| + tmp_ptr += hln; |
| + |
| + /* The target protocol address */ |
| + grub_memcpy (tmp_ptr, &sender_addr.ipv4, pln); |
| + tmp_ptr += pln; |
| + |
| + target.type = hw_type; |
| + target.len = hln; |
| + grub_memcpy (target.mac, sender_mac_addr.mac, hln); |
| |
| /* Change operation to REPLY and send packet */ |
| send_ethernet_packet (inf, &nb_reply, target, GRUB_NET_ETHERTYPE_ARP); |
| diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c |
| index 2869482fe..4e55adc55 100644 |
| |
| |
| @@ -219,7 +219,6 @@ grub_net_configure_by_dhcp_ack (const char *name, |
| int is_def, char **device, char **path) |
| { |
| grub_net_network_level_address_t addr; |
| - grub_net_link_level_address_t hwaddr; |
| struct grub_net_network_level_interface *inter; |
| int mask = -1; |
| char server_ip[sizeof ("xxx.xxx.xxx.xxx")]; |
| @@ -232,12 +231,8 @@ grub_net_configure_by_dhcp_ack (const char *name, |
| if (path) |
| *path = 0; |
| |
| - grub_memcpy (hwaddr.mac, bp->mac_addr, |
| - bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len |
| - : sizeof (hwaddr.mac)); |
| - hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| - |
| - inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags); |
| + grub_dprintf("dhcp", "configuring dhcp for %s\n", name); |
| + inter = grub_net_add_addr (name, card, &addr, &card->default_address, flags); |
| if (!inter) |
| return 0; |
| |
| @@ -770,7 +765,8 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), |
| grub_memset (pack, 0, sizeof (*pack) + 64); |
| pack->opcode = 1; |
| pack->hw_type = 1; |
| - pack->hw_len = 6; |
| + pack->hw_len = ifaces[j].hwaddress.len > 16 ? 0 |
| + : ifaces[j].hwaddress.len; |
| err = grub_get_datetime (&date); |
| if (err || !grub_datetime2unixtime (&date, &t)) |
| { |
| @@ -781,7 +777,7 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), |
| ifaces[j].dhcp_xid = pack->xid; |
| pack->seconds = grub_cpu_to_be16 (t); |
| |
| - grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6); |
| + grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, pack->hw_len); |
| |
| grub_netbuff_push (nb, sizeof (*udph)); |
| |
| diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c |
| index a4daaa460..cd6dba79f 100644 |
| |
| |
| @@ -280,6 +280,9 @@ grub_efinet_findcards (void) |
| /* This should not happen... Why? */ |
| continue; |
| |
| + if (net->mode->hwaddr_size > GRUB_NET_MAX_LINK_ADDRESS_SIZE) |
| + continue; |
| + |
| if (net->mode->state == GRUB_EFI_NETWORK_STOPPED |
| && efi_call_1 (net->start, net) != GRUB_EFI_SUCCESS) |
| continue; |
| @@ -316,10 +319,11 @@ grub_efinet_findcards (void) |
| card->name = grub_xasprintf ("efinet%d", i++); |
| card->driver = &efidriver; |
| card->flags = 0; |
| - card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| + card->default_address.type = net->mode->if_type; |
| + card->default_address.len = net->mode->hwaddr_size; |
| grub_memcpy (card->default_address.mac, |
| net->mode->current_address, |
| - sizeof (card->default_address.mac)); |
| + net->mode->hwaddr_size); |
| card->efi_net = net; |
| card->efi_handle = *handle; |
| |
| diff --git a/grub-core/net/drivers/emu/emunet.c b/grub-core/net/drivers/emu/emunet.c |
| index b19492086..5b6c5e16a 100644 |
| |
| |
| @@ -46,6 +46,7 @@ static struct grub_net_card emucard = |
| .mtu = 1500, |
| .default_address = { |
| .type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET, |
| + . len = 6, |
| {.mac = {0, 1, 2, 3, 4, 5}} |
| }, |
| .flags = 0 |
| diff --git a/grub-core/net/drivers/i386/pc/pxe.c b/grub-core/net/drivers/i386/pc/pxe.c |
| index 3f4152d03..9f8fb4b6d 100644 |
| |
| |
| @@ -386,20 +386,21 @@ GRUB_MOD_INIT(pxe) |
| grub_memset (ui, 0, sizeof (*ui)); |
| grub_pxe_call (GRUB_PXENV_UNDI_GET_INFORMATION, ui, pxe_rm_entry); |
| |
| + grub_pxe_card.default_address.len = 6; |
| grub_memcpy (grub_pxe_card.default_address.mac, ui->current_addr, |
| - sizeof (grub_pxe_card.default_address.mac)); |
| - for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) |
| + grub_pxe_card.default_address.len); |
| + for (i = 0; i < grub_pxe_card.default_address.len; i++) |
| if (grub_pxe_card.default_address.mac[i] != 0) |
| break; |
| - if (i != sizeof (grub_pxe_card.default_address.mac)) |
| + if (i != grub_pxe_card.default_address.len) |
| { |
| - for (i = 0; i < sizeof (grub_pxe_card.default_address.mac); i++) |
| + for (i = 0; i < grub_pxe_card.default_address.len; i++) |
| if (grub_pxe_card.default_address.mac[i] != 0xff) |
| break; |
| } |
| - if (i == sizeof (grub_pxe_card.default_address.mac)) |
| + if (i == grub_pxe_card.default_address.len) |
| grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr, |
| - sizeof (grub_pxe_card.default_address.mac)); |
| + grub_pxe_card.default_address.len); |
| grub_pxe_card.mtu = ui->mtu; |
| |
| grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c |
| index 3df75357a..ba50415f5 100644 |
| |
| |
| @@ -160,6 +160,7 @@ grub_ieee1275_parse_bootpath (const char *devpath, char *bootpath, |
| grub_uint16_t vlantag = 0; |
| |
| hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| + hw_addr.len = 6; |
| |
| args = bootpath + grub_strlen (devpath) + 1; |
| do |
| @@ -503,6 +504,7 @@ search_net_devices (struct grub_ieee1275_devalias *alias) |
| grub_memcpy (&lla.mac, pprop, 6); |
| |
| lla.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| + lla.len = 6; |
| card->default_address = lla; |
| |
| card->txbufsize = ALIGN_UP (card->mtu, 64) + 256; |
| diff --git a/grub-core/net/drivers/uboot/ubootnet.c b/grub-core/net/drivers/uboot/ubootnet.c |
| index 056052e40..22ebcbf21 100644 |
| |
| |
| @@ -131,6 +131,7 @@ GRUB_MOD_INIT (ubootnet) |
| |
| grub_memcpy (&(card->default_address.mac), &devinfo->di_net.hwaddr, 6); |
| card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| + card->default_address.len = 6; |
| |
| card->txbufsize = ALIGN_UP (card->mtu, 64) + 256; |
| card->txbuf = grub_zalloc (card->txbufsize); |
| diff --git a/grub-core/net/ethernet.c b/grub-core/net/ethernet.c |
| index 4d7ceed6f..9aae83a5e 100644 |
| |
| |
| @@ -29,13 +29,6 @@ |
| |
| #define LLCADDRMASK 0x7f |
| |
| -struct etherhdr |
| -{ |
| - grub_uint8_t dst[6]; |
| - grub_uint8_t src[6]; |
| - grub_uint16_t type; |
| -} GRUB_PACKED; |
| - |
| struct llchdr |
| { |
| grub_uint8_t dsap; |
| @@ -55,13 +48,15 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, |
| grub_net_link_level_address_t target_addr, |
| grub_net_ethertype_t ethertype) |
| { |
| - struct etherhdr *eth; |
| + grub_uint8_t *eth; |
| grub_err_t err; |
| - grub_uint8_t etherhdr_size; |
| - grub_uint16_t vlantag_id = VLANTAG_IDENTIFIER; |
| + grub_uint32_t vlantag = 0; |
| + grub_uint8_t hw_addr_len = inf->card->default_address.len; |
| + grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2; |
| |
| - etherhdr_size = sizeof (*eth); |
| - COMPILE_TIME_ASSERT (sizeof (*eth) + 4 < GRUB_NET_MAX_LINK_HEADER_SIZE); |
| + /* Source and destination link addresses + ethertype + vlan tag */ |
| + COMPILE_TIME_ASSERT ((GRUB_NET_MAX_LINK_ADDRESS_SIZE * 2 + 2 + 4) < |
| + GRUB_NET_MAX_LINK_HEADER_SIZE); |
| |
| /* Increase ethernet header in case of vlantag */ |
| if (inf->vlantag != 0) |
| @@ -70,11 +65,22 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, |
| err = grub_netbuff_push (nb, etherhdr_size); |
| if (err) |
| return err; |
| - eth = (struct etherhdr *) nb->data; |
| - grub_memcpy (eth->dst, target_addr.mac, 6); |
| - grub_memcpy (eth->src, inf->hwaddress.mac, 6); |
| + eth = nb->data; |
| + grub_memcpy (eth, target_addr.mac, hw_addr_len); |
| + eth += hw_addr_len; |
| + grub_memcpy (eth, inf->hwaddress.mac, hw_addr_len); |
| + eth += hw_addr_len; |
| + |
| + /* Check if a vlan-tag is present. */ |
| + if (vlantag != 0) |
| + { |
| + *((grub_uint32_t *)eth) = grub_cpu_to_be32 (vlantag); |
| + eth += sizeof (vlantag); |
| + } |
| + |
| + /* Write ethertype */ |
| + *((grub_uint16_t*) eth) = grub_cpu_to_be16 (ethertype); |
| |
| - eth->type = grub_cpu_to_be16 (ethertype); |
| if (!inf->card->opened) |
| { |
| err = GRUB_ERR_NONE; |
| @@ -85,18 +91,6 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf, |
| inf->card->opened = 1; |
| } |
| |
| - /* Check and add a vlan-tag if needed. */ |
| - if (inf->vlantag != 0) |
| - { |
| - /* Move eth type to the right */ |
| - grub_memcpy ((char *) nb->data + etherhdr_size - 2, |
| - (char *) nb->data + etherhdr_size - 6, 2); |
| - |
| - /* Add the tag in the middle */ |
| - grub_memcpy ((char *) nb->data + etherhdr_size - 6, &vlantag_id, 2); |
| - grub_memcpy ((char *) nb->data + etherhdr_size - 4, (char *) &(inf->vlantag), 2); |
| - } |
| - |
| return inf->card->driver->send (inf->card, nb); |
| } |
| |
| @@ -104,31 +98,40 @@ grub_err_t |
| grub_net_recv_ethernet_packet (struct grub_net_buff *nb, |
| struct grub_net_card *card) |
| { |
| - struct etherhdr *eth; |
| + grub_uint8_t *eth; |
| struct llchdr *llch; |
| struct snaphdr *snaph; |
| grub_net_ethertype_t type; |
| grub_net_link_level_address_t hwaddress; |
| grub_net_link_level_address_t src_hwaddress; |
| grub_err_t err; |
| - grub_uint8_t etherhdr_size = sizeof (*eth); |
| + grub_uint8_t hw_addr_len = card->default_address.len; |
| + grub_uint8_t etherhdr_size = 2 * hw_addr_len + 2; |
| grub_uint16_t vlantag = 0; |
| |
| + eth = nb->data; |
| |
| - /* Check if a vlan-tag is present. If so, the ethernet header is 4 bytes */ |
| - /* longer than the original one. The vlantag id is extracted and the header */ |
| - /* is reseted to the original size. */ |
| - if (grub_get_unaligned16 (nb->data + etherhdr_size - 2) == VLANTAG_IDENTIFIER) |
| + hwaddress.type = card->default_address.type; |
| + hwaddress.len = hw_addr_len; |
| + grub_memcpy (hwaddress.mac, eth, hw_addr_len); |
| + eth += hw_addr_len; |
| + |
| + src_hwaddress.type = card->default_address.type; |
| + src_hwaddress.len = hw_addr_len; |
| + grub_memcpy (src_hwaddress.mac, eth, hw_addr_len); |
| + eth += hw_addr_len; |
| + |
| + type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); |
| + if (type == VLANTAG_IDENTIFIER) |
| { |
| - vlantag = grub_get_unaligned16 (nb->data + etherhdr_size); |
| + /* Skip vlan tag */ |
| + eth += 2; |
| + vlantag = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); |
| etherhdr_size += 4; |
| - /* Move eth type to the original position */ |
| - grub_memcpy((char *) nb->data + etherhdr_size - 6, |
| - (char *) nb->data + etherhdr_size - 2, 2); |
| + eth += 2; |
| + type = grub_be_to_cpu16 (*(grub_uint16_t*)(eth)); |
| } |
| |
| - eth = (struct etherhdr *) nb->data; |
| - type = grub_be_to_cpu16 (eth->type); |
| err = grub_netbuff_pull (nb, etherhdr_size); |
| if (err) |
| return err; |
| @@ -148,11 +151,6 @@ grub_net_recv_ethernet_packet (struct grub_net_buff *nb, |
| } |
| } |
| |
| - hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| - grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac)); |
| - src_hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| - grub_memcpy (src_hwaddress.mac, eth->src, sizeof (src_hwaddress.mac)); |
| - |
| switch (type) |
| { |
| /* ARP packet. */ |
| diff --git a/grub-core/net/icmp6.c b/grub-core/net/icmp6.c |
| index 2cbd95dce..56a3ec5c8 100644 |
| |
| |
| @@ -231,8 +231,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, |
| && ohdr->len == 1) |
| { |
| grub_net_link_level_address_t ll_address; |
| - ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| - grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); |
| + ll_address.type = card->default_address.type; |
| + ll_address.len = card->default_address.len; |
| + grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); |
| grub_net_link_layer_add_address (card, source, &ll_address, 0); |
| } |
| } |
| @@ -335,8 +336,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, |
| && ohdr->len == 1) |
| { |
| grub_net_link_level_address_t ll_address; |
| - ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| - grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); |
| + ll_address.type = card->default_address.type; |
| + ll_address.len = card->default_address.len; |
| + grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); |
| grub_net_link_layer_add_address (card, source, &ll_address, 0); |
| } |
| } |
| @@ -384,8 +386,9 @@ grub_net_recv_icmp6_packet (struct grub_net_buff *nb, |
| && ohdr->len == 1) |
| { |
| grub_net_link_level_address_t ll_address; |
| - ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| - grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac)); |
| + ll_address.type = card->default_address.type; |
| + ll_address.len = card->default_address.len; |
| + grub_memcpy (ll_address.mac, ohdr + 1, ll_address.len); |
| grub_net_link_layer_add_address (card, source, &ll_address, 0); |
| } |
| if (ohdr->type == OPTION_PREFIX && ohdr->len == 4) |
| diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c |
| index 8411e0ecc..b2ca74b6e 100644 |
| |
| |
| @@ -277,8 +277,8 @@ handle_dgram (struct grub_net_buff *nb, |
| && inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV |
| && inf->dhcp_xid == bootp->xid |
| && inf->hwaddress.type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET |
| - && grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr, |
| - sizeof (inf->hwaddress.mac)) == 0) |
| + && (grub_memcmp (inf->hwaddress.mac, &bootp->mac_addr, |
| + bootp->hw_len) == 0 || bootp->hw_len == 0)) |
| { |
| grub_net_process_dhcp (nb, inf->card); |
| grub_netbuff_free (nb); |
| diff --git a/grub-core/net/net.c b/grub-core/net/net.c |
| index fa3e29126..9b8944292 100644 |
| |
| |
| @@ -128,8 +128,9 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, |
| << 48) |
| && proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1)))) |
| { |
| - hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| - grub_memset (hw_addr->mac, -1, 6); |
| + hw_addr->type = inf->card->default_address.type; |
| + hw_addr->len = inf->card->default_address.len; |
| + grub_memset (hw_addr->mac, -1, hw_addr->len); |
| return GRUB_ERR_NONE; |
| } |
| |
| @@ -137,6 +138,7 @@ grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf, |
| && ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff)) |
| { |
| hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET; |
| + hw_addr->len = inf->card->default_address.len; |
| hw_addr->mac[0] = 0x33; |
| hw_addr->mac[1] = 0x33; |
| hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff); |
| @@ -757,23 +759,21 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf) |
| void |
| grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str) |
| { |
| - str[0] = 0; |
| - switch (addr->type) |
| + char *ptr; |
| + unsigned i; |
| + |
| + if (addr->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE) |
| { |
| - case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: |
| - { |
| - char *ptr; |
| - unsigned i; |
| - for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++) |
| - { |
| - grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str), |
| - "%02x:", addr->mac[i] & 0xff); |
| - ptr += (sizeof ("XX:") - 1); |
| - } |
| - return; |
| - } |
| + str[0] = 0; |
| + grub_printf (_("Unsupported hw address type %d len %d\n"), |
| + addr->type, addr->len); |
| + return; |
| + } |
| + for (ptr = str, i = 0; i < addr->len; i++) |
| + { |
| + ptr += grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str), |
| + "%02x:", addr->mac[i] & 0xff); |
| } |
| - grub_printf (_("Unsupported hw address type %d\n"), addr->type); |
| } |
| |
| int |
| @@ -784,13 +784,17 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a, |
| return -1; |
| if (a->type > b->type) |
| return +1; |
| - switch (a->type) |
| + if (a->len < b->len) |
| + return -1; |
| + if (a->len > b->len) |
| + return +1; |
| + if (a->len > GRUB_NET_MAX_LINK_ADDRESS_SIZE) |
| { |
| - case GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET: |
| - return grub_memcmp (a->mac, b->mac, sizeof (a->mac)); |
| + grub_printf (_("Unsupported hw address type %d len %d\n"), |
| + a->type, a->len); |
| + return + 1; |
| } |
| - grub_printf (_("Unsupported hw address type %d\n"), a->type); |
| - return 1; |
| + return grub_memcmp (a->mac, b->mac, a->len); |
| } |
| |
| int |
| diff --git a/include/grub/net.h b/include/grub/net.h |
| index de51894cb..e9ebc6a1b 100644 |
| |
| |
| @@ -29,7 +29,8 @@ |
| |
| enum |
| { |
| - GRUB_NET_MAX_LINK_HEADER_SIZE = 64, |
| + GRUB_NET_MAX_LINK_HEADER_SIZE = 96, |
| + GRUB_NET_MAX_LINK_ADDRESS_SIZE = 32, |
| GRUB_NET_UDP_HEADER_SIZE = 8, |
| GRUB_NET_TCP_HEADER_SIZE = 20, |
| GRUB_NET_OUR_IPV4_HEADER_SIZE = 20, |
| @@ -42,15 +43,17 @@ enum |
| |
| typedef enum grub_link_level_protocol_id |
| { |
| - GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET |
| + /* IANA ARP constant to define hardware type. */ |
| + GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET = 1, |
| } grub_link_level_protocol_id_t; |
| |
| typedef struct grub_net_link_level_address |
| { |
| grub_link_level_protocol_id_t type; |
| + grub_uint8_t len; |
| union |
| { |
| - grub_uint8_t mac[6]; |
| + grub_uint8_t mac[GRUB_NET_MAX_LINK_ADDRESS_SIZE]; |
| }; |
| } grub_net_link_level_address_t; |
| |
| @@ -555,11 +558,13 @@ grub_net_addr_cmp (const grub_net_network_level_address_t *a, |
| #define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX") |
| |
| /* |
| - Currently suppoerted adresses: |
| - ethernet: XX:XX:XX:XX:XX:XX |
| + Up to 32 byte hardware address supported, see GRUB_NET_MAX_LINK_ADDRESS_SIZE |
| */ |
| - |
| -#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX")) |
| +#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof (\ |
| + "XX:XX:XX:XX:XX:XX:XX:XX:"\ |
| + "XX:XX:XX:XX:XX:XX:XX:XX:"\ |
| + "XX:XX:XX:XX:XX:XX:XX:XX:"\ |
| + "XX:XX:XX:XX:XX:XX:XX:XX")) |
| |
| void |
| grub_net_addr_to_str (const grub_net_network_level_address_t *target, |