Exemple #1
0
int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
	struct inet_sock *inet = inet_sk(sk);
	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
	struct rtable *rt;
	__be32 saddr;
	int oif;
	int err;


	if (addr_len < sizeof(*usin))
		return -EINVAL;

	if (usin->sin_family != AF_INET)
		return -EAFNOSUPPORT;

	sk_dst_reset(sk);

	oif = sk->sk_bound_dev_if;
	saddr = inet->inet_saddr;
	if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
		if (!oif)
			oif = inet->mc_index;
		if (!saddr)
			saddr = inet->mc_addr;
	}
	err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr,
			       RT_CONN_FLAGS(sk), oif,
			       sk->sk_protocol,
			       inet->inet_sport, usin->sin_port, sk, 1);
	if (err) {
		if (err == -ENETUNREACH)
			IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
		return err;
	}

	if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) {
		ip_rt_put(rt);
		return -EACCES;
	}
	if (!inet->inet_saddr)
		inet->inet_saddr = rt->rt_src;	/* Update source address */
	if (!inet->inet_rcv_saddr) {
		inet->inet_rcv_saddr = rt->rt_src;
		if (sk->sk_prot->rehash)
			sk->sk_prot->rehash(sk);
	}
	inet->inet_daddr = rt->rt_dst;
	inet->inet_dport = usin->sin_port;
	sk->sk_state = TCP_ESTABLISHED;
	inet->inet_id = jiffies;

	sk_dst_set(sk, &rt->dst);
	return(0);
}
Exemple #2
0
static struct dst_entry *rxe_find_route(struct net_device *ndev,
					struct rxe_qp *qp,
					struct rxe_av *av)
{
	struct dst_entry *dst = NULL;

	if (qp_type(qp) == IB_QPT_RC)
		dst = sk_dst_get(qp->sk->sk);

	if (!dst || !dst_check(dst, qp->dst_cookie)) {
		if (dst)
			dst_release(dst);

		if (av->network_type == RDMA_NETWORK_IPV4) {
			struct in_addr *saddr;
			struct in_addr *daddr;

			saddr = &av->sgid_addr._sockaddr_in.sin_addr;
			daddr = &av->dgid_addr._sockaddr_in.sin_addr;
			dst = rxe_find_route4(ndev, saddr, daddr);
		} else if (av->network_type == RDMA_NETWORK_IPV6) {
			struct in6_addr *saddr6;
			struct in6_addr *daddr6;

			saddr6 = &av->sgid_addr._sockaddr_in6.sin6_addr;
			daddr6 = &av->dgid_addr._sockaddr_in6.sin6_addr;
			dst = rxe_find_route6(ndev, saddr6, daddr6);
#if IS_ENABLED(CONFIG_IPV6)
			if (dst)
				qp->dst_cookie =
					rt6_get_cookie((struct rt6_info *)dst);
#endif
		}

		if (dst && (qp_type(qp) == IB_QPT_RC)) {
			dst_hold(dst);
			sk_dst_set(qp->sk->sk, dst);
		}
	}
	return dst;
}
Exemple #3
0
static int
mptp_sendmsg(struct kiocb *iocb, struct socket *sock,
	     struct msghdr *msg, size_t len)
{
	int err;
	uint16_t dport;
	__be32 daddr;
	__be32 saddr;
	uint16_t sport;
	struct sk_buff *skb;
	struct sock *sk;
	struct inet_sock *isk;
	struct mptp_sock *ssk;
	struct mptphdr *shdr;
	int connected = 0;
	int totlen;
	struct rtable *rt = NULL;
	int dests = 0;
	int i;
	struct sockaddr_mptp *mptp_addr = NULL;
	int ret = 0;

	if (unlikely(sock == NULL)) {
		log_error("Sock is NULL\n");
		err = -EINVAL;
		goto out;
	}
	sk = sock->sk;

	if (unlikely(sk == NULL)) {
		log_error("Sock->sk is NULL\n");
		err = -EINVAL;
		goto out;
	}

	isk = inet_sk(sk);
	ssk = mptp_sk(sk);

	sport = ssk->src;
	saddr = isk->inet_saddr;

	if (sport == 0) {
		sport = get_next_free_port();
		if (unlikely(sport == 0)) {
			log_error("No free ports\n");
			err = -ENOMEM;
			goto out;
		}
	}

	if (msg->msg_name) {
		mptp_addr = (struct sockaddr_mptp *)msg->msg_name;

		if (unlikely
		    (msg->msg_namelen <
		     sizeof(*mptp_addr) +
		     mptp_addr->count * sizeof(struct mptp_dest)
		     || mptp_addr->count <= 0)) {
			log_error
			    ("Invalid size for msg_name (size=%u, addr_count=%u)\n",
			     msg->msg_namelen, mptp_addr->count);
			err = -EINVAL;
			goto out;
		}

		dests = mptp_addr->count;
	} else {
		BUG();
		if (unlikely(!ssk->dst || !isk->inet_daddr)) {
			log_error("No destination port/address\n");
			err = -EDESTADDRREQ;
			goto out;
		}
		dport = ssk->dst;
		daddr = isk->inet_daddr;

		log_debug
		    ("Got from socket destination port=%u and address=%u\n",
		     dport, daddr);
		connected = 1;
	}

	if (msg->msg_iovlen < dests)
		dests = msg->msg_iovlen;

	for (i = 0; i < dests; i++) {
		struct mptp_dest *dest = &mptp_addr->dests[i];
		struct iovec *iov = &msg->msg_iov[i];
		char *payload;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
		struct flowi fl = {};
#endif

		dport = ntohs(dest->port);
		if (unlikely(dport == 0 || dport >= MAX_MPTP_PORT)) {
			log_error("Invalid value for destination port(%u)\n",
				  dport);
			err = -EINVAL;
			goto out;
		}

		daddr = dest->addr;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
		fl.u.ip4.saddr = saddr;
		fl.u.ip4.daddr = daddr;
		fl.flowi_proto = sk->sk_protocol;
		fl.flowi_flags = inet_sk_flowi_flags(sk);
#endif

		log_debug
		    ("Received from user space destination port=%u and address=%u\n",
		     dport, daddr);

		len = iov->iov_len;
		totlen = len + sizeof(struct mptphdr) + sizeof(struct iphdr);
		skb =
		    sock_alloc_send_skb(sk, totlen,
					msg->msg_flags & MSG_DONTWAIT, &err);
		if (unlikely(!skb)) {
			log_error("sock_alloc_send_skb failed\n");
			goto out;
		}
		log_debug("Allocated %u bytes for skb (payload size=%u)\n",
			  totlen, len);

		skb_reset_network_header(skb);
		skb_reserve(skb, sizeof(struct iphdr));
		log_debug("Reseted network header\n");
		skb_reset_transport_header(skb);
		skb_put(skb, sizeof(struct mptphdr));
		log_debug("Reseted transport header\n");

		shdr = (struct mptphdr *)skb_transport_header(skb);
		shdr->dst = htons(dport);
		shdr->src = htons(sport);
		shdr->len = htons(len + sizeof(struct mptphdr));

		payload = skb_put(skb, len);
		log_debug("payload=%p\n", payload);

		err =
		    skb_copy_datagram_from_iovec(skb, sizeof(struct mptphdr),
						 iov, 0, len);
		if (unlikely(err)) {
			log_error("skb_copy_datagram_from_iovec failed\n");
			goto out_free;
		}
		log_debug("Copied %u bytes into the skb\n", len);

		if (connected)
			rt = (struct rtable *)__sk_dst_check(sk, 0);

		if (rt == NULL) {
			log_debug("rt == NULL\n");
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
			struct flowi fl = {.fl4_dst = daddr,
				.proto = sk->sk_protocol,
				.flags = inet_sk_flowi_flags(sk),
			};
			err =
			    ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0);
			if (unlikely(err)) {
				log_error("Route lookup failed\n");
				goto out_free;
			}
#else
			rt = ip_route_output_flow(sock_net(sk), &fl.u.ip4, sk);
			log_debug("rt = %p\n", rt);
			if (IS_ERR(rt)) {
				log_error("Route lookup failed\n");
				goto out_free;
			}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
			sk_dst_set(sk, dst_clone(&rt->u.dst));
#else
			sk_dst_set(sk, dst_clone(&rt->dst));
#endif
		}
		log_debug("rt != NULL\n");

		skb->local_df = 1;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
		err = ip_queue_xmit(skb);
#else
		err = ip_queue_xmit(skb, &fl);
#endif
		if (likely(!err)) {
			log_debug("Sent %u bytes on wire\n", len);
			ret += len;
			dest->bytes = len;
		} else {
			log_error("ip_queue_xmit failed\n");
			dest->bytes = -1;
		}
	}

	return ret;

 out_free:
	kfree(skb);

 out:
	return err;
}
int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
	struct inet_sock *inet = inet_sk(sk);
	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
	struct flowi4 *fl4;
	struct rtable *rt;
	__be32 saddr;
	int oif;
	int err;


	if (addr_len < sizeof(*usin))
		return -EINVAL;

	if (usin->sin_family != AF_INET)
		return -EAFNOSUPPORT;

	sk_dst_reset(sk);

	lock_sock(sk);

	oif = sk->sk_bound_dev_if;
	saddr = inet->inet_saddr;
	if (ipv4_is_multicast(usin->sin_addr.s_addr)) {
		if (!oif)
			oif = inet->mc_index;
		if (!saddr)
			saddr = inet->mc_addr;
	}
	fl4 = &inet->cork.fl.u.ip4;
	rt = ip_route_connect(fl4, usin->sin_addr.s_addr, saddr,
			      RT_CONN_FLAGS(sk), oif,
			      sk->sk_protocol,
			      inet->inet_sport, usin->sin_port, sk, true);
	if (IS_ERR(rt)) {
		err = PTR_ERR(rt);
		if (err == -ENETUNREACH)
			IP_INC_STATS_BH(sock_net(sk), IPSTATS_MIB_OUTNOROUTES);
		goto out;
	}

	if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) {
		ip_rt_put(rt);
		err = -EACCES;
		goto out;
	}
	if (!inet->inet_saddr)
		inet->inet_saddr = fl4->saddr;	
	if (!inet->inet_rcv_saddr) {
		inet->inet_rcv_saddr = fl4->saddr;
		if (sk->sk_prot->rehash)
			sk->sk_prot->rehash(sk);
	}
	inet->inet_daddr = fl4->daddr;
	inet->inet_dport = usin->sin_port;
	sk->sk_state = TCP_ESTABLISHED;
	inet->inet_id = jiffies;

	sk_dst_set(sk, &rt->dst);
	err = 0;
out:
	release_sock(sk);
	return err;
}