Beispiel #1
0
static int parse_layer4(struct packet *packet, u8 *layer4_start,
			int layer4_protocol, int layer4_bytes,
			u8 *packet_end, bool *is_inner, char **error)
{
	if (layer4_protocol == IPPROTO_TCP) {
		*is_inner = true;	/* found inner-most layer 4 */
		return parse_tcp(packet, layer4_start, layer4_bytes, packet_end,
				 error);
	} else if (layer4_protocol == IPPROTO_UDP) {
		*is_inner = true;	/* found inner-most layer 4 */
		return parse_udp(packet, layer4_start, layer4_bytes, packet_end,
				 error);
	} else if (layer4_protocol == IPPROTO_ICMP) {
		*is_inner = true;	/* found inner-most layer 4 */
		return parse_icmpv4(packet, layer4_start, layer4_bytes,
				    packet_end, error);
	} else if (layer4_protocol == IPPROTO_ICMPV6) {
		*is_inner = true;	/* found inner-most layer 4 */
		return parse_icmpv6(packet, layer4_start, layer4_bytes,
				    packet_end, error);
	} else if (layer4_protocol == IPPROTO_GRE) {
		*is_inner = false;
		return parse_gre(packet, layer4_start, layer4_bytes, packet_end,
				 error);
	} else if (layer4_protocol == IPPROTO_IPIP) {
		*is_inner = false;
		return parse_ipv4(packet, layer4_start, packet_end, error);
	} else if (layer4_protocol == IPPROTO_IPV6) {
		*is_inner = false;
		return parse_ipv6(packet, layer4_start, packet_end, error);
	}
	return PACKET_UNKNOWN_L4;
}
Beispiel #2
0
static int parse_layer3_packet(struct packet *packet,
			       u8 *header_start, u8 *packet_end,
			       char **error)
{
	u8 *p = header_start;
	/* Note that packet_end points to the byte beyond the end of packet. */
	struct ipv4 *ip = NULL;

	/* Examine IPv4/IPv6 header. */
	if (p + sizeof(struct ipv4) > packet_end) {
		asprintf(error, "IP header overflows packet");
		return PACKET_BAD;
	}

	/* Look at the IP version number, which is in the first 4 bits
	 * of both IPv4 and IPv6 packets.
	 */
	ip = (struct ipv4 *) (p);
	if (ip->version == 4)
		return parse_ipv4(packet, p, packet_end, error);
	else if (ip->version == 6)
		return parse_ipv6(packet, p, packet_end, error);

	asprintf(error, "Unsupported IP version");
	return PACKET_BAD;
}
Beispiel #3
0
static int parse_layer3_packet_by_proto(struct packet *packet,
					u16 proto, u8 *header_start,
					u8 *packet_end, char **error)
{
	u8 *p = header_start;

	if (proto == ETHERTYPE_IP) {
		struct ipv4 *ip = NULL;

		/* Examine IPv4 header. */
		if (p + sizeof(struct ipv4) > packet_end) {
			asprintf(error, "IPv4 header overflows packet");
			goto error_out;
		}

		/* Look at the IP version number, which is in the first 4 bits
		 * of both IPv4 and IPv6 packets.
		 */
		ip = (struct ipv4 *)p;
		if (ip->version == 4) {
			return parse_ipv4(packet, p, packet_end, error);
		} else {
			asprintf(error, "Bad IP version for ETHERTYPE_IP");
			goto error_out;
		}
	} else if (proto == ETHERTYPE_IPV6) {
		struct ipv6 *ip = NULL;

		/* Examine IPv6 header. */
		if (p + sizeof(struct ipv6) > packet_end) {
			asprintf(error, "IPv6 header overflows packet");
			goto error_out;
		}

		/* Look at the IP version number, which is in the first 4 bits
		 * of both IPv4 and IPv6 packets.
		 */
		ip = (struct ipv6 *)p;
		if (ip->version == 6) {
			return parse_ipv6(packet, p, packet_end, error);
		} else {
			asprintf(error, "Bad IP version for ETHERTYPE_IPV6");
			goto error_out;
		}
	} else if ((proto == ETHERTYPE_MPLS_UC) ||
		   (proto == ETHERTYPE_MPLS_MC)) {
		return parse_mpls(packet, p, packet_end, error);
	} else {
		return PACKET_UNKNOWN_L4;
	}

error_out:
	return PACKET_BAD;
}
Beispiel #4
0
static grpc_resolver* fake_resolver_create(grpc_resolver_factory* factory,
                                           grpc_resolver_args* args) {
  if (0 != strcmp(args->uri->authority, "")) {
    gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
            args->uri->scheme);
    return NULL;
  }
  // Get lb_enabled arg.  Anything other than "0" is interpreted as true.
  const char* lb_enabled_qpart =
      grpc_uri_get_query_arg(args->uri, "lb_enabled");
  const bool lb_enabled =
      lb_enabled_qpart != NULL && strcmp("0", lb_enabled_qpart) != 0;
  // Construct addresses.
  gpr_slice path_slice =
      gpr_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
  gpr_slice_buffer path_parts;
  gpr_slice_buffer_init(&path_parts);
  gpr_slice_split(path_slice, ",", &path_parts);
  grpc_lb_addresses* addresses = grpc_lb_addresses_create(path_parts.count);
  bool errors_found = false;
  for (size_t i = 0; i < addresses->num_addresses; i++) {
    grpc_uri ith_uri = *args->uri;
    char* part_str = gpr_dump_slice(path_parts.slices[i], GPR_DUMP_ASCII);
    ith_uri.path = part_str;
    if (!parse_ipv4(
            &ith_uri,
            (struct sockaddr_storage*)(&addresses->addresses[i].address.addr),
            &addresses->addresses[i].address.len)) {
      errors_found = true;
    }
    gpr_free(part_str);
    addresses->addresses[i].is_balancer = lb_enabled;
    if (errors_found) break;
  }
  gpr_slice_buffer_destroy(&path_parts);
  gpr_slice_unref(path_slice);
  if (errors_found) {
    grpc_lb_addresses_destroy(addresses, NULL /* user_data_destroy */);
    return NULL;
  }
  // Instantiate resolver.
  fake_resolver* r = gpr_malloc(sizeof(fake_resolver));
  memset(r, 0, sizeof(*r));
  r->target_name = gpr_strdup(args->uri->path);
  r->addresses = addresses;
  r->lb_policy_name =
      gpr_strdup(grpc_uri_get_query_arg(args->uri, "lb_policy"));
  gpr_mu_init(&r->mu);
  grpc_resolver_init(&r->base, &fake_resolver_vtable);
  return &r->base;
}
Beispiel #5
0
/*
  parse an ip
 */
bool parse_ip(const char *addr, const char *ifaces, unsigned port, ctdb_sock_addr *saddr)
{
	char *p;
	bool ret;

	ZERO_STRUCTP(saddr); /* valgrind :-) */

	/* now is this a ipv4 or ipv6 address ?*/
	p = index(addr, ':');
	if (p == NULL) {
		ret = parse_ipv4(addr, port, &saddr->ip);
	} else {
		ret = parse_ipv6(addr, ifaces, port, saddr);
	}

	return ret;
}
Beispiel #6
0
static void test_parse_ipv4(const char *uri_text, const char *host,
                            unsigned short port) {
  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
  grpc_uri *uri = grpc_uri_parse(&exec_ctx, uri_text, 0);
  grpc_resolved_address addr;
  char ntop_buf[INET_ADDRSTRLEN];

  GPR_ASSERT(1 == parse_ipv4(uri, &addr));
  struct sockaddr_in *addr_in = (struct sockaddr_in *)addr.addr;
  GPR_ASSERT(AF_INET == addr_in->sin_family);
  GPR_ASSERT(NULL != grpc_inet_ntop(AF_INET, &addr_in->sin_addr, ntop_buf,
                                    sizeof(ntop_buf)));
  GPR_ASSERT(0 == strcmp(ntop_buf, host));
  GPR_ASSERT(ntohs(addr_in->sin_port) == port);

  grpc_uri_destroy(uri);
  grpc_exec_ctx_finish(&exec_ctx);
}
Beispiel #7
0
/* parse ipv4 or ipv6 address
 */
int parse_ip(str *s, struct ip_addr *ip, unsigned short *port)
{
	if (!s || !s->len) return -1;

	if (memchr(s->s, '.', s->len)) {
		/* ipv4 address */
		if (parse_ipv4(s, ip, port)) {
			LOG(L_ERR, "ERROR: parse_ip(): failed to parse ipv4 iddress: %.*s\n",
					s->len, s->s);
			return -1;
		}
	} else {
		/* ipv6 address */
		if (parse_ipv6(s, ip, port)) {
			LOG(L_ERR, "ERROR: parse_ip(): failed to parse ipv6 iddress: %.*s\n",
					s->len, s->s);
			return -1;
		}
	}

	return 0;
}
Beispiel #8
0
int handle_ingress(struct __sk_buff *skb)
{
	void *data = (void *)(long)skb->data;
	struct ethhdr *eth = data;
	void *data_end = (void *)(long)skb->data_end;
	uint64_t h_proto, nh_off;

	nh_off = sizeof(*eth);
	if (data + nh_off > data_end)
		return 0;

	h_proto = eth->h_proto;

	if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
		struct vlan_hdr *vhdr;

		vhdr = data + nh_off;
		nh_off += sizeof(struct vlan_hdr);
		if (data + nh_off > data_end)
			return 0;
		h_proto = vhdr->h_vlan_encapsulated_proto;
	}
	if (h_proto == ETH_P_8021Q || h_proto == ETH_P_8021AD) {
		struct vlan_hdr *vhdr;

		vhdr = data + nh_off;
		nh_off += sizeof(struct vlan_hdr);
		if (data + nh_off > data_end)
			return 0;
		h_proto = vhdr->h_vlan_encapsulated_proto;
	}
	if (h_proto == htons(ETH_P_IP))
		return parse_ipv4(data, nh_off, data_end);
	else if (h_proto == htons(ETH_P_IPV6))
		return parse_ipv6(data, nh_off, data_end);
	return 0;
}
Beispiel #9
0
/****************************************************************************
 * Parse from text an IPv4 address range. This can be in one of several
 * formats:
 * - '192.168.1.1" - a single address
 * - '192.168.1.0/24" - a CIDR spec
 * - '192.168.1.0-192.168.1.255' - a range
 * @param line
 *      Part of a line of text, probably read from a commandline or conf
 *      file.
 * @param inout_offset
 *      On input, the offset from the start of the line where the address
 *      starts. On output, the offset of the first character after the
 *      range, or equal to 'max' if the line prematurely ended.
 * @param max
 *      The maximum length of the line.
 * @return
 *      The first and last address of the range, inclusive.
 ****************************************************************************/
struct Range
range_parse_ipv4(const char *line, unsigned *inout_offset, unsigned max)
{
    unsigned offset;
    struct Range result;
    static const struct Range badrange = {0xFFFFFFFF, 0};
    int err;


    if (inout_offset == NULL) {
         inout_offset = &offset;
         offset = 0;
         max = (unsigned)strlen(line);
    } else
        offset = *inout_offset;


    /* trim whitespace */
    while (offset < max && isspace(line[offset]&0xFF))
        offset++;

    /* get the first IP address */
    err = parse_ipv4(line, &offset, max, &result.begin);
    if (err) {
        return badrange;
    }
    result.end = result.begin;

    /* trim whitespace */
    while (offset < max && isspace(line[offset]&0xFF))
        offset++;

    /* If onely one IP address, return that */
    if (offset >= max)
        goto end;

    /*
     * Handle CIDR address of the form "10.0.0.0/8"
     */
    if (line[offset] == '/') {
        uint64_t prefix = 0;
        uint64_t mask = 0;
        unsigned digits = 0;

        /* skip slash */
        offset++;

        if (!isdigit(line[offset]&0xFF)) {
            return badrange;
        }

        /* strip leading zeroes */
        while (offset<max && line[offset] == '0')
            offset++;

        /* parse decimal integer */
        while (offset<max && isdigit(line[offset]&0xFF)) {
            prefix = prefix * 10 + (line[offset++] - '0');
            if (++digits > 2)
                return badrange;
        }
        if (prefix > 32)
            return badrange;

        /* Create the mask from the prefix */
        mask = 0xFFFFFFFF00000000ULL >> prefix;

        /* Mask off any non-zero bits from the start
         * TODO print warning */
        result.begin &= mask;

        /* Set all suffix bits to 1, so that 192.168.1.0/24 has
         * an ending address of 192.168.1.255. */
        result.end = result.begin | (unsigned)~mask;
        goto end;
    }
static int
do_client(int port, const char *ipaddrz)
{
	int sockfd;
	struct sockaddr_in addr;
	struct sigaction sigact;
	int i, nwritten;
	char databuf[512];

	bzero(databuf, sizeof (databuf));

	if (parse_ipv4(ipaddrz, &addr) != 0) {
		warnx("failed to parse IP address: %s\n", ipaddrz);
		return (-1);
	}
	addr.sin_port = htons(port);

	bzero(&sigact, sizeof (sigact));
	sigact.sa_sigaction = on_sigpipe;
	if (sigaction(SIGPIPE, &sigact, NULL) != 0) {
		warn("sigaction");
		return (-1);
	}

	log_time();
	(void) printf("connecting to %s port %d\n", ipaddrz, port);

	sockfd = make_tcp_socket();
	if (sockfd < 0) {
		return (-1);
	}

	if (connect(sockfd, (struct sockaddr *)&addr, sizeof (addr)) != 0) {
		warn("connect");
		(void) close(sockfd);
		return (-1);
	}

	log_time();
	(void) printf("connected\n");

	for (i = 0; i < 20; i++) {
		log_time();
		(void) printf("write (%d)\n", i);
		nwritten = write(sockfd, databuf, sizeof (databuf));
		if (nwritten != sizeof (databuf)) {
			log_time();
			if (nwritten < 0) {
				(void) printf(
				    "write returned %d (error %d: %s)\n",
				    nwritten, errno, strerror(errno));
			} else {
				(void) printf("write returned %d\n",
				    nwritten);
			}

			break;
		}

		usleep(500000);
	}

	log_time();
	(void) printf("teardown\n");
	(void) close(sockfd);
	return (0);
}
Beispiel #11
0
static grpc_resolver* fake_resolver_create(grpc_exec_ctx* exec_ctx,
                                           grpc_resolver_factory* factory,
                                           grpc_resolver_args* args) {
  if (0 != strcmp(args->uri->authority, "")) {
    gpr_log(GPR_ERROR, "authority based uri's not supported by the %s scheme",
            args->uri->scheme);
    return NULL;
  }
  // Get lb_enabled arg.  Anything other than "0" is interpreted as true.
  const char* lb_enabled_qpart =
      grpc_uri_get_query_arg(args->uri, "lb_enabled");
  const bool lb_enabled =
      lb_enabled_qpart != NULL && strcmp("0", lb_enabled_qpart) != 0;

  // Get the balancer's names.
  const char* balancer_names =
      grpc_uri_get_query_arg(args->uri, "balancer_names");
  grpc_slice_buffer balancer_names_parts;
  grpc_slice_buffer_init(&balancer_names_parts);
  if (balancer_names != NULL) {
    const grpc_slice balancer_names_slice =
        grpc_slice_from_copied_string(balancer_names);
    grpc_slice_split(balancer_names_slice, ",", &balancer_names_parts);
    grpc_slice_unref(balancer_names_slice);
  }

  // Construct addresses.
  grpc_slice path_slice =
      grpc_slice_new(args->uri->path, strlen(args->uri->path), do_nothing);
  grpc_slice_buffer path_parts;
  grpc_slice_buffer_init(&path_parts);
  grpc_slice_split(path_slice, ",", &path_parts);
  if (balancer_names_parts.count > 0 &&
      path_parts.count != balancer_names_parts.count) {
    gpr_log(GPR_ERROR,
            "Balancer names present but mismatched with number of addresses: "
            "%lu balancer names != %lu addresses",
            (unsigned long)balancer_names_parts.count,
            (unsigned long)path_parts.count);
    return NULL;
  }
  grpc_lb_addresses* addresses =
      grpc_lb_addresses_create(path_parts.count, NULL /* user_data_vtable */);
  bool errors_found = false;
  for (size_t i = 0; i < addresses->num_addresses; i++) {
    grpc_uri ith_uri = *args->uri;
    char* part_str = grpc_slice_to_c_string(path_parts.slices[i]);
    ith_uri.path = part_str;
    if (!parse_ipv4(&ith_uri, &addresses->addresses[i].address)) {
      errors_found = true;
    }
    gpr_free(part_str);
    if (errors_found) break;
    addresses->addresses[i].is_balancer = lb_enabled;
    addresses->addresses[i].balancer_name =
        balancer_names_parts.count > 0
            ? grpc_dump_slice(balancer_names_parts.slices[i], GPR_DUMP_ASCII)
            : NULL;
  }
  grpc_slice_buffer_destroy_internal(exec_ctx, &path_parts);
  grpc_slice_buffer_destroy_internal(exec_ctx, &balancer_names_parts);
  grpc_slice_unref(path_slice);
  if (errors_found) {
    grpc_lb_addresses_destroy(exec_ctx, addresses);
    return NULL;
  }
  // Instantiate resolver.
  fake_resolver* r = gpr_malloc(sizeof(fake_resolver));
  memset(r, 0, sizeof(*r));
  r->channel_args = grpc_channel_args_copy(args->args);
  r->addresses = addresses;
  gpr_mu_init(&r->mu);
  grpc_resolver_init(&r->base, &fake_resolver_vtable);
  return &r->base;
}
Beispiel #12
0
static int parse_hostport(int* type, struct ip_addr* ip, unsigned int* port, 
						  cfg_token_t* token, cfg_parser_t* st)
{
	int ret;
	cfg_token_t t;
    cfg_option_t* opt;

	ret = cfg_get_token(&t, st, 0);
	if (ret < 0) return -1;
	if (ret > 0) {
		ERR("%s:%d:%d: Missing IP address\n", st->file, 
			token->start.line, token->start.col);
		return -1;
	}

	if (t.type == '[') {
		if (parse_ipv6(ip, &t, st) < 0) return -1;
	} else if (t.type == CFG_TOKEN_ALPHA) {
		opt = cfg_lookup_token(token_default, &t.val);
		if (opt) {
			*type = TLS_DOMAIN_DEF;
			     /* Default domain */
			return 0;
		} else {
			if (parse_ipv4(ip, &t, st) < 0) return -1;
		}
	} else {
		ERR("%s:%d:%d: Syntax error, IP address expected\n", 
		    st->file, t.start.line, t.start.col);
		return -1;
	}
	*type = 0;

	     /* Parse port */
	ret = cfg_get_token(&t, st, 0);
	if (ret < 0) return -1;
	if (ret > 0) {
		ERR("%s:%d:%d: Syntax error, ':' expected\n", st->file, st->line, 
			st->col);
		return -1;
	}
	
	if (t.type != ':') {
		ERR("%s:%d:%d: Syntax error, ':' expected\n", 
		    st->file, t.start.line, t.start.col);
		return -1;
	}	
	
	ret = cfg_get_token(&t, st, 0);
	if (ret < 0) return -1;
	if (ret > 0) {
		ERR("%s:%d:%d: Premature end of file, port number missing\n", 
		    st->file, t.start.line, t.start.col);
		return -1;
	}
	
	if (t.type != CFG_TOKEN_ALPHA || (str2int(&t.val, port) < 0)) {
		ERR("%s:%d:%d: Invalid port number '%.*s'\n", 
		    st->file, t.start.line, t.start.col, STR_FMT(&t.val));
		return -1;
	}		
	return 0;
}
Beispiel #13
0
/**
 * Simple packet parser: eth, VLAN, IP, TCP/UDP/ICMP
 *
 * Internal function: caller is resposible for passing only valid packet handles
 * , lengths and offsets (usually done&called in packet input).
 *
 * @param pkt        Packet handle
 * @param len        Packet length in bytes
 * @param frame_offset  Byte offset to L2 header
 */
void odp_packet_parse(odp_packet_t pkt, size_t len, size_t frame_offset)
{
	odp_packet_hdr_t *const pkt_hdr = odp_packet_hdr(pkt);
	odp_ethhdr_t *eth;
	odp_vlanhdr_t *vlan;
	odp_ipv4hdr_t *ipv4;
	odp_ipv6hdr_t *ipv6;
	uint16_t ethtype;
	size_t offset = 0;
	uint8_t ip_proto = 0;

	pkt_hdr->input_flags.eth = 1;
	pkt_hdr->frame_offset = frame_offset;
	pkt_hdr->frame_len = len;

	if (odp_unlikely(len < ODP_ETH_LEN_MIN)) {
		pkt_hdr->error_flags.frame_len = 1;
		return;
	} else if (len > ODP_ETH_LEN_MAX) {
		pkt_hdr->input_flags.jumbo = 1;
	}

	/* Assume valid L2 header, no CRC/FCS check in SW */
	pkt_hdr->input_flags.l2 = 1;
	pkt_hdr->l2_offset = frame_offset;

	eth = (odp_ethhdr_t *)odp_packet_start(pkt);
	ethtype = odp_be_to_cpu_16(eth->type);
	vlan = (odp_vlanhdr_t *)&eth->type;

	if (ethtype == ODP_ETHTYPE_VLAN_OUTER) {
		pkt_hdr->input_flags.vlan_qinq = 1;
		ethtype = odp_be_to_cpu_16(vlan->tpid);
		offset += sizeof(odp_vlanhdr_t);
		vlan = &vlan[1];
	}

	if (ethtype == ODP_ETHTYPE_VLAN) {
		pkt_hdr->input_flags.vlan = 1;
		ethtype = odp_be_to_cpu_16(vlan->tpid);
		offset += sizeof(odp_vlanhdr_t);
	}

	/* Set l3_offset+flag only for known ethtypes */
	switch (ethtype) {
	case ODP_ETHTYPE_IPV4:
		pkt_hdr->input_flags.ipv4 = 1;
		pkt_hdr->input_flags.l3 = 1;
		pkt_hdr->l3_offset = frame_offset + ODP_ETHHDR_LEN + offset;
		ipv4 = (odp_ipv4hdr_t *)odp_packet_l3(pkt);
		ip_proto = parse_ipv4(pkt_hdr, ipv4, &offset);
		break;
	case ODP_ETHTYPE_IPV6:
		pkt_hdr->input_flags.ipv6 = 1;
		pkt_hdr->input_flags.l3 = 1;
		pkt_hdr->l3_offset = frame_offset + ODP_ETHHDR_LEN + offset;
		ipv6 = (odp_ipv6hdr_t *)odp_packet_l3(pkt);
		ip_proto = parse_ipv6(pkt_hdr, ipv6, &offset);
		break;
	case ODP_ETHTYPE_ARP:
		pkt_hdr->input_flags.arp = 1;
		/* fall through */
	default:
		ip_proto = 0;
		break;
	}

	switch (ip_proto) {
	case ODP_IPPROTO_UDP:
		pkt_hdr->input_flags.udp = 1;
		pkt_hdr->input_flags.l4 = 1;
		pkt_hdr->l4_offset = pkt_hdr->l3_offset + offset;
		break;
	case ODP_IPPROTO_TCP:
		pkt_hdr->input_flags.tcp = 1;
		pkt_hdr->input_flags.l4 = 1;
		pkt_hdr->l4_offset = pkt_hdr->l3_offset + offset;
		break;
	case ODP_IPPROTO_SCTP:
		pkt_hdr->input_flags.sctp = 1;
		pkt_hdr->input_flags.l4 = 1;
		pkt_hdr->l4_offset = pkt_hdr->l3_offset + offset;
		break;
	case ODP_IPPROTO_ICMP:
		pkt_hdr->input_flags.icmp = 1;
		pkt_hdr->input_flags.l4 = 1;
		pkt_hdr->l4_offset = pkt_hdr->l3_offset + offset;
		break;
	default:
		/* 0 or unhandled IP protocols, don't set L4 flag+offset */
		if (pkt_hdr->input_flags.ipv6) {
			/* IPv6 next_hdr is not L4, mark as IP-option instead */
			pkt_hdr->input_flags.ipopt = 1;
		}
		break;
	}
}
Beispiel #14
0
static int parse_layer2_packet(struct packet *packet, int in_bytes,
				       char **error)
{
	u8 *p = packet->buffer;
	/* Note that packet_end points to the byte beyond the end of packet. */
	u8 *packet_end = packet->buffer + in_bytes;
	struct ether_header *ether = NULL;

	/* Find Ethernet header */
	if (p + sizeof(*ether) > packet_end) {
		asprintf(error, "Ethernet header overflows packet");
		goto error_out;
	}
	ether = (struct ether_header *)p;
	p += sizeof(*ether);

	if (ntohs(ether->ether_type) == ETHERTYPE_IP) {
		struct ipv4 *ip = NULL;

		/* Examine IPv4 header. */
		if (p + sizeof(struct ipv4) > packet_end) {
			asprintf(error, "IPv4 header overflows packet");
			goto error_out;
		}

		/* Look at the IP version number, which is in the first 4 bits
		 * of both IPv4 and IPv6 packets.
		 */
		ip = (struct ipv4 *)p;
		if (ip->version == 4) {
			return parse_ipv4(packet, p, packet_end, error);
		} else {
			asprintf(error, "Bad IP version for ETHERTYPE_IP");
			goto error_out;
		}
	} else if (ntohs(ether->ether_type) == ETHERTYPE_IPV6) {
		struct ipv6 *ip = NULL;

		/* Examine IPv6 header. */
		if (p + sizeof(struct ipv6) > packet_end) {
			asprintf(error, "IPv6 header overflows packet");
			goto error_out;
		}

		/* Look at the IP version number, which is in the first 4 bits
		 * of both IPv4 and IPv6 packets.
		 */
		ip = (struct ipv6 *)p;
		if (ip->version == 6) {
			return parse_ipv6(packet, p, packet_end, error);
		} else {
			asprintf(error, "Bad IP version for ETHERTYPE_IPV6");
			goto error_out;
		}
	} else {
		return PACKET_UNKNOWN_L4;
	}

error_out:
	return PACKET_BAD;
}
static bool update_service_property(DBusMessageIter *arg, void *user_data)
{
	struct connman_service *service = user_data;
	const char *name, *value;
	gboolean boolean_value;
	char **array;
	int length;

	if (cui_dbus_get_basic(arg, DBUS_TYPE_STRING, &name) != 0)
		return FALSE;

	dbus_message_iter_next(arg);

	if (g_strcmp0(name, "Name") == 0) {
		cui_dbus_get_basic_variant(arg, DBUS_TYPE_STRING, &value);
		service->name = g_strdup(value);
	} else if (g_strcmp0(name, "Type") == 0) {
		cui_dbus_get_basic_variant(arg, DBUS_TYPE_STRING, &value);
		service->type = g_strdup(value);
	} else if (g_strcmp0(name, "Security") == 0) {
		cui_dbus_get_array(arg, DBUS_TYPE_STRING, &length, &array);

		g_free(service->security);
		if (array != NULL) {
			service->security = g_strjoinv(";", array);
			g_free(array);
		} else
			service->security = NULL;
	} else if (g_strcmp0(name, "Immutable") == 0) {
		cui_dbus_get_basic_variant(arg,
				DBUS_TYPE_BOOLEAN, &boolean_value);
		service->immutable = boolean_value;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_STATE)) == 0) {
		cui_dbus_get_basic_variant(arg, DBUS_TYPE_STRING, &value);

		service->state = string2enum_state(value);

		service->update_index = SERVICE_STATE;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_ERROR)) == 0) {
		cui_dbus_get_basic_variant(arg, DBUS_TYPE_STRING, &value);

		g_free(service->error);
		service->error = g_strdup(value);

		service->update_index = SERVICE_ERROR;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_STRENGTH)) == 0) {
		uint8_t uint8_value;

		cui_dbus_get_basic_variant(arg, DBUS_TYPE_BYTE, &uint8_value);
		service->strength = uint8_value;

		service->update_index = SERVICE_STRENGTH;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_FAVORITE)) == 0) {
		cui_dbus_get_basic_variant(arg,
				DBUS_TYPE_BOOLEAN, &boolean_value);
		service->favorite = boolean_value;

		service->update_index = SERVICE_FAVORITE;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_AUTOCONNECT)) == 0) {
		cui_dbus_get_basic_variant(arg,
				DBUS_TYPE_BOOLEAN, &boolean_value);
		service->autoconnect = boolean_value;

		service->update_index = SERVICE_AUTOCONNECT;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_ROAMING)) == 0) {
		cui_dbus_get_basic_variant(arg,
				DBUS_TYPE_BOOLEAN, &boolean_value);
		service->roaming = boolean_value;

		service->update_index = SERVICE_ROAMING;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_NAMESERVERS)) == 0) {
		cui_dbus_get_array(arg, DBUS_TYPE_STRING, &length, &array);

		g_free(service->nameservers);
		if (array != NULL) {
			service->nameservers = g_strjoinv(";", array);
			g_free(array);
		} else
			service->nameservers = NULL;

		service->update_index = SERVICE_NAMESERVERS;
	} else if (g_strcmp0(name,
			PROPERTY(SERVICE_NAMESERVERS_CONFIGURATION)) == 0) {
		cui_dbus_get_array(arg, DBUS_TYPE_STRING, &length, &array);

		g_free(service->nameservers_conf);
		if (array != NULL) {
			service->nameservers_conf = g_strjoinv(";", array);
			g_free(array);
		} else
			 service->nameservers_conf = NULL;

		service->update_index = SERVICE_NAMESERVERS_CONFIGURATION;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_DOMAINS)) == 0) {
		cui_dbus_get_array(arg, DBUS_TYPE_STRING, &length, &array);

		g_free(service->domains);
		if (array != NULL) {
			service->domains = g_strjoinv(";", array);
			g_free(array);
		} else
			service->domains = NULL;

		service->update_index = SERVICE_DOMAINS;
	} else if (g_strcmp0(name,
			PROPERTY(SERVICE_DOMAINS_CONFIGURATION)) == 0) {
		cui_dbus_get_array(arg, DBUS_TYPE_STRING, &length, &array);

		g_free(service->domains_conf);
		if (array != NULL) {
			service->domains_conf = g_strjoinv(";", array);
			g_free(array);
		} else
			service->domains_conf = NULL;

		service->update_index = SERVICE_DOMAINS_CONFIGURATION;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_TIMESERVERS)) == 0) {
		cui_dbus_get_array(arg, DBUS_TYPE_STRING, &length, &array);

		g_free(service->timeservers);
		if (array != NULL) {
			service->timeservers = g_strjoinv(";", array);
			g_free(array);
		} else
			service->timeservers = NULL;

		service->update_index = SERVICE_TIMESERVERS;
	} else if (g_strcmp0(name,
			PROPERTY(SERVICE_TIMESERVERS_CONFIGURATION)) == 0) {
		cui_dbus_get_array(arg, DBUS_TYPE_STRING, &length, &array);

		g_free(service->timeservers_conf);
		if (array != NULL) {
			service->timeservers_conf = g_strjoinv(";", array);
			g_free(array);
		} else
			service->timeservers_conf = NULL;

		service->update_index = SERVICE_TIMESERVERS_CONFIGURATION;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_IPv4)) == 0) {
		service->ipv4 = parse_ipv4(arg, service->ipv4);
		service->update_index = SERVICE_IPv4;
	} else if (g_strcmp0(name,
			PROPERTY(SERVICE_IPv4_CONFIGURATION)) == 0) {
		service->ipv4_conf = parse_ipv4(arg, service->ipv4_conf);
		service->update_index = SERVICE_IPv4_CONFIGURATION;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_IPv6)) == 0) {
		service->ipv6 = parse_ipv6(arg, service->ipv6);
		service->update_index = SERVICE_IPv6;
	} else if (g_strcmp0(name,
			PROPERTY(SERVICE_IPv6_CONFIGURATION)) == 0) {
		service->ipv6_conf = parse_ipv6(arg, service->ipv6_conf);
		service->update_index = SERVICE_IPv6_CONFIGURATION;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_PROXY)) == 0) {
		service->proxy = parse_proxy(arg, service->proxy);
		service->update_index = SERVICE_PROXY;
	} else if (g_strcmp0(name,
			PROPERTY(SERVICE_PROXY_CONFIGURATION)) == 0) {
		service->proxy_conf = parse_proxy(arg, service->proxy_conf);
		service->update_index = SERVICE_PROXY_CONFIGURATION;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_PROVIDER)) == 0) {
		service->provider = parse_provider(arg, service->provider);
		service->update_index = SERVICE_PROVIDER;
	} else if (g_strcmp0(name, PROPERTY(SERVICE_ETHERNET)) == 0) {
		service->ethernet = parse_ethernet(arg, service->ethernet);
		service->update_index = SERVICE_ETHERNET;
	}

	return FALSE;
}