Esempio n. 1
0
int
recv_address(struct nbr *nbr, char *buf, u_int16_t len)
{
	struct ldp_msg		addr;
	struct address_list_tlv	alt;
	enum imsg_type		type;

	if (nbr->state != NBR_STA_OPER) {
		log_debug("recv_address: neighbor ID %s not operational",
		    inet_ntoa(nbr->id));
		return (-1);
	}

	bcopy(buf, &addr, sizeof(addr));
	log_debug("recv_address: neighbor ID %s%s", inet_ntoa(nbr->id),
	    ntohs(addr.type) == MSG_TYPE_ADDR ? "" : " address withdraw");
	if (ntohs(addr.type) == MSG_TYPE_ADDR)
		type = IMSG_ADDRESS_ADD;
	else
		type = IMSG_ADDRESS_DEL;

	buf += sizeof(struct ldp_msg);
	len -= sizeof(struct ldp_msg);

	if (len < sizeof(alt)) {
		session_shutdown(nbr, S_BAD_MSG_LEN, addr.msgid, addr.type);
		return (-1);
	}

	bcopy(buf, &alt, sizeof(alt));

	if (ntohs(alt.length) != len - TLV_HDR_LEN) {
		session_shutdown(nbr, S_BAD_TLV_LEN, addr.msgid, addr.type);
		return (-1);
	}

	if (ntohs(alt.type) != TLV_TYPE_ADDRLIST) {
		session_shutdown(nbr, S_UNKNOWN_TLV, addr.msgid, addr.type);
		return (-1);
	}

	/* For now we only support IPv4 */
	if (alt.family != htons(ADDR_IPV4)) {
		send_notification_nbr(nbr, S_UNSUP_ADDR, addr.msgid, addr.type);
		return (-1);
	}

	buf += sizeof(alt);
	len -= sizeof(alt);

	while (len >= sizeof(struct in_addr)) {
		ldpe_imsg_compose_lde(type, nbr->peerid, 0,
		    buf, sizeof(struct in_addr));

		buf += sizeof(struct in_addr);
		len -= sizeof(struct in_addr);
	}

	if (len != 0) {
		session_shutdown(nbr, S_BAD_TLV_LEN, addr.msgid, addr.type);
		return (-1);
	}

	return (ntohs(addr.length));
}
Esempio n. 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);
}