return false;
}
+/* Attempts to parse 's' as an Ethernet address. If successful, stores the
+ * address in 'ea' and returns true, otherwise zeros 'ea' and returns
+ * false. This function checks trailing characters. */
bool
eth_addr_from_string(const char *s, struct eth_addr *ea)
{
- if (ovs_scan(s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(*ea))) {
+ int n = 0;
+ if (ovs_scan(s, ETH_ADDR_SCAN_FMT"%n", ETH_ADDR_SCAN_ARGS(*ea), &n)
+ && !s[n]) {
return true;
} else {
*ea = eth_addr_zero;
return inet_pton(AF_INET, s, ip) == 1;
}
+/* Parses string 's', which must be an IP address with a port number
+ * with ":" as a separator (e.g.: 192.168.1.2:80).
+ * Stores the IP address into '*ip' and port number to '*port'. */
+char * OVS_WARN_UNUSED_RESULT
+ip_parse_port(const char *s, ovs_be32 *ip, ovs_be16 *port)
+{
+ int n = 0;
+ if (!ovs_scan_len(s, &n, IP_PORT_SCAN_FMT,
+ IP_PORT_SCAN_ARGS(ip, port))) {
+ return xasprintf("%s: invalid IP address or port number", s);
+ }
+
+ if (s[n]) {
+ return xasprintf("%s: invalid IP address or port number", s);
+ }
+ return NULL;
+}
+
/* Parses string 's', which must be an IP address with an optional netmask or
* CIDR prefix length. Stores the IP address into '*ip', netmask into '*mask',
* (255.255.255.255, if 's' lacks a netmask), and number of scanned characters
dp_packet_set_l3(b, arp);
}
-/* This function expect packet with ethernet header with correct
+/* This function expects packet with ethernet header with correct
* l3 pointer set. */
static void *
-compose_ipv6(struct dp_packet *packet, uint8_t proto, const ovs_be32 src[4],
- const ovs_be32 dst[4], uint8_t key_tc, ovs_be32 key_fl,
- uint8_t key_hl, int size)
+compose_ipv6(struct dp_packet *packet, uint8_t proto,
+ const struct in6_addr *src, const struct in6_addr *dst,
+ uint8_t key_tc, ovs_be32 key_fl, uint8_t key_hl, int size)
{
struct ip6_hdr *nh;
void *data;
+ /* Copy 'src' and 'dst' to temporary buffers to prevent misaligned
+ * accesses. */
+ ovs_be32 sbuf[4], dbuf[4];
+ memcpy(sbuf, src, sizeof sbuf);
+ memcpy(dbuf, dst, sizeof dbuf);
+
nh = dp_packet_l3(packet);
nh->ip6_vfc = 0x60;
nh->ip6_nxt = proto;
nh->ip6_plen = htons(size);
data = dp_packet_put_zeros(packet, size);
dp_packet_set_l4(packet, data);
- packet_set_ipv6(packet, src, dst, key_tc, key_fl, key_hl);
+ packet_set_ipv6(packet, sbuf, dbuf, key_tc, key_fl, key_hl);
return data;
}
+/* Compose an IPv6 Neighbor Discovery Neighbor Solicitation message. */
void
-compose_nd(struct dp_packet *b, const struct eth_addr eth_src,
- struct in6_addr *ipv6_src, struct in6_addr *ipv6_dst)
+compose_nd_ns(struct dp_packet *b, const struct eth_addr eth_src,
+ const struct in6_addr *ipv6_src, const struct in6_addr *ipv6_dst)
{
struct in6_addr sn_addr;
struct eth_addr eth_dst;
ipv6_multicast_to_ethernet(ð_dst, &sn_addr);
eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
- ns = compose_ipv6(b, IPPROTO_ICMPV6,
- ALIGNED_CAST(ovs_be32 *, ipv6_src->s6_addr),
- ALIGNED_CAST(ovs_be32 *, sn_addr.s6_addr),
- 0, 0, 255,
- ND_MSG_LEN + ND_OPT_LEN);
+ ns = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, &sn_addr,
+ 0, 0, 255, ND_MSG_LEN + ND_OPT_LEN);
ns->icmph.icmp6_type = ND_NEIGHBOR_SOLICIT;
ns->icmph.icmp6_code = 0;
nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
nd_opt->nd_opt_len = 1;
- packet_set_nd(b, ALIGNED_CAST(ovs_be32 *, ipv6_dst->s6_addr),
- eth_src, eth_addr_zero);
+ /* Copy target address to temp buffer to prevent misaligned access. */
+ ovs_be32 tbuf[4];
+ memcpy(tbuf, ipv6_dst->s6_addr, sizeof tbuf);
+ packet_set_nd(b, tbuf, eth_src, eth_addr_zero);
+
ns->icmph.icmp6_cksum = 0;
icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b));
ns->icmph.icmp6_cksum = csum_finish(csum_continue(icmp_csum, ns,
ND_MSG_LEN + ND_OPT_LEN));
}
+/* Compose an IPv6 Neighbor Discovery Neighbor Advertisement message. */
void
-compose_na(struct dp_packet *b,
- const struct eth_addr eth_src, const struct eth_addr eth_dst,
- const ovs_be32 ipv6_src[4], const ovs_be32 ipv6_dst[4],
- ovs_be32 rso_flags)
+compose_nd_na(struct dp_packet *b,
+ const struct eth_addr eth_src, const struct eth_addr eth_dst,
+ const struct in6_addr *ipv6_src, const struct in6_addr *ipv6_dst,
+ ovs_be32 rso_flags)
{
struct ovs_nd_msg *na;
struct ovs_nd_opt *nd_opt;
uint32_t icmp_csum;
eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN);
- na = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst, 0, 0, 255,
- ND_MSG_LEN + ND_OPT_LEN);
+ na = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst,
+ 0, 0, 255, ND_MSG_LEN + ND_OPT_LEN);
na->icmph.icmp6_type = ND_NEIGHBOR_ADVERT;
na->icmph.icmp6_code = 0;
nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
nd_opt->nd_opt_len = 1;
- packet_set_nd(b, ipv6_src, eth_addr_zero, eth_src);
+ /* Copy target address to temp buffer to prevent misaligned access. */
+ ovs_be32 tbuf[4];
+ memcpy(tbuf, ipv6_src->s6_addr, sizeof tbuf);
+ packet_set_nd(b, tbuf, eth_addr_zero, eth_src);
+
na->icmph.icmp6_cksum = 0;
icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b));
na->icmph.icmp6_cksum = csum_finish(csum_continue(icmp_csum, na,