Ejemplo n.º 1
0
void rip_incoming(ssize_t n)
/* Use a RIP packet to add to the router table.  (RIP packets are really for
 * between routers, but often it is the only information around.)
 */
{
	udp_io_hdr_t *udp_io_hdr;
	u32_t default_dist;
	i32_t pref;
	routeinfo_t *routeinfo;
	struct routedata *data, *end;

	/* We don't care about RIP packets when there are router adverts. */
	if (now + MaxAdvertisementInterval < router_advert_valid) return;

	udp_io_hdr= (udp_io_hdr_t *) rip_buf;
	if (udp_io_hdr->uih_data_len != n - sizeof(*udp_io_hdr)) {
		if (debug) printf("Bad sized route packet (discarded)\n");
		return;
	}
	routeinfo= (routeinfo_t *) (rip_buf + sizeof(*udp_io_hdr)
			+ udp_io_hdr->uih_ip_opt_len);

	if (routeinfo->command != RIP_REPLY) {
		if (debug) {
			printf("RIP-%d packet command %d ignored\n",
				routeinfo->version, routeinfo->command);
		}
		return;
	}

	/* Look for a default route, the route to the gateway. */
	end= (struct routedata *) (rip_buf + n);
	default_dist= (u32_t) -1;
	for (data= routeinfo->data; data < end; data++) {
		if (ntohs(data->family) != AF_INET || data->ip_addr != 0)
			continue;
		default_dist= ntohl(data->metric);
		if (default_dist >= 256) {
			if (debug) {
				printf("Strange metric %lu\n",
					(unsigned long) default_dist);
			}
		}
	}
	pref= default_dist >= 256 ? 1 : 512 - default_dist;
	pref+= priority_offset;

	/* Add the gateway to the table with the calculated preference. */
	add_gateway(udp_io_hdr->uih_src_addr, pref);

	if (debug) {
		printf("Routing table after RIP-%d packet from %s:\n",
			routeinfo->version,
			addr2name(udp_io_hdr->uih_src_addr));
		print_table();
	}

	/* Start advertizing. */
	if (next_advert == NEVER) next_advert= IMMEDIATELY;
}
Ejemplo n.º 2
0
void irdp_incoming(ssize_t n)
/* Look for router solicitations and router advertisements.  The solicitations
 * are probably from other irdpd daemons, we answer them if we do not expect
 * a real router to answer.  The advertisements cause this daemon to shut up.
 */
{
	ip_hdr_t *ip_hdr;
	icmp_hdr_t *icmp_hdr;
	int ip_hdr_len;
	char *data;
	int i;
	int router;
	ipaddr_t addr;
	i32_t pref;
	time_t valid;

	ip_hdr= (ip_hdr_t *) irdp_buf;
	ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
	if (n < ip_hdr_len + 8) {
		if (debug) printf("Bad sized ICMP (discarded)\n");
		return;
	}

	icmp_hdr= (icmp_hdr_t *)(irdp_buf + ip_hdr_len);

	/* Did I send this myself? */
	if (ip_hdr->ih_src == ip_hdr->ih_dst) return;
	if ((htonl(ip_hdr->ih_src) & 0xFF000000L) == 0x7F000000L) return;

	if (icmp_hdr->ih_type != ICMP_TYPE_ROUTER_ADVER) return;

	/* Incoming router advertisement, the kind of packet the TCP/IP task
	 * is very happy with.  No need to solicit further.
	 */
	sol_retries= 0;

	/* Add router info to our table.  Also see if the packet really came
	 * from a router.  If so then we can go dormant for the lifetime of
	 * the ICMP.
	 */
	router= 0;
	data= (char *) icmp_hdr->ih_dun.uhd_data;
	for (i= 0; i < icmp_hdr->ih_hun.ihh_ram.iram_na; i++) {
		addr= * (ipaddr_t *) data;
		data+= sizeof(ipaddr_t);
		pref= htonl(* (i32_t *) data);
		data+= sizeof(i32_t);

		if (addr == ip_hdr->ih_src) {
			/* The sender is in the routing table! */
			router= 1;
		}
		add_gateway(addr, pref);
	}

	valid= now + ntohs(icmp_hdr->ih_hun.ihh_ram.iram_lt);
	if (router) router_advert_valid= valid;

	/* Restart advertizing close to the timeout of the advert.  (No more
	 * irdpd adverts if the router stays alive.)
	 */
	if (router || next_advert > valid - DANGER)
		next_advert= valid - DANGER;

	if (debug) {
		printf("Routing table after advert received from %s:\n",
			addr2name(ip_hdr->ih_src));
		print_table();
		if (router) {
			struct tm *tm= localtime(&router_advert_valid);
			printf(
			"This router advert is valid until %02d:%02d:%02d\n",
				tm->tm_hour, tm->tm_min, tm->tm_sec);
		}
	}
}
Ejemplo n.º 3
0
static void 
read_ascii (FILE *fd, io_t *IO)
{
    LINKED_LIST *ll_ann, *ll_with;
    bgp_attr_t *attr;
    int announce_flag = 0;
    int line_num = 0;
    int have_data = 0;
    int have_data2 = 0;
    time_t tstamp = 0;
    int type = 0;
    int subtype = 0;
    int bgptype = 0;
    int newtype = 0;
    gateway_t *gateway_from = NULL;
    gateway_t *gateway_to = NULL;
    int first = 1;
    u_char bgp_packet[BGPMAXPACKETSIZE], *bp = bgp_packet;
    u_char buffer[MAX_MSG_SIZE], *buffer_p = buffer;
    u_char *end = buffer + sizeof (buffer);
    int eof = 0;
    buffer_t *stdbuf;

    int state1 = 0, state2 = 0;

    int version = 0, as = 0, holdtime = 0, optlen = 0;
    u_long id = 0;

    int code = 0, subcode = 0;

    int viewno = 0;
    char *filename = NULL;

    prefix_t *route_prefix = NULL;
    time_t originated = 0;
    u_long status = 0;
    int seq_num = 0;

    attr = bgp_new_attr (PROTO_BGP);
    ll_ann = LL_Create (LL_DestroyFunction, Deref_Prefix, 0);
    ll_with = LL_Create (LL_DestroyFunction, Deref_Prefix, 0);

    stdbuf = New_Buffer_Stream (fd);
    for (;;) {
        char *line = NULL, *ret = NULL;
	int len = 0;
        int ok = 0;
	char *cp;

        if (buffer_gets (stdbuf) <= 0) {
	    eof++;
	}
	else {
	    len = buffer_data_len (stdbuf);
	    line = buffer_data (stdbuf);

	    if (line[len - 1] == '\n') {
	        line[len - 1] = '\0';
	        len--;
	    }
	    trace (TR_TRACE, MRT->trace, "++%s\n", line);
            line_num++;

	    if ((cp = strpbrk (line, "#!")) != NULL) {
	        *cp = '\0';
	        len = cp - line;
	    }

	    if (first && nulline (line))
	        continue;
	    first = 0;
	}
    
	if (eof || nulline (line)) {
	    if (have_data && have_data2) {
		trace (TR_ERROR, MRT->trace, "Mixture of two formats\n");
		goto error;
	    }
	    if (bgptype == BGP_UPDATE && have_data) {
		flushout (IO, tstamp, type, subtype, attr, ll_ann, ll_with, 
			  gateway_to);
	    }
	    else if (have_data2) {
		flushout2 (IO, tstamp, type, subtype, 
			   bgp_packet, bp - bgp_packet, 
			   gateway_from, gateway_to);
	    }
    	    else if (bgptype == BGP_KEEPALIVE) {
		if (type == MSG_PROTOCOL_BGP4MP) {
		    memset (bgp_packet, 0xff, BGP_HEADER_MARKER_LEN);
	  	    BGP_PUT_HDRTYPE (bgptype, bgp_packet);
		    bp = bgp_packet + BGP_HEADER_LEN;
	  	    BGP_PUT_HDRLEN (bp - bgp_packet, bgp_packet);
		}
		else {
		    bp = bgp_packet;
		}
		flushout2 (IO, tstamp, type, subtype, 
		   	   bgp_packet, bp - bgp_packet, 
			   gateway_from, gateway_to);
    	    }
    	    else if (bgptype == BGP_OPEN) {
		if (type == MSG_PROTOCOL_BGP4MP) {
		    memset (bgp_packet, 0xff, BGP_HEADER_MARKER_LEN);
	  	    BGP_PUT_HDRTYPE (bgptype, bgp_packet);
		    bp = bgp_packet + BGP_HEADER_LEN;
		}
		else {
		    bp = bgp_packet;
		}
		BGP_PUT_BYTE (version, bp);
		BGP_PUT_SHORT (as, bp);
		BGP_PUT_SHORT (holdtime, bp);
		BGP_PUT_NETLONG (id, bp);
		BGP_PUT_BYTE (0, bp); /* XXX */
		if (type == MSG_PROTOCOL_BGP4MP) {
	  	    BGP_PUT_HDRLEN (bp - bgp_packet, bgp_packet);
		}
		flushout2 (IO, tstamp, type, subtype, 
		 	   bgp_packet, bp - bgp_packet, 
			   gateway_from, gateway_to);
    	    }
    	    else if (bgptype == BGP_NOTIFY) {
		if (type == MSG_PROTOCOL_BGP4MP) {
		    memset (bgp_packet, 0xff, BGP_HEADER_MARKER_LEN);
	  	    BGP_PUT_HDRTYPE (bgptype, bgp_packet);
		    bp = bgp_packet + BGP_HEADER_LEN;
		}
		else {
		    bp = bgp_packet;
		}
		BGP_PUT_BYTE (code, bp);
		BGP_PUT_BYTE (subcode, bp);
		if (type == MSG_PROTOCOL_BGP4MP) {
	  	    BGP_PUT_HDRLEN (bp - bgp_packet, bgp_packet);
		}
		flushout2 (IO, tstamp, type, subtype, 
		 	   bgp_packet, bp - bgp_packet, 
			   gateway_from, gateway_to);
    	    }
	    else if (newtype == BGP4MP_STATE_CHANGE) {
		bp = bgp_packet;
		BGP_PUT_SHORT (state1, bp);
		BGP_PUT_SHORT (state2, bp);
		flushout2 (IO, tstamp, type, subtype, 
		 	   bgp_packet, bp - bgp_packet, 
			   gateway_from, NULL);
	    }
	    else if (newtype == BGP4MP_SNAPSHOT) {
		bp = bgp_packet;
		BGP_PUT_SHORT (viewno, bp);
		if (filename)
		    BGP_PUT_DATA (filename, strlen (filename), bp);
		BGP_PUT_BYTE (0, bp);
    		trace_mrt_header (MRT->trace, tstamp, type, subtype);
    		io_write (IO, tstamp, type, subtype, 
			  bp - bgp_packet, bgp_packet);
	    }
	    else if (newtype == BGP4MP_ENTRY) {
		if (route_prefix != NULL) {
		    buffer_p = bgp_table_dump_entry (buffer_p, end, type, 
						     subtype, viewno, 
				   route_prefix, status, originated, attr);
		}
		if (buffer_p - buffer > 0) {
    		    trace_mrt_header (MRT->trace, tstamp, type, subtype);
    		    io_write (IO, tstamp, type, subtype, 
			      buffer_p - buffer, buffer);
		}
	    }

	    if (eof)
		break;
	if (MRT->force_exit_flag)
	    exit (1);
	    bgp_deref_attr (attr);
	    attr = bgp_new_attr (PROTO_BGP);
	    LL_Clear (ll_ann);
	    LL_Clear (ll_with);

    	    announce_flag = 0;
    	    have_data = 0;
    	    have_data2 = 0;
    	    tstamp = 0;
    	    type = 0;
    	    subtype = 0;
    	    bgptype = 0;
    	    newtype = 0;
    	    gateway_to = NULL;
    	    gateway_from = NULL;
    	    route_prefix = NULL;
	    seq_num = 0;
    	    first = 1;
    	    if (filename)
		free (filename);
	    filename = NULL;
	    continue;
	}

    if (have_data) {
	/* a prefix -- line begins with a space */
	if (isspace (line[0])) {
	    prefix_t *prefix;
	    char *cp = line +1;

	    while (isspace (*cp))
		cp++;
	    if ((prefix = ascii2prefix (0, cp)) != NULL) {
		if (announce_flag == 1) {
		    LL_Add (ll_ann, prefix);
		}
		else {
		    LL_Add (ll_with, prefix);
		}
	        continue;
	    }
	}
    }

	if (have_data2) {
	    prefix_t *prefix;
	    int num;
	    u_long value;

	    if (isspace (line[0]) &&
		    strpbrk (line, ".:") && strchr (line, '/') &&
		    parse_line (line, "%d %m", &num, &prefix) == 2) {
		u_char *here = bp;
		/* v4 or v6 address with prefixlen */
#ifdef HAVE_IPV6
		if (prefix->family == AF_INET6)
		    BGP_PUT_PREFIX6 (prefix->bitlen, prefix_tochar (prefix), 
				     bp);
		else
#endif /* HAVE_IPV6 */
		    BGP_PUT_PREFIX (prefix->bitlen, prefix_tochar (prefix), 
				    bp);
		Deref_Prefix (prefix);
		if (num != bp - here) {
		    trace (TR_ERROR, MRT->trace, 
			   "length was %d but must be %d\n", num, bp - here);
		    goto error;
		}
		continue;
	    }
	    else if (isspace (line[0]) &&
	    	         strpbrk (line, ".:") && 
		    	 parse_line (line, "%d %M", &num, &prefix) == 2) {
		/* v4 or v6 address w/o prefixlen */
		if (prefix->family == AF_INET6 && num > 16) {
		    trace (TR_ERROR, MRT->trace, 
			   "length was %d but must be less than or equal %d\n",
			    num, 16);
		    Deref_Prefix (prefix);
		    goto error;
		}
		if (prefix->family == AF_INET && num > 4) {
		    trace (TR_ERROR, MRT->trace, 
			   "length was %d but must be less than or equal %d\n",
			    num, 4);
		    Deref_Prefix (prefix);
		    goto error;
		}
		BGP_PUT_DATA (prefix_tochar (prefix), num, bp);
		Deref_Prefix (prefix);
		continue;
	    }
	    else if (isspace (line[0]) &&
	    		parse_line (line, "%d %i", &num, &value) == 2) {
		if (num == 1)
		    BGP_PUT_BYTE (value, bp);
		else if (num == 2)
		    BGP_PUT_SHORT (value, bp);
		else if (num == 4)
		    BGP_PUT_LONG (value, bp);
		else {
		    trace (TR_ERROR, MRT->trace, 
			   "unknown length %d\n", num);
		    goto error;
		}
		continue;
	    }
	}

	if ((ret = checkstradvance (line, "TIME"))) {
	    struct tm tm;
	    if (strptime (ret, "%D %T", &tm)) {
		time_t now;
		time (&now);
		tm.tm_isdst = localtime (&now)->tm_isdst;
		adjust_y2k (&tm);
		tstamp = mktime (&tm);
	    }
	}

	else if ((ret = checkstradvance (line, "TO"))) {
	    int as;
    	    char data[MAXLINE];
	    prefix_t *prefix;
	    if (sscanf (ret, "%s AS%d", data, &as) >= 2 ||
	        sscanf (ret, "AS%d %s", &as, data) >= 2 /* obsolete */) {
		prefix = ascii2prefix (0, data);
		gateway_to = add_gateway (prefix, as, NULL);
		Deref_Prefix (prefix);
	    }
	}

	else if ((ret = checkstradvance (line, "FROM"))) {
	    int as;
    	    char data[MAXLINE];
	    if (sscanf (ret, "%s AS%d", data, &as) >= 2 ||
	        sscanf (ret, "AS%d %s", &as, data) >= 2 /* obsolete */) {
		prefix_t *prefix = ascii2prefix (0, data);
		gateway_from = add_gateway (prefix, as, NULL);
		attr->gateway = gateway_from;
		Deref_Prefix (prefix);
	    }
	}

	/* type BGP/UPDATE */
	else if ((ret = checkstradvance (line, "TYPE"))) {
	    char *subtypestr;
	    char **cpp;
	    int i;

	    if ((subtypestr = strchr (ret, '/')) != NULL)
		*subtypestr++ = '\0';

	    cpp = S_MRT_MSG_TYPES;
	    for (i = 0; cpp[i]; i++) {
	        if (strcasecmp (cpp[i], ret) == 0)
			break;
	    }
	    type = (enum MRT_MSG_TYPES) i;

	    if (subtypestr) {
		char *subsubtypestr;

	        if ((subsubtypestr = strchr (subtypestr, '/')) != NULL)
		    *subsubtypestr++ = '\0';
		if ((cpp = S_MRT_MSG_SUBTYPES[type]) != NULL) {
		    for (i = 0; cpp[i]; i++) {
		        if (strcasecmp (cpp[i], subtypestr) == 0)
			    break;
		    }
		    subtype = i;
		}
		newtype = subtype;

		if (type == MSG_PROTOCOL_BGP ||
			type == MSG_PROTOCOL_BGP4PLUS ||
			type == MSG_PROTOCOL_BGP4PLUS_01) {
		    if (subtype == MSG_BGP_UPDATE) {
		        bgptype = BGP_UPDATE;
			newtype = BGP4MP_MESSAGE;
		    }
		    else if (subtype == MSG_BGP_KEEPALIVE) {
		        bgptype = BGP_KEEPALIVE;
			newtype = BGP4MP_MESSAGE;
		    }
		    else if (subtype == MSG_BGP_NOTIFY) {
		        bgptype = BGP_NOTIFY;
			newtype = BGP4MP_MESSAGE;
		    }
		    else if (subtype == MSG_BGP_OPEN) {
		        bgptype = BGP_OPEN;
			newtype = BGP4MP_MESSAGE;
		    }
		    else if (subtype == MSG_BGP_SYNC) {
			newtype = BGP4MP_SNAPSHOT;
		    }
		    else if (subtype == MSG_BGP_STATE_CHANGE) {
			newtype = BGP4MP_STATE_CHANGE;
		    }
		    else if (subtype == MSG_TABLE_DUMP) {
			newtype = BGP4MP_ENTRY;
		    }
		}
		else if (type == MSG_PROTOCOL_BGP4MP && (
			subtype == BGP4MP_MESSAGE || 
			subtype == BGP4MP_MESSAGE_OLD)) {
		    for (i = 0; sbgp_pdus[i]; i++) {
		        if (strcasecmp (sbgp_pdus[i], subsubtypestr) == 0) {
		    	    bgptype = i;
			    break;
			}
		    }
		}
	    }

	    if (type == MSG_PROTOCOL_BGP
		    || type == MSG_PROTOCOL_BGP4PLUS
		    || type == MSG_PROTOCOL_BGP4PLUS_01
		    || type == MSG_TABLE_DUMP
		    || type == MSG_PROTOCOL_BGP4MP
		    ) {
		/* OK */
	    }
	    else {
		trace (TR_ERROR, MRT->trace, 
		       "Unknown message type %s at line %d\n", ret, line_num);
		goto error;
	    }
	}

	else if ((ret = checkstradvance (line, "DATA"))) {
	    bp = bgp_packet;
	    have_data2++;
	}
	else if (newtype == BGP4MP_STATE_CHANGE &&
	         (ret = checkstradvance (line, "PEER"))) {
	    int as;
    	    char data[MAXLINE];
	    if (sscanf (ret, "%s AS%d", data, &as) >= 2 ||
	        sscanf (ret, "AS%d %s", &as, data) >= 2 /* obsolete */) {
		prefix_t *prefix = ascii2prefix (0, data);
		gateway_from = add_gateway (prefix, as, NULL);
		Deref_Prefix (prefix);
	    }
	}
	else if (newtype == BGP4MP_STATE_CHANGE &&
	         (ret = checkstradvance (line, "STATE"))) {
	    char *cp = strchr (ret, '/');
	    int i;

	    if (cp == NULL)
		goto error;
	    *cp++ = '\0';
	    for (i = 0; sbgp_states[i]; i++) {
		if (strcasecmp (sbgp_states[i], ret) == 0) {
		    state1 = i;
		}
	    }
	    for (i = 0; sbgp_states[i]; i++) {
		if (strcasecmp (sbgp_states[i], cp) == 0) {
		    state2 = i;
		}
	    }
	}
	else if ((newtype == BGP4MP_SNAPSHOT || newtype == BGP4MP_ENTRY) &&
	         (ret = checkstradvance (line, "VIEW"))) {
	    viewno = atoi (ret);
	}
	else if (newtype == BGP4MP_SNAPSHOT &&
	         (ret = checkstradvance (line, "FILE"))) {
	    if (filename)
		free (filename);
	    filename = strdup (ret);
	}
	else if (newtype == BGP4MP_ENTRY &&
	         (ret = checkstradvance (line, "PREFIX"))) {
	    if (route_prefix == NULL) {
	    	buffer_p = buffer;
		if (type == MSG_TABLE_DUMP) {
	    	    BGP_PUT_SHORT (viewno, buffer_p);
            	    BGP_PUT_SHORT (seq_num, buffer_p);
		}
	    }
	    else {
		buffer_p = bgp_table_dump_entry (buffer_p, end, type, subtype,
                      viewno, route_prefix, status, originated, attr);
	    }
	    route_prefix = ascii2prefix (0, ret);
	    bgp_deref_attr (attr);
	    attr = bgp_new_attr (PROTO_BGP);
	}
	else if (newtype == BGP4MP_ENTRY &&
	         (ret = checkstradvance (line, "SEQUENCE"))) {
	    seq_num = atoi (ret);
	}
	else if (newtype == BGP4MP_ENTRY &&
	        (ret = checkstradvance (line, "ORIGINATED"))) {
	    struct tm tm;
	    if (strptime (ret, "%D %T", &tm)) {
		time_t now;
		time (&now);
		tm.tm_isdst = localtime (&now)->tm_isdst;
		adjust_y2k (&tm);
		originated = mktime (&tm);
	    }
	}
	else if (newtype == BGP4MP_ENTRY &&
	         (ret = checkstradvance (line, "STATUS"))) {
	    sscanf (ret, "%li", &status);
	}
	else if (bgptype == BGP_OPEN &&
		(ret = checkstradvance (line, "VERSION"))) {
	    version = atoi (ret);
	}
	else if (bgptype == BGP_OPEN &&
		(ret = checkstradvance (line, "AS"))) {
	    as = atoi (ret);
	}
	else if (bgptype == BGP_OPEN &&
		(ret = checkstradvance (line, "HOLD_TIME"))) {
	    holdtime = atoi (ret);
	}
	else if (bgptype == BGP_OPEN &&
		(ret = checkstradvance (line, "ID"))) {
	    inet_pton (AF_INET, ret, &id);
	}
	else if (bgptype == BGP_OPEN &&
		(ret = checkstradvance (line, "OPT_PARM_LEN"))) {
	    optlen = atoi (ret);
	}
	else if (bgptype == BGP_NOTIFY &&
		(ret = checkstradvance (line, "CODE"))) {
	    char *cp;
	    code = atoi (ret);
	    if ((cp = strchr (ret, '/')) != NULL)
		subcode = atoi (cp + 1);
	}
	else if (bgptype == BGP_UPDATE &&
		(ret = checkstradvance (line, "ANNOUNCE"))) {
	    announce_flag = 1;
	    have_data++;
	}
	else if (bgptype == BGP_UPDATE &&
		(ret = checkstradvance (line, "WITHDRAW"))) {
	    announce_flag = 0;
	    have_data++;
	}
	else if ((bgptype == BGP_UPDATE || newtype == BGP4MP_ENTRY) &&
		(ok = bgp_scan_attr (line, attr, MRT->trace)) > 0) {
	    /* OK */
	}
	else if ((bgptype == BGP_UPDATE || newtype == BGP4MP_ENTRY) && ok < 0) {
	    trace (TR_ERROR, MRT->trace, 
	           "Invalid BGP attribute at line %d\n", line_num);
	    goto error;
	}
	else {
	    trace (TR_ERROR, MRT->trace, "Unrecognized line at %d\n", line_num);
	    goto error;
	}
    }

error:
    if (filename)
	free (filename);
    bgp_deref_attr (attr);
    LL_Destroy (ll_ann);
    LL_Destroy (ll_with);
    Delete_Buffer (stdbuf);
}
Ejemplo n.º 4
0
int __connman_connection_gateway_add(struct connman_service *service,
					const char *gateway,
					enum connman_ipconfig_type type,
					const char *peer)
{
	struct gateway_data *active_gateway = NULL;
	struct gateway_data *new_gateway = NULL;
	enum connman_ipconfig_type type4 = CONNMAN_IPCONFIG_TYPE_UNKNOWN,
		type6 = CONNMAN_IPCONFIG_TYPE_UNKNOWN;
	enum connman_service_type service_type =
					connman_service_get_type(service);
	int index;

	index = __connman_service_get_index(service);

	/*
	 * If gateway is NULL, it's a point to point link and the default
	 * gateway for ipv4 is 0.0.0.0 and for ipv6 is ::, meaning the
	 * interface
	 */
	if (!gateway && type == CONNMAN_IPCONFIG_TYPE_IPV4)
		gateway = "0.0.0.0";

	if (!gateway && type == CONNMAN_IPCONFIG_TYPE_IPV6)
		gateway = "::";

	DBG("service %p index %d gateway %s vpn ip %s type %d",
		service, index, gateway, peer, type);

	new_gateway = add_gateway(service, index, gateway, type);
	if (!new_gateway)
		return -EINVAL;

	active_gateway = find_active_gateway();

	DBG("active %p index %d new %p", active_gateway,
		active_gateway ? active_gateway->index : -1, new_gateway);

	if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
				new_gateway->ipv4_gateway) {
		add_host_route(AF_INET, index, gateway, service_type);
		__connman_service_nameserver_add_routes(service,
					new_gateway->ipv4_gateway->gateway);
		type4 = CONNMAN_IPCONFIG_TYPE_IPV4;
	}

	if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
				new_gateway->ipv6_gateway) {
		add_host_route(AF_INET6, index, gateway, service_type);
		__connman_service_nameserver_add_routes(service,
					new_gateway->ipv6_gateway->gateway);
		type6 = CONNMAN_IPCONFIG_TYPE_IPV6;
	}

	if (service_type == CONNMAN_SERVICE_TYPE_VPN) {

		set_vpn_routes(new_gateway, service, gateway, type, peer,
							active_gateway);

	} else {
		if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
					new_gateway->ipv4_gateway)
			new_gateway->ipv4_gateway->vpn = false;

		if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
					new_gateway->ipv6_gateway)
			new_gateway->ipv6_gateway->vpn = false;
	}

	if (!active_gateway) {
		set_default_gateway(new_gateway, type);
		goto done;
	}

	if (type == CONNMAN_IPCONFIG_TYPE_IPV4 &&
				new_gateway->ipv4_gateway &&
				new_gateway->ipv4_gateway->vpn) {
		if (!__connman_service_is_split_routing(new_gateway->service))
			connman_inet_clear_gateway_address(
					active_gateway->index,
					active_gateway->ipv4_gateway->gateway);
	}

	if (type == CONNMAN_IPCONFIG_TYPE_IPV6 &&
				new_gateway->ipv6_gateway &&
				new_gateway->ipv6_gateway->vpn) {
		if (!__connman_service_is_split_routing(new_gateway->service))
			connman_inet_clear_ipv6_gateway_address(
					active_gateway->index,
					active_gateway->ipv6_gateway->gateway);
	}

done:
	if (type4 == CONNMAN_IPCONFIG_TYPE_IPV4)
		__connman_service_ipconfig_indicate_state(service,
						CONNMAN_SERVICE_STATE_READY,
						CONNMAN_IPCONFIG_TYPE_IPV4);

	if (type6 == CONNMAN_IPCONFIG_TYPE_IPV6)
		__connman_service_ipconfig_indicate_state(service,
						CONNMAN_SERVICE_STATE_READY,
						CONNMAN_IPCONFIG_TYPE_IPV6);
	return 0;
}