int i;
grub_size_t addrlen;
grub_uint16_t etherpro;
+ grub_uint8_t *nbd;
if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
{
grub_memcpy (aux, &proto_addr->ipv4, 4);
grub_memset (&target_hw_addr.mac, 0xff, 6);
+ nbd = nb.data;
send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP);
for (i = 0; i < GRUB_NET_TRIES; i++)
{
grub_net_poll_cards (GRUB_NET_INTERVAL);
if (grub_net_link_layer_resolve_check (inf, proto_addr))
return GRUB_ERR_NONE;
+ nb.data = nbd;
send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP);
}
return GRUB_ERR_NONE;
sender_hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
- grub_memcpy (sender_hw_addr.mac, &sender_hardware_address,
+ grub_memcpy (sender_hw_addr.mac, sender_hardware_address,
sizeof (sender_hw_addr.mac));
grub_net_link_layer_add_address (card, &sender_addr, &sender_hw_addr, 1);
&ifaces[j].address,
&target);
- err = grub_net_send_ip_packet (&ifaces[j], &target, nb,
+ err = grub_net_send_ip_packet (&ifaces[j], &target, NULL, nb,
GRUB_NET_IP_UDP);
grub_netbuff_free (nb);
if (err)
icmphr->checksum = 0;
icmphr->checksum = grub_net_ip_chksum ((void *) nb_reply->data,
nb_reply->tail - nb_reply->data);
- err = grub_net_send_ip_packet (inf, src, nb_reply, GRUB_NET_IP_ICMP);
+ /* FIXME: gateway pings. */
+ err = grub_net_send_ip_packet (inf, src, NULL,
+ nb_reply, GRUB_NET_IP_ICMP);
ping_fail:
grub_netbuff_free (nb);
GRUB_NET_IP_ICMPV6,
&inf->address,
source);
- err = grub_net_send_ip_packet (inf, source, nb_reply,
+ /* FIXME: gateway pings. */
+ err = grub_net_send_ip_packet (inf, source, NULL, nb_reply,
GRUB_NET_IP_ICMPV6);
ping_fail:
GRUB_NET_IP_ICMPV6,
&inf->address,
source);
- err = grub_net_send_ip_packet (inf, source, nb_reply,
+ err = grub_net_send_ip_packet (inf, source, NULL, nb_reply,
GRUB_NET_IP_ICMPV6);
ndp_fail:
for (slaac = card->slaac_list; slaac; slaac = slaac->next)
{
grub_net_network_level_address_t addr;
+ grub_net_network_level_netaddress_t netaddr;
+
if (slaac->address.type
!= GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET)
continue;
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
addr.ipv6[0] = opt->prefix[0];
addr.ipv6[1] = grub_net_ipv6_get_id (&slaac->address);
+ netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+ netaddr.ipv6.base[0] = opt->prefix[0];
+ netaddr.ipv6.base[1] = 0;
+ netaddr.ipv6.masksize = 64;
+
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
{
if (inf->card == card
+ sizeof (":XXXXXXXXXXXXXXXXXXXX")];
grub_snprintf (name, sizeof (name), "%s:%d",
slaac->name, slaac->slaac_counter++);
- grub_net_add_addr (name,
- card, &addr,
- &slaac->address, 0);
+ inf = grub_net_add_addr (name,
+ card, &addr,
+ &slaac->address, 0);
+ grub_net_add_route (name, netaddr, inf);
}
}
}
struct neighbour_solicit *sol;
struct icmp_header *icmphr;
grub_net_network_level_address_t multicast;
-
+ grub_uint8_t *nbd;
multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
multicast.ipv6[0] = grub_be_to_cpu64_compile_time (0xff02ULL << 48);
multicast.ipv6[1] = (grub_be_to_cpu64_compile_time (0x01ff000000ULL)
goto fail;
ohdr = (struct option_header *) nb->data;
- ohdr->type = OPTION_TARGET_LINK_LAYER_ADDRESS;
+ ohdr->type = OPTION_SOURCE_LINK_LAYER_ADDRESS;
ohdr->len = 1;
err = grub_netbuff_push (nb, sizeof (*sol));
if (err)
goto fail;
icmphr = (struct icmp_header *) nb->data;
- icmphr->type = ICMP6_NEIGHBOUR_ADVERTISE;
+ icmphr->type = ICMP6_NEIGHBOUR_SOLICIT;
icmphr->code = 0;
icmphr->checksum = 0;
icmphr->checksum = grub_net_ip_transport_checksum (nb,
GRUB_NET_IP_ICMPV6,
&inf->address,
&multicast);
- err = grub_net_send_ip_packet (inf, &multicast, nb,
+ nbd = nb->data;
+ err = grub_net_send_ip_packet (inf, &multicast, NULL, nb,
GRUB_NET_IP_ICMPV6);
if (err)
goto fail;
grub_net_poll_cards (GRUB_NET_INTERVAL);
if (grub_net_link_layer_resolve_check (inf, proto_addr))
break;
- err = grub_net_send_ip_packet (inf, &multicast, nb,
+ nb->data = nbd;
+ err = grub_net_send_ip_packet (inf, &multicast, NULL, nb,
GRUB_NET_IP_ICMPV6);
if (err)
break;
}
static grub_err_t
-grub_net_send_ip4_packet (struct grub_net_network_level_interface * inf,
- const grub_net_network_level_address_t * target,
- struct grub_net_buff * nb,
+grub_net_send_ip4_packet (struct grub_net_network_level_interface *inf,
+ const grub_net_network_level_address_t *target,
+ const grub_net_network_level_address_t *gw,
+ struct grub_net_buff *nb,
grub_net_ip_protocol_t proto)
{
struct iphdr *iph;
COMPILE_TIME_ASSERT (GRUB_NET_OUR_IPV4_HEADER_SIZE == sizeof (*iph));
/* Determine link layer target address via ARP. */
- err = grub_net_link_layer_resolve (inf, target, &ll_target_addr);
+ err = grub_net_link_layer_resolve (inf, gw ? : target, &ll_target_addr);
if (err)
return err;
}
static grub_err_t
-grub_net_send_ip6_packet (struct grub_net_network_level_interface * inf,
- const grub_net_network_level_address_t * target,
- struct grub_net_buff * nb,
+grub_net_send_ip6_packet (struct grub_net_network_level_interface *inf,
+ const grub_net_network_level_address_t *target,
+ const grub_net_network_level_address_t *gw,
+ struct grub_net_buff *nb,
grub_net_ip_protocol_t proto)
{
struct ip6hdr *iph;
COMPILE_TIME_ASSERT (GRUB_NET_OUR_IPV6_HEADER_SIZE == sizeof (*iph));
/* Determine link layer target address via ARP. */
- err = grub_net_link_layer_resolve (inf, target, &ll_target_addr);
+ err = grub_net_link_layer_resolve (inf, gw ? : target, &ll_target_addr);
if (err)
return err;
}
grub_err_t
-grub_net_send_ip_packet (struct grub_net_network_level_interface * inf,
- const grub_net_network_level_address_t * target,
- struct grub_net_buff * nb,
+grub_net_send_ip_packet (struct grub_net_network_level_interface *inf,
+ const grub_net_network_level_address_t *target,
+ const grub_net_network_level_address_t *gw,
+ struct grub_net_buff *nb,
grub_net_ip_protocol_t proto)
{
switch (target->type)
{
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
- return grub_net_send_ip4_packet (inf, target, nb, proto);
+ return grub_net_send_ip4_packet (inf, target, gw, nb, proto);
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
- return grub_net_send_ip6_packet (inf, target, nb, proto);
+ return grub_net_send_ip6_packet (inf, target, gw, nb, proto);
default:
return grub_error (GRUB_ERR_BAD_ARGUMENT, "not an IP");
}
return GRUB_ERR_NONE;
}
-
-
/* Check cache table. */
entry = link_layer_find_entry (proto_addr, inf->card);
if (entry)
parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
{
grub_uint32_t newip = 0;
- unsigned long t;
int i;
const char *ptr = val;
for (i = 0; i < 4; i++)
{
+ unsigned long t;
t = grub_strtoul (ptr, (char **) &ptr, 0);
if (grub_errno)
{
grub_errno = GRUB_ERR_NONE;
return 0;
}
+ if (*ptr != '.' && i == 0)
+ {
+ newip = t;
+ break;
+ }
if (t & ~0xff)
return 0;
newip >>= 8;
}
*ip = grub_cpu_to_le32 (newip);
if (rest)
- *rest = ptr - 1;
+ *rest = (ptr - 1);
+ return 1;
+}
+
+static int
+parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
+{
+ grub_uint16_t newip[8];
+ const char *ptr = val;
+ int word, quaddot = -1;
+
+ if (ptr[0] == ':' && ptr[1] != ':')
+ return 0;
+ if (ptr[0] == ':')
+ ptr++;
+
+ for (word = 0; word < 8; word++)
+ {
+ unsigned long t;
+ if (*ptr == ':')
+ {
+ quaddot = word;
+ word--;
+ ptr++;
+ continue;
+ }
+ t = grub_strtoul (ptr, (char **) &ptr, 16);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ break;
+ }
+ if (t & ~0xffff)
+ return 0;
+ newip[word] = grub_cpu_to_be16 (t);
+ if (*ptr != ':')
+ break;
+ ptr++;
+ }
+ if (quaddot == -1 && word < 7)
+ return 0;
+ if (quaddot != -1)
+ {
+ grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
+ (word - quaddot + 1) * sizeof (newip[0]));
+ grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
+ }
+ grub_memcpy (ip, newip, 16);
+ if (rest)
+ *rest = ptr;
return 1;
}
}
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
{
- grub_int64_t mask[2];
- mask[1] = 0xffffffffffffffffULL << (128 - net->ipv6.masksize);
- if (net->ipv6.masksize < 64)
- mask[0] = 0xffffffffffffffffULL;
+ grub_uint64_t mask[2];
+ if (net->ipv6.masksize <= 64)
+ {
+ mask[0] = 0xffffffffffffffffULL << (64 - net->ipv6.masksize);
+ mask[1] = 0;
+ }
else
- mask[0] = 0xffffffffffffffffULL << (64 - net->ipv6.masksize);
+ {
+ mask[0] = 0xffffffffffffffffULL;
+ mask[1] = 0xffffffffffffffffULL << (128 - net->ipv6.masksize);
+ }
return (((grub_be_to_cpu64 (net->ipv6.base[0]) & mask[0])
- == (grub_be_to_cpu32 (addr->ipv6[0]) & mask[0]))
+ == (grub_be_to_cpu64 (addr->ipv6[0]) & mask[0]))
&& ((grub_be_to_cpu64 (net->ipv6.base[1]) & mask[1])
- == (grub_be_to_cpu32 (addr->ipv6[1]) & mask[1])));
+ == (grub_be_to_cpu64 (addr->ipv6[1]) & mask[1])));
}
}
return 0;
grub_net_resolve_address (const char *name,
grub_net_network_level_address_t *addr)
{
- if (parse_ip (name, &addr->ipv4, NULL))
+ const char *rest;
+ if (parse_ip (name, &addr->ipv4, &rest) && *rest == 0)
{
addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
return GRUB_ERR_NONE;
}
+ if (parse_ip6 (name, addr->ipv6, &rest) && *rest == 0)
+ {
+ addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+ return GRUB_ERR_NONE;
+ }
return grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("unrecognised address %s"),
name);
}
addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
if (*rest == '/')
{
- addr->ipv4.masksize = grub_strtoul (rest + 1, NULL, 0);
- if (!grub_errno)
- return GRUB_ERR_NONE;
+ addr->ipv4.masksize = grub_strtoul (rest + 1, (char **) &rest, 0);
+ if (!grub_errno && *rest == 0)
+ return GRUB_ERR_NONE;
+ grub_errno = GRUB_ERR_NONE;
+ }
+ else if (*rest == 0)
+ {
+ addr->ipv4.masksize = 32;
+ return GRUB_ERR_NONE;
+ }
+ }
+ if (parse_ip6 (name, addr->ipv6.base, &rest))
+ {
+ addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+ if (*rest == '/')
+ {
+ addr->ipv6.masksize = grub_strtoul (rest + 1, (char **) &rest, 0);
+ if (!grub_errno && *rest == 0)
+ return GRUB_ERR_NONE;
+ grub_errno = GRUB_ERR_NONE;
+ }
+ else if (*rest == 0)
+ {
+ addr->ipv6.masksize = 128;
+ return GRUB_ERR_NONE;
}
- addr->ipv4.masksize = 32;
- return GRUB_ERR_NONE;
}
return grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("unrecognised address %s"),
name);
void *recv);
void (*error_hook) (grub_net_tcp_socket_t sock, void *recv);
void *hook_data;
- grub_net_network_level_address_t out_nla;
+ grub_net_network_level_address_t out_nla, gw;
struct grub_net_network_level_interface *inf;
grub_net_packets_t packs;
grub_priority_queue_t pq;
socket->unack_last->next = unack;
}
- err = grub_net_send_ip_packet (socket->inf, &(socket->out_nla), nb,
- GRUB_NET_IP_TCP);
+ err = grub_net_send_ip_packet (socket->inf, &(socket->out_nla),
+ &(socket->gw),nb, GRUB_NET_IP_TCP);
if (err)
return err;
nb->data = nbd;
sock->recv_hook = NULL;
nb_fin = grub_netbuff_alloc (sizeof (*tcph_fin)
- + GRUB_NET_OUR_IPV4_HEADER_SIZE
+ + GRUB_NET_OUR_MAX_IP_HEADER_SIZE
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
if (!nb_fin)
return;
- err = grub_netbuff_reserve (nb_fin, GRUB_NET_OUR_IPV4_HEADER_SIZE
+ err = grub_netbuff_reserve (nb_fin, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
if (err)
{
unack->try_count++;
unack->last_try = ctime;
nbd = unack->nb->data;
- err = grub_net_send_ip_packet (sock->inf, &(sock->out_nla), unack->nb,
+ err = grub_net_send_ip_packet (sock->inf, &(sock->out_nla),
+ &(sock->gw), unack->nb,
GRUB_NET_IP_TCP);
unack->nb->data = nbd;
if (err)
sock->error_hook = error_hook;
sock->hook_data = hook_data;
nb_ack = grub_netbuff_alloc (sizeof (*tcph)
- + GRUB_NET_OUR_IPV4_HEADER_SIZE
+ + GRUB_NET_OUR_MAX_IP_HEADER_SIZE
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
if (!nb_ack)
return grub_errno;
- err = grub_netbuff_reserve (nb_ack, GRUB_NET_OUR_IPV4_HEADER_SIZE
+ err = grub_netbuff_reserve (nb_ack, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
if (err)
{
if (err)
return NULL;
- if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
+ if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
+ && addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6)
{
- grub_error (GRUB_ERR_BAD_ARGUMENT, "not a IPv4 address");
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "not an IP address");
return NULL;
}
socket->out_port = out_port;
socket->inf = inf;
socket->out_nla = addr;
+ socket->gw = gateway;
socket->in_port = in_port++;
socket->recv_hook = recv_hook;
socket->error_hook = error_hook;
{
int j;
nb->data = nbd;
- err = grub_net_send_ip_packet (socket->inf, &(socket->out_nla), nb,
+ err = grub_net_send_ip_packet (socket->inf, &(socket->out_nla),
+ &(socket->gw), nb,
GRUB_NET_IP_TCP);
if (err)
{
grub_err_t err;
grub_ssize_t fraglen;
COMPILE_TIME_ASSERT (sizeof (struct tcphdr) == GRUB_NET_TCP_HEADER_SIZE);
- fraglen = (socket->inf->card->mtu - GRUB_NET_OUR_IPV4_HEADER_SIZE
- - sizeof (*tcph));
+ if (socket->out_nla.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
+ fraglen = (socket->inf->card->mtu - GRUB_NET_OUR_IPV4_HEADER_SIZE
+ - sizeof (*tcph));
+ else
+ fraglen = 1280 - GRUB_NET_OUR_IPV6_HEADER_SIZE;
while (nb->tail - nb->data > fraglen)
{
struct grub_net_buff *nb2;
nb2 = grub_netbuff_alloc (fraglen + sizeof (*tcph)
- + GRUB_NET_OUR_IPV4_HEADER_SIZE
+ + GRUB_NET_OUR_MAX_IP_HEADER_SIZE
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
if (!nb2)
return grub_errno;
err = grub_netbuff_reserve (nb2, GRUB_NET_MAX_LINK_HEADER_SIZE
- + GRUB_NET_OUR_IPV4_HEADER_SIZE);
+ + GRUB_NET_OUR_MAX_IP_HEADER_SIZE);
if (err)
return err;
err = grub_netbuff_put (nb2, sizeof (*tcph));
if (!(grub_be_to_cpu16 (tcph->dst) == sock->in_port
&& grub_be_to_cpu16 (tcph->src) == sock->out_port
&& inf == sock->inf
- && source->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
- && source->ipv4 == sock->out_nla.ipv4))
+ && grub_net_addr_cmp (source, &sock->out_nla) == 0))
continue;
if (tcph->checksum)
{
grub_err_t (*recv_hook) (grub_net_udp_socket_t sock, struct grub_net_buff *nb,
void *recv);
void *recv_hook_data;
- grub_net_network_level_address_t out_nla;
+ grub_net_network_level_address_t out_nla, gw;
struct grub_net_network_level_interface *inf;
};
if (err)
return NULL;
- if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
+ if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
+ && addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6)
{
- grub_error (GRUB_ERR_BAD_ARGUMENT, "not a IPv4 address");
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "not an IP address");
return NULL;
}
socket->out_port = out_port;
socket->inf = inf;
socket->out_nla = addr;
+ socket->gw = gateway;
socket->in_port = in_port++;
socket->status = GRUB_NET_SOCKET_START;
socket->recv_hook = recv_hook;
&socket->inf->address,
&socket->out_nla);
- return grub_net_send_ip_packet (socket->inf, &(socket->out_nla), nb,
- GRUB_NET_IP_UDP);
+ return grub_net_send_ip_packet (socket->inf, &(socket->out_nla),
+ &(socket->gw), nb, GRUB_NET_IP_UDP);
}
grub_err_t
{
if (grub_be_to_cpu16 (udph->dst) == sock->in_port
&& inf == sock->inf
- && source->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
- && source->ipv4 == sock->out_nla.ipv4
+ && grub_net_addr_cmp (source, &sock->out_nla) == 0
&& (sock->status == GRUB_NET_SOCKET_START
|| grub_be_to_cpu16 (udph->src) == sock->out_port))
{
GRUB_NET_TCP_HEADER_SIZE = 20,
GRUB_NET_OUR_IPV4_HEADER_SIZE = 20,
GRUB_NET_OUR_IPV6_HEADER_SIZE = 40,
+ GRUB_NET_OUR_MAX_IP_HEADER_SIZE = 40,
GRUB_NET_TCP_RESERVE_SIZE = GRUB_NET_TCP_HEADER_SIZE
+ GRUB_NET_OUR_IPV4_HEADER_SIZE
+ GRUB_NET_MAX_LINK_HEADER_SIZE
grub_err_t
grub_net_send_ip_packet (struct grub_net_network_level_interface *inf,
const grub_net_network_level_address_t *target,
+ const grub_net_network_level_address_t *gw,
struct grub_net_buff *nb,
grub_net_ip_protocol_t proto);
grub_uint8_t *end;
};
-grub_err_t grub_netbuff_put (struct grub_net_buff *net_buff ,grub_size_t len);
-grub_err_t grub_netbuff_unput (struct grub_net_buff *net_buff ,grub_size_t len);
-grub_err_t grub_netbuff_push (struct grub_net_buff *net_buff ,grub_size_t len);
-grub_err_t grub_netbuff_pull (struct grub_net_buff *net_buff ,grub_size_t len);
-grub_err_t grub_netbuff_reserve (struct grub_net_buff *net_buff ,grub_size_t len);
+grub_err_t grub_netbuff_put (struct grub_net_buff *net_buff, grub_size_t len);
+grub_err_t grub_netbuff_unput (struct grub_net_buff *net_buff, grub_size_t len);
+grub_err_t grub_netbuff_push (struct grub_net_buff *net_buff, grub_size_t len);
+grub_err_t grub_netbuff_pull (struct grub_net_buff *net_buff, grub_size_t len);
+grub_err_t grub_netbuff_reserve (struct grub_net_buff *net_buff, grub_size_t len);
grub_err_t grub_netbuff_clear (struct grub_net_buff *net_buff);
-struct grub_net_buff * grub_netbuff_alloc ( grub_size_t len );
+struct grub_net_buff * grub_netbuff_alloc (grub_size_t len);
grub_err_t grub_netbuff_free (struct grub_net_buff *net_buff);
#endif