Exemple #1
0
int
ctl_msg_recv(int fd, enum hmsg_type *type, void **t)
{
	int n, flags = -1;
	struct hmsg_header hdr;
	*type = NONE; *t = NULL;
	/* First, we read the header to know the size of the message */
	if ((n = read(fd, &hdr, sizeof(struct hmsg_header))) == -1) {
		LLOG_WARN("unable to read message header");
		return -1;
	}
	if (n == 0)
		/* Remote closed the connection. */
		return -1;
	if (n < sizeof(struct hmsg_header)) {
		LLOG_WARNX("message received too short (%d)", n);
		goto recv_error;
	}
	if (hdr.len > (1<<15)) {
		LLOG_WARNX("message received is too large");
		goto recv_error;
	}
	if (hdr.len == 0) {
		/* No answer */
		*type = hdr.type;
		return 0;
	}
	/* Now, we read the remaining message. We need to use non-blocking stuff
	 * just in case the message was truncated. */
	if ((*t = malloc(hdr.len)) == NULL) {
		LLOG_WARNX("not enough space available for incoming message");
		goto recv_error;
	}
	if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
	    fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
		LLOG_WARN("unable to set socket access mode to non blocking");
		goto recv_error;
	}
	if ((n = read(fd, *t, hdr.len)) == -1) {
		if (errno == EAGAIN || errno == EWOULDBLOCK) {
			LLOG_WARNX("message seems truncated");
			goto recv_error;
		}
		LLOG_WARN("unable to read incoming request");
		goto recv_error;
	}
	if (n != hdr.len) {
		LLOG_WARNX("received message is too short (%d < %zu)",
			   n, hdr.len);
		goto recv_error;
	}
	fcntl(fd, F_SETFL, flags); /* No error check */
	*type = hdr.type;
	return hdr.len;
recv_error:
	free(*t); *t = NULL;
	if (flags != -1) fcntl(fd, F_SETFL, flags);
	return -1;
}
Exemple #2
0
int
ctl_msg_send_recv(int fd,
    enum hmsg_type type,
    void *input, struct marshal_info *input_mi,
    void **output, struct marshal_info *output_mi)
{
	int n, input_len = 0;
	void *input_buffer = NULL;
	void *serialized = NULL;
	enum hmsg_type received_type;

	/* Serialize */
	if (input) {
		input_len = marshal_serialize_(input_mi, input, &input_buffer, 0, NULL, 0);
		if (input_len <= 0) {
			LLOG_WARNX("unable to serialize input data");
			return -1;
		}
	}
	/* Send request */
	if (ctl_msg_send(fd, type, input_buffer, input_len) == -1) {
		LLOG_WARN("unable to send request");
		goto send_recv_error;
	}
	free(input_buffer); input_buffer = NULL;
	/* Receive answer */
	if ((n = ctl_msg_recv(fd, &received_type, &serialized)) == -1)
		goto send_recv_error;
	/* Check type */
	if (received_type != type) {
		LLOG_WARNX("incorrect received message type (expected: %d, received: %d)",
		    type, received_type);
		goto send_recv_error;
	}
	/* Unserialize */
	if (output == NULL) {
		free(serialized);
		return 0;
	}
	if (n == 0) {
		LLOG_WARNX("no payload available in answer");
		goto send_recv_error;
	}
	if (marshal_unserialize_(output_mi, serialized, n, output, NULL, 0, 0) <= 0) {
		LLOG_WARNX("unable to deserialize received data");
		goto send_recv_error;
	}
	/* All done. */
	return 0;
send_recv_error:
	free(serialized);
	free(input_buffer);
	return -1;
}
Exemple #3
0
int
ctl_connect(char *name)
{
	int s;
	struct sockaddr_un su;
	int rc;

	if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
		return -1;
	su.sun_family = AF_UNIX;
	strlcpy(su.sun_path, name, UNIX_PATH_MAX);
	if (connect(s, (struct sockaddr *)&su, sizeof(struct sockaddr_un)) == -1) {
		rc = errno;
		LLOG_WARN("unable to connect to socket " LLDPD_CTL_SOCKET);
		errno = rc; return -1;
	}
	return s;
}
Exemple #4
0
static int
cdp_send(struct lldpd *global,
	 struct lldpd_hardware *hardware, int version)
{
	struct lldpd_chassis *chassis;
	u_int8_t mcastaddr[] = CDP_MULTICAST_ADDR;
	u_int8_t llcorg[] = LLC_ORG_CISCO;
#ifdef ENABLE_FDP
	char *capstr;
#endif
	u_int16_t checksum;
	int length;
	u_int32_t cap;
	u_int8_t *packet;
	u_int8_t *pos, *pos_len_eh, *pos_llc, *pos_cdp, *pos_checksum, *tlv, *end;

	chassis = hardware->h_lport.p_chassis;

#ifdef ENABLE_FDP
	if (version == 0) {
		/* With FDP, change multicast address and LLC PID */
		const u_int8_t fdpmcastaddr[] = FDP_MULTICAST_ADDR;
		const u_int8_t fdpllcorg[] = LLC_ORG_FOUNDRY;
		memcpy(mcastaddr, fdpmcastaddr, sizeof(mcastaddr));
		memcpy(llcorg, fdpllcorg, sizeof(llcorg));
	}
#endif

	length = hardware->h_mtu;
	if ((packet = (u_int8_t*)malloc(length)) == NULL)
		return ENOMEM;
	memset(packet, 0, length);
	pos = packet;

	/* Ethernet header */
	if (!(
	      POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
	      POKE_BYTES(&hardware->h_lladdr, sizeof(hardware->h_lladdr)) &&
	      POKE_SAVE(pos_len_eh) && /* We compute the len later */
	      POKE_UINT16(0)))
		goto toobig;

	/* LLC */
	if (!(
	      POKE_SAVE(pos_llc) &&
	      POKE_UINT8(0xaa) && /* SSAP */
	      POKE_UINT8(0xaa) && /* DSAP */
	      POKE_UINT8(0x03) && /* Control field */
	      POKE_BYTES(llcorg, sizeof(llcorg)) &&
	      POKE_UINT16(LLC_PID_CDP)))
		goto toobig;

	/* CDP header */
	if (!(
	      POKE_SAVE(pos_cdp) &&
	      POKE_UINT8((version == 0)?1:version) &&
	      POKE_UINT8(chassis->c_ttl) &&
	      POKE_SAVE(pos_checksum) && /* Save checksum position */
	      POKE_UINT16(0)))
		goto toobig;

	/* Chassis ID */
	if (!(
	      POKE_START_CDP_TLV(CDP_TLV_CHASSIS) &&
	      POKE_BYTES(chassis->c_name, strlen(chassis->c_name)) &&
	      POKE_END_CDP_TLV))
		goto toobig;

	/* Adresses */
	if (!(
	      POKE_START_CDP_TLV(CDP_TLV_ADDRESSES) &&
	      POKE_UINT32(1) &&	/* We ship only one address */
	      POKE_UINT8(1) &&	/* Type: NLPID */
	      POKE_UINT8(1) &&  /* Length: 1 */
	      POKE_UINT8(CDP_ADDRESS_PROTO_IP) && /* IP */
	      POKE_UINT16(sizeof(struct in_addr)) && /* Address length */
	      POKE_BYTES(&chassis->c_mgmt, sizeof(struct in_addr)) &&
	      POKE_END_CDP_TLV))
		goto toobig;

	/* Port ID */
	if (!(
	      POKE_START_CDP_TLV(CDP_TLV_PORT) &&
	      POKE_BYTES(hardware->h_lport.p_descr,
			 strlen(hardware->h_lport.p_descr)) &&
	      POKE_END_CDP_TLV))
		goto toobig;

	/* Capabilities */
	if (version != 0) {
		cap = 0;
		if (chassis->c_cap_enabled & LLDP_CAP_ROUTER)
			cap |= CDP_CAP_ROUTER;
		if (chassis->c_cap_enabled & LLDP_CAP_BRIDGE)
			cap |= CDP_CAP_SWITCH;
		cap |= CDP_CAP_HOST;
		if (!(
		      POKE_START_CDP_TLV(CDP_TLV_CAPABILITIES) &&
		      POKE_UINT32(cap) &&
		      POKE_END_CDP_TLV))
			goto toobig;
#ifdef ENABLE_FDP
	} else {
		/* With FDP, it seems that a string is used in place of an int */
		if (chassis->c_cap_enabled & LLDP_CAP_ROUTER)
			capstr = "Router";
		else if (chassis->c_cap_enabled & LLDP_CAP_BRIDGE)
			capstr = "Switch";
		else if (chassis->c_cap_enabled & LLDP_CAP_REPEATER)
			capstr = "Bridge";
		else
			capstr = "Host";
		if (!(
		      POKE_START_CDP_TLV(CDP_TLV_CAPABILITIES) &&
		      POKE_BYTES(capstr, strlen(capstr)) &&
		      POKE_END_CDP_TLV))
			goto toobig;
#endif
	}
		
	/* Software version */
	if (!(
	      POKE_START_CDP_TLV(CDP_TLV_SOFTWARE) &&
	      POKE_BYTES(chassis->c_descr, strlen(chassis->c_descr)) &&
	      POKE_END_CDP_TLV))
		goto toobig;

	/* Platform */
	if (!(
	      POKE_START_CDP_TLV(CDP_TLV_PLATFORM) &&
	      POKE_BYTES("Linux", strlen("Linux")) &&
	      POKE_END_CDP_TLV))
		goto toobig;
	POKE_SAVE(end);

	/* Compute len and checksum */
	POKE_RESTORE(pos_len_eh);
	if (!(POKE_UINT16(end - pos_llc))) goto toobig;
	checksum = frame_checksum(pos_cdp, end - pos_cdp, (version != 0) ? 1 : 0);
	POKE_RESTORE(pos_checksum);
	if (!(POKE_UINT16(ntohs(checksum)))) goto toobig;

	if (hardware->h_ops->send(global, hardware,
		(char *)packet, end - packet) == -1) {
		LLOG_WARN("unable to send packet on real device for %s",
			   hardware->h_ifname);
		free(packet);
		return ENETDOWN;
	}

	hardware->h_tx_cnt++;

	free(packet);
	return 0;
 toobig:
	free(packet);
	return -1;
}
Exemple #5
0
/* cdp_decode also decodes FDP */
int
cdp_decode(struct lldpd *cfg, char *frame, int s,
    struct lldpd_hardware *hardware,
    struct lldpd_chassis **newchassis, struct lldpd_port **newport)
{
	struct lldpd_chassis *chassis;
	struct lldpd_port *port;
#if 0
	u_int16_t cksum;
#endif
	u_int8_t *software = NULL, *platform = NULL;
	int software_len = 0, platform_len = 0, proto, version, nb, caps;
	const unsigned char cdpaddr[] = CDP_MULTICAST_ADDR;
#ifdef ENABLE_FDP
	const unsigned char fdpaddr[] = CDP_MULTICAST_ADDR;
	int fdp = 0;
#endif
	u_int8_t *pos, *tlv, *pos_address, *pos_next_address;
	int length, len_eth, tlv_type, tlv_len, addresses_len, address_len;

	if ((chassis = calloc(1, sizeof(struct lldpd_chassis))) == NULL) {
		LLOG_WARN("failed to allocate remote chassis");
		return -1;
	}
	if ((port = calloc(1, sizeof(struct lldpd_port))) == NULL) {
		LLOG_WARN("failed to allocate remote port");
		free(chassis);
		return -1;
	}
#ifdef ENABLE_DOT1
	TAILQ_INIT(&port->p_vlans);
#endif

	length = s;
	pos = (u_int8_t*)frame;

	if (length < 2*ETH_ALEN + sizeof(u_int16_t) /* Ethernet */ +
	    8 /* LLC */ + 4 /* CDP header */) {
		LLOG_WARNX("too short CDP/FDP frame received on %s", hardware->h_ifname);
		goto malformed;
	}

	if (PEEK_CMP(cdpaddr, sizeof(cdpaddr)) != 0) {
#ifdef ENABLE_FDP
		PEEK_RESTORE((u_int8_t*)frame);
		if (PEEK_CMP(fdpaddr, sizeof(fdpaddr)) != 0)
			fdp = 1;
		else {
#endif
			LLOG_INFO("frame not targeted at CDP/FDP multicast address received on %s",
			    hardware->h_ifname);
			goto malformed;
#ifdef ENABLE_FDP
		}
#endif
	}
	PEEK_DISCARD(ETH_ALEN);	/* Don't care of source address */
	len_eth = PEEK_UINT16;
	if (len_eth > length) {
		LLOG_WARNX("incorrect 802.3 frame size reported on %s",
		    hardware->h_ifname);
		goto malformed;
	}
	PEEK_DISCARD(6);	/* Skip beginning of LLC */
	proto = PEEK_UINT16;
	if (proto != LLC_PID_CDP) {
		if ((proto != LLC_PID_DRIP) &&
		    (proto != LLC_PID_PAGP) &&
		    (proto != LLC_PID_PVSTP) &&
		    (proto != LLC_PID_UDLD) &&
		    (proto != LLC_PID_VTP) &&
		    (proto != LLC_PID_DTP) &&
		    (proto != LLC_PID_STP))
			LLOG_DEBUG("incorrect LLC protocol ID received on %s",
			    hardware->h_ifname);
		goto malformed;
	}

#if 0
	/* Check checksum */
	cksum = frame_checksum(pos, len_eth - 8,
#ifdef ENABLE_FDP
	    !fdp		/* fdp = 0 -> cisco checksum */
#else
	    1			/* cisco checksum */
#endif
		);
	/* An off-by-one error may happen. Just ignore it */
	if ((cksum != 0) && (cksum != 0xfffe)) {
		LLOG_INFO("incorrect CDP/FDP checksum for frame received on %s (%d)",
			  hardware->h_ifname, cksum);
		goto malformed;
	}
#endif

	/* Check version */
	version = PEEK_UINT8;
	if ((version != 1) && (version != 2)) {
		LLOG_WARNX("incorrect CDP/FDP version (%d) for frame received on %s",
		    version, hardware->h_ifname);
		goto malformed;
	}
	chassis->c_ttl = PEEK_UINT8; /* TTL */
	PEEK_DISCARD_UINT16;	     /* Checksum, already checked */

	while (length) {
		if (length < 4) {
			LLOG_WARNX("CDP/FDP TLV header is too large for "
			    "frame received on %s",
			    hardware->h_ifname);
			goto malformed;
		}
		tlv_type = PEEK_UINT16;
		tlv_len = PEEK_UINT16 - 4;
		PEEK_SAVE(tlv);
		if ((tlv_len < 0) || (length < tlv_len)) {
			LLOG_WARNX("incorrect size in CDP/FDP TLV header for frame "
			    "received on %s",
			    hardware->h_ifname);
			goto malformed;
		}
		switch (tlv_type) {
		case CDP_TLV_CHASSIS:
			if ((chassis->c_name = (char *)calloc(1, tlv_len + 1)) == NULL) {
				LLOG_WARN("unable to allocate memory for chassis name");
				goto malformed;
			}
			PEEK_BYTES(chassis->c_name, tlv_len);
			chassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LOCAL;
			if ((chassis->c_id =  (char *)malloc(tlv_len)) == NULL) {
				LLOG_WARN("unable to allocate memory for chassis ID");
				goto malformed;
			}
			memcpy(chassis->c_id, chassis->c_name, tlv_len);
			chassis->c_id_len = tlv_len;
			break;
		case CDP_TLV_ADDRESSES:
			CHECK_TLV_SIZE(4, "Address");
			addresses_len = tlv_len - 4;
			for (nb = PEEK_UINT32; nb > 0; nb--) {
				PEEK_SAVE(pos_address);
				/* We first try to get the real length of the packet */
				if (addresses_len < 2) {
					LLOG_WARN("too short address subframe "
						  "received on %s",
						  hardware->h_ifname);
					goto malformed;
				}
				PEEK_DISCARD_UINT8; addresses_len--;
				address_len = PEEK_UINT8; addresses_len--;
				if (addresses_len < address_len + 2) {
					LLOG_WARN("too short address subframe "
						  "received on %s",
						  hardware->h_ifname);
					goto malformed;
				}
				PEEK_DISCARD(address_len);
				addresses_len -= address_len;
				address_len = PEEK_UINT16; addresses_len -= 2;
				if (addresses_len < address_len) {
					LLOG_WARN("too short address subframe "
						  "received on %s",
						  hardware->h_ifname);
					goto malformed;
				}
				PEEK_DISCARD(address_len);
				PEEK_SAVE(pos_next_address);
				/* Next, we go back and try to extract
				   IPv4 address */
				PEEK_RESTORE(pos_address);
				if ((PEEK_UINT8 == 1) && (PEEK_UINT8 == 1) &&
				    (PEEK_UINT8 == CDP_ADDRESS_PROTO_IP) &&
				    (PEEK_UINT16 == sizeof(struct in_addr)) &&
				    (chassis->c_mgmt.s_addr == INADDR_ANY))
					PEEK_BYTES(&chassis->c_mgmt,
						   sizeof(struct in_addr));
				/* Go to the end of the address */
				PEEK_RESTORE(pos_next_address);
			}
			break;
		case CDP_TLV_PORT:
			if ((port->p_descr = (char *)calloc(1, tlv_len + 1)) == NULL) {
				LLOG_WARN("unable to allocate memory for port description");
				goto malformed;
			}
			PEEK_BYTES(port->p_descr, tlv_len);
			port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
			if ((port->p_id =  (char *)calloc(1, tlv_len)) == NULL) {
				LLOG_WARN("unable to allocate memory for port ID");
				goto malformed;
			}
			memcpy(port->p_id, port->p_descr, tlv_len);
			port->p_id_len = tlv_len;
			break;
		case CDP_TLV_CAPABILITIES:
#ifdef ENABLE_FDP
			if (fdp) {
				/* Capabilities are string with FDP */
				if (!strncmp("Router", (char*)pos, tlv_len))
					chassis->c_cap_enabled = LLDP_CAP_ROUTER;
				else if (!strncmp("Switch", (char*)pos, tlv_len))
					chassis->c_cap_enabled = LLDP_CAP_BRIDGE;
				else if (!strncmp("Bridge", (char*)pos, tlv_len))
					chassis->c_cap_enabled = LLDP_CAP_REPEATER;
				else
					chassis->c_cap_enabled = LLDP_CAP_STATION;
				chassis->c_cap_available = chassis->c_cap_enabled;
				break;
			}
#endif
			CHECK_TLV_SIZE(4, "Capabilities");
			caps = PEEK_UINT32;
			if (caps & CDP_CAP_ROUTER)
				chassis->c_cap_enabled |= LLDP_CAP_ROUTER;
			if (caps & 0x0e)
				chassis->c_cap_enabled |= LLDP_CAP_BRIDGE;
			if (chassis->c_cap_enabled == 0)
				chassis->c_cap_enabled = LLDP_CAP_STATION;
			chassis->c_cap_available = chassis->c_cap_enabled;
			break;
		case CDP_TLV_SOFTWARE:
			software_len = tlv_len;
			PEEK_SAVE(software);
			break;
		case CDP_TLV_PLATFORM:
			platform_len = tlv_len;
			PEEK_SAVE(platform);
			break;
		default:
			LLOG_DEBUG("unknown CDP/FDP TLV type (%d) received on %s",
			    ntohs(tlv_type), hardware->h_ifname);
			hardware->h_rx_unrecognized_cnt++;
		}
		PEEK_DISCARD(tlv + tlv_len - pos);
	}
	if (!software && platform) {
		if ((chassis->c_descr = (char *)calloc(1,
			    platform_len + 1)) == NULL) {
			LLOG_WARN("unable to allocate memory for chassis description");
			goto malformed;
		}
		memcpy(chassis->c_descr, platform, platform_len);
	} else if (software && !platform) {
		if ((chassis->c_descr = (char *)calloc(1,
			    software_len + 1)) == NULL) {
			LLOG_WARN("unable to allocate memory for chassis description");
			goto malformed;
		}
		memcpy(chassis->c_descr, software, software_len);
	} else if (software && platform) {
#define CONCAT_PLATFORM " running on\n"
		if ((chassis->c_descr = (char *)calloc(1,
			    software_len + platform_len +
			    strlen(CONCAT_PLATFORM) + 1)) == NULL) {
			LLOG_WARN("unable to allocate memory for chassis description");
			goto malformed;
		}
		memcpy(chassis->c_descr, platform, platform_len);
		memcpy(chassis->c_descr + platform_len,
		    CONCAT_PLATFORM, strlen(CONCAT_PLATFORM));
		memcpy(chassis->c_descr + platform_len + strlen(CONCAT_PLATFORM),
		    software, software_len);
	}
	if ((chassis->c_id == NULL) ||
	    (port->p_id == NULL) ||
	    (chassis->c_name == NULL) ||
	    (chassis->c_descr == NULL) ||
	    (port->p_descr == NULL) ||
	    (chassis->c_ttl == 0) ||
	    (chassis->c_cap_enabled == 0)) {
		LLOG_WARNX("some mandatory CDP/FDP tlv are missing for frame received on %s",
		    hardware->h_ifname);
		goto malformed;
	}
	*newchassis = chassis;
	*newport = port;
	return 1;

malformed:
	lldpd_chassis_cleanup(chassis, 1);
	lldpd_port_cleanup(cfg, port, 1);
	free(port);
	return -1;
}
Exemple #6
0
void
ctl_cleanup(char *name)
{
	if (unlink(name) == -1)
		LLOG_WARN("unable to unlink %s", name);
}