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); }
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; }
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; }