Esempio n. 1
0
/* Send the contents of the global buffer via the non-multicast socket
 */
int					/* <0 on failure */
output(enum output_type type,
       struct sockaddr_in *dst,		/* send to here */
       struct interface *ifp,
       struct rip *buf,
       int size)			/* this many bytes */
{
	struct sockaddr_in in;
	int flags;
	const char *msg;
	int res;
	naddr tgt_mcast;
	int soc;
	int serrno;

	in = *dst;
	if (in.sin_port == 0)
		in.sin_port = htons(RIP_PORT);
#ifdef _HAVE_SIN_LEN
	if (in.sin_len == 0)
		in.sin_len = sizeof(in);
#endif

	soc = rip_sock;
	flags = 0;

	switch (type) {
	case OUT_QUERY:
		msg = "Answer Query";
		if (soc < 0)
			soc = ifp->int_rip_sock;
		break;
	case OUT_UNICAST:
		msg = "Send";
		if (soc < 0)
			soc = ifp->int_rip_sock;
		flags = MSG_DONTROUTE;
		break;
	case OUT_BROADCAST:
		if (ifp->int_if_flags & IFF_POINTOPOINT) {
			msg = "Send";
		} else {
			msg = "Send bcast";
		}
		flags = MSG_DONTROUTE;
		break;
	case OUT_MULTICAST:
		if (ifp->int_if_flags & IFF_POINTOPOINT) {
			msg = "Send pt-to-pt";
		} else if (ifp->int_state & IS_DUP) {
			trace_act("abort multicast output via %s"
				  " with duplicate address",
				  ifp->int_name);
			return 0;
		} else {
			msg = "Send mcast";
			if (rip_sock_mcast != ifp) {
#ifdef MCAST_PPP_BUG
				/* Do not specify the primary interface
				 * explicitly if we have the multicast
				 * point-to-point kernel bug, since the
				 * kernel will do the wrong thing if the
				 * local address of a point-to-point link
				 * is the same as the address of an ordinary
				 * interface.
				 */
				if (ifp->int_addr == myaddr) {
					tgt_mcast = 0;
				} else
#endif
				tgt_mcast = ifp->int_addr;
				if (0 > setsockopt(rip_sock,
						   IPPROTO_IP, IP_MULTICAST_IF,
						   &tgt_mcast,
						   sizeof(tgt_mcast))) {
					serrno = errno;
					LOGERR("setsockopt(rip_sock,"
					       "IP_MULTICAST_IF)");
					errno = serrno;
					ifp = NULL;
					return -1;
				}
				rip_sock_mcast = ifp;
			}
			in.sin_addr.s_addr = htonl(INADDR_RIP_GROUP);
		}
		break;

	case NO_OUT_MULTICAST:
	case NO_OUT_RIPV2:
	default:
#ifdef DEBUG
		abort();
#endif
		return -1;
	}

	trace_rip(msg, "to", &in, ifp, buf, size);

	res = sendto(soc, buf, size, flags,
		     (struct sockaddr *)&in, sizeof(in));
	if (res < 0
	    && (ifp == NULL || !(ifp->int_state & IS_BROKE))) {
		serrno = errno;
		msglog("%s sendto(%s%s%s.%d): %s", msg,
		       ifp != NULL ? ifp->int_name : "",
		       ifp != NULL ? ", " : "",
		       inet_ntoa(in.sin_addr),
		       ntohs(in.sin_port),
		       strerror(errno));
		errno = serrno;
	}

	return res;
}
Esempio n. 2
0
/* Send the contents of the global buffer via the non-multicast socket
 */
int					/* <0 on failure */
output(enum output_type type,
       struct sockaddr_in *dst,		/* send to here */
       struct interface *ifp,
       struct rip *buf,
       int size)			/* this many bytes */
{
	struct sockaddr_in osin;
	int flags;
	const char *msg;
	int res;
	int soc;
	int serrno;

	assert(ifp != NULL);
	osin = *dst;
	if (osin.sin_port == 0)
		osin.sin_port = htons(RIP_PORT);
#ifdef _HAVE_SIN_LEN
	if (osin.sin_len == 0)
		osin.sin_len = sizeof(osin);
#endif

	soc = rip_sock;
	flags = 0;

	switch (type) {
	case OUT_QUERY:
		msg = "Answer Query";
		if (soc < 0)
			soc = ifp->int_rip_sock;
		break;
	case OUT_UNICAST:
		msg = "Send";
		if (soc < 0)
			soc = ifp->int_rip_sock;
		flags = MSG_DONTROUTE;
		break;
	case OUT_BROADCAST:
		if (ifp->int_if_flags & IFF_POINTOPOINT) {
			msg = "Send";
		} else {
			msg = "Send bcast";
		}
		flags = MSG_DONTROUTE;
		break;
	case OUT_MULTICAST:
		if ((ifp->int_if_flags & (IFF_POINTOPOINT|IFF_MULTICAST)) ==
		    IFF_POINTOPOINT) {
			msg = "Send pt-to-pt";
		} else if (ifp->int_state & IS_DUP) {
			trace_act("abort multicast output via %s"
				  " with duplicate address",
				  ifp->int_name);
			return 0;
		} else {
			msg = "Send mcast";
			if (rip_sock_mcast != ifp) {
				struct ip_mreqn mreqn;

				memset(&mreqn, 0, sizeof(struct ip_mreqn));
				mreqn.imr_ifindex = ifp->int_index;
				if (0 > setsockopt(rip_sock,
						   IPPROTO_IP,
						   IP_MULTICAST_IF,
						   &mreqn,
						   sizeof(mreqn))) {
					serrno = errno;
					LOGERR("setsockopt(rip_sock, "
					       "IP_MULTICAST_IF)");
					errno = serrno;
					ifp = 0;
					return -1;
				}
				rip_sock_mcast = ifp;
			}
			osin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP);
		}
		break;

	case NO_OUT_MULTICAST:
	case NO_OUT_RIPV2:
	default:
#ifdef DEBUG
		abort();
#endif
		return -1;
	}

	trace_rip(msg, "to", &osin, ifp, buf, size);

	res = sendto(soc, buf, size, flags,
		     (struct sockaddr *)&osin, sizeof(osin));
	if (res < 0
	    && (ifp == 0 || !(ifp->int_state & IS_BROKE))) {
		serrno = errno;
		msglog("%s sendto(%s%s%s.%d): %s", msg,
		       ifp != 0 ? ifp->int_name : "",
		       ifp != 0 ? ", " : "",
		       inet_ntoa(osin.sin_addr),
		       ntohs(osin.sin_port),
		       strerror(errno));
		errno = serrno;
	}

	return res;
}