示例#1
0
void
recv_hello(struct iface *iface, struct in_addr src, char *buf, u_int16_t len)
{
	struct ldp_msg		 hello;
	struct ldp_hdr		 ldp;
	struct nbr		*nbr = NULL;
	struct in_addr		 address;
	u_int32_t		 conf_number;
	u_int16_t		 holdtime, flags;
	int			 r;

	bcopy(buf, &ldp, sizeof(ldp));
	buf += LDP_HDR_SIZE;
	len -= LDP_HDR_SIZE;

	bcopy(buf, &hello, sizeof(hello));
	buf += sizeof(struct ldp_msg);
	len -= sizeof(struct ldp_msg);

	r = tlv_decode_hello_prms(buf, len, &holdtime, &flags);
	if (r == -1) {
		address.s_addr = ldp.lsr_id;
		log_debug("recv_hello: neighbor %s: failed to decode params",
		    inet_ntoa(address));
		return;
	}

	buf += r;
	len -= r;

	r = tlv_decode_opt_hello_prms(buf, len, &address, &conf_number);
	if (r == -1) {
		address.s_addr = ldp.lsr_id;
		log_debug("recv_hello: neighbor %s: failed to decode "
		    "optional params", inet_ntoa(address));
		return;
	}
	if (r != len) {
		address.s_addr = ldp.lsr_id;
		log_debug("recv_hello: neighbor %s: unexpected data in message",
		    inet_ntoa(address));
		return;
	}

	nbr = nbr_find_ldpid(ldp.lsr_id, ldp.lspace_id);
	if (!nbr) {
		struct in_addr	a;

		if (address.s_addr == INADDR_ANY)
			a = src;
		else
			a = address;

		nbr = nbr_new(ldp.lsr_id, ldp.lspace_id, iface, a);

		/* set neighbor parameters */
		nbr->hello_type = flags;

		if (holdtime == 0) {
			/* XXX: lacks support for targeted hellos */
			if (iface->holdtime < LINK_DFLT_HOLDTIME)
				nbr->holdtime = iface->holdtime;
			else
				nbr->holdtime = LINK_DFLT_HOLDTIME;
		} else if (holdtime == INFINITE_HOLDTIME) {
			/* No timeout for this neighbor */
			nbr->holdtime = iface->holdtime;
		} else {
			if (iface->holdtime < holdtime)
				nbr->holdtime = iface->holdtime;
			else
				nbr->holdtime = holdtime;
		}
	}

	nbr_fsm(nbr, NBR_EVT_HELLO_RCVD);

	if (ntohl(nbr->addr.s_addr) < ntohl(nbr->iface->addr.s_addr) &&
	    nbr->state == NBR_STA_PRESENT && !nbr_pending_idtimer(nbr))
		nbr_act_session_establish(nbr, 1);
}
示例#2
0
int
recv_notification(struct nbr *nbr, char *buf, uint16_t len)
{
	struct ldp_msg		msg;
	struct status_tlv	st;
	struct notify_msg	nm;
	int			tlen;

	memcpy(&msg, buf, sizeof(msg));
	buf += LDP_MSG_SIZE;
	len -= LDP_MSG_SIZE;

	if (len < STATUS_SIZE) {
		session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
		return (-1);
	}
	memcpy(&st, buf, sizeof(st));

	if (ntohs(st.length) > STATUS_SIZE - TLV_HDR_SIZE ||
	    ntohs(st.length) > len - TLV_HDR_SIZE) {
		session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
		return (-1);
	}
	buf += STATUS_SIZE;
	len -= STATUS_SIZE;

	memset(&nm, 0, sizeof(nm));
	nm.status_code = ntohl(st.status_code);

	/* Optional Parameters */
	while (len > 0) {
		struct tlv 	tlv;
		uint16_t	tlv_len;

		if (len < sizeof(tlv)) {
			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
			return (-1);
		}

		memcpy(&tlv, buf, TLV_HDR_SIZE);
		tlv_len = ntohs(tlv.length);
		if (tlv_len + TLV_HDR_SIZE > len) {
			session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
			return (-1);
		}
		buf += TLV_HDR_SIZE;
		len -= TLV_HDR_SIZE;

		switch (ntohs(tlv.type)) {
		case TLV_TYPE_EXTSTATUS:
		case TLV_TYPE_RETURNEDPDU:
		case TLV_TYPE_RETURNEDMSG:
			/* TODO is there any use for this? */
			break;
		case TLV_TYPE_PW_STATUS:
			if (tlv_len != 4) {
				session_shutdown(nbr, S_BAD_TLV_LEN,
				    msg.id, msg.type);
				return (-1);
			}

			nm.pw_status = ntohl(*(uint32_t *)buf);
			nm.flags |= F_NOTIF_PW_STATUS;
			break;
		case TLV_TYPE_FEC:
			if ((tlen = tlv_decode_fec_elm(nbr, &msg, buf,
			    tlv_len, &nm.fec)) == -1)
				return (-1);
			/* allow only one fec element */
			if (tlen != tlv_len) {
				session_shutdown(nbr, S_BAD_TLV_VAL,
				    msg.id, msg.type);
				return (-1);
			}
			nm.flags |= F_NOTIF_FEC;
			break;
		default:
			if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
				send_notification_nbr(nbr, S_UNKNOWN_TLV,
				    msg.id, msg.type);
			/* ignore unknown tlv */
			break;
		}
		buf += tlv_len;
		len -= tlv_len;
	}

	if (nm.status_code == S_PW_STATUS) {
		if (!(nm.flags & (F_NOTIF_PW_STATUS|F_NOTIF_FEC))) {
			send_notification_nbr(nbr, S_MISS_MSG,
			    msg.id, msg.type);
			return (-1);
		}

		switch (nm.fec.type) {
		case MAP_TYPE_PWID:
			break;
		default:
			send_notification_nbr(nbr, S_BAD_TLV_VAL,
			    msg.id, msg.type);
			return (-1);
		}
	}

	if (st.status_code & htonl(STATUS_FATAL))
		log_warnx("received notification from lsr-id %s: %s",
		    inet_ntoa(nbr->id),
		    status_code_name(ntohl(st.status_code)));
	else
		log_debug("received non-fatal notification from lsr-id "
		    "%s: %s", inet_ntoa(nbr->id),
		    status_code_name(ntohl(st.status_code)));

	if (st.status_code & htonl(STATUS_FATAL)) {
		if (nbr->state == NBR_STA_OPENSENT)
			nbr_start_idtimer(nbr);

		nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
		return (-1);
	}

	if (nm.status_code == S_PW_STATUS)
		ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0,
		    &nm, sizeof(nm));

	return (0);
}