/** * tipc_msg_build - create buffer chain containing specified header and data * @mhdr: Message header, to be prepended to data * @m: User message * @offset: Posision in iov to start copying from * @dsz: Total length of user data * @pktmax: Max packet size that can be used * @list: Buffer or chain of buffers to be returned to caller * * Returns message data size or errno: -ENOMEM, -EFAULT */ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset, int dsz, int pktmax, struct sk_buff_head *list) { int mhsz = msg_hdr_sz(mhdr); int msz = mhsz + dsz; int pktno = 1; int pktsz; int pktrem = pktmax; int drem = dsz; struct tipc_msg pkthdr; struct sk_buff *skb; char *pktpos; int rc; msg_set_size(mhdr, msz); /* No fragmentation needed? */ if (likely(msz <= pktmax)) { skb = tipc_buf_acquire(msz); if (unlikely(!skb)) return -ENOMEM; __skb_queue_tail(list, skb); skb_copy_to_linear_data(skb, mhdr, mhsz); pktpos = skb->data + mhsz; if (!dsz || !memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, dsz)) return dsz; rc = -EFAULT; goto error; } /* Prepare reusable fragment header */ tipc_msg_init(&pkthdr, MSG_FRAGMENTER, FIRST_FRAGMENT, INT_H_SIZE, msg_destnode(mhdr)); msg_set_size(&pkthdr, pktmax); msg_set_fragm_no(&pkthdr, pktno); /* Prepare first fragment */ skb = tipc_buf_acquire(pktmax); if (!skb) return -ENOMEM; __skb_queue_tail(list, skb); pktpos = skb->data; skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE); pktpos += INT_H_SIZE; pktrem -= INT_H_SIZE; skb_copy_to_linear_data_offset(skb, INT_H_SIZE, mhdr, mhsz); pktpos += mhsz; pktrem -= mhsz; do { if (drem < pktrem) pktrem = drem; if (memcpy_fromiovecend(pktpos, m->msg_iter.iov, offset, pktrem)) { rc = -EFAULT; goto error; } drem -= pktrem; offset += pktrem; if (!drem) break; /* Prepare new fragment: */ if (drem < (pktmax - INT_H_SIZE)) pktsz = drem + INT_H_SIZE; else pktsz = pktmax; skb = tipc_buf_acquire(pktsz); if (!skb) { rc = -ENOMEM; goto error; } __skb_queue_tail(list, skb); msg_set_type(&pkthdr, FRAGMENT); msg_set_size(&pkthdr, pktsz); msg_set_fragm_no(&pkthdr, ++pktno); skb_copy_to_linear_data(skb, &pkthdr, INT_H_SIZE); pktpos = skb->data + INT_H_SIZE; pktrem = pktsz - INT_H_SIZE; } while (1); msg_set_type(buf_msg(skb), LAST_FRAGMENT); return dsz; error: __skb_queue_purge(list); __skb_queue_head_init(list); return rc; }
static int rawv6_getfrag(const void *data, struct in6_addr *saddr, char *buff, unsigned int offset, unsigned int len) { struct iovec *iov = (struct iovec *) data; return memcpy_fromiovecend(buff, iov, offset, len); }
static int raw_getrawfrag(const void *p, char *to, unsigned int offset, unsigned int fraglen, struct sk_buff *skb) { struct rawfakehdr *rfh = (struct rawfakehdr *) p; if (memcpy_fromiovecend(to, rfh->iov, offset, fraglen)) return -EFAULT; if (!offset) { struct iphdr *iph = (struct iphdr *)to; if (!iph->saddr) iph->saddr = rfh->saddr; iph->check = 0; iph->tot_len = htons(fraglen); /* This is right as you can't frag RAW packets */ /* * Deliberate breach of modularity to keep * ip_build_xmit clean (well less messy). */ if (!iph->id) ip_select_ident(iph, rfh->dst, NULL); iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); } return 0; }
/** * tipc_msg_build - create message using specified header and data * * Note: Caller must not hold any locks in case copy_from_user() is interrupted! * * Returns message data size or errno */ int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect, unsigned int len, int max_size, struct sk_buff **buf) { int dsz, sz, hsz; unsigned char *to; dsz = len; hsz = msg_hdr_sz(hdr); sz = hsz + dsz; msg_set_size(hdr, sz); if (unlikely(sz > max_size)) { *buf = NULL; return dsz; } *buf = tipc_buf_acquire(sz); if (!(*buf)) return -ENOMEM; skb_copy_to_linear_data(*buf, hdr, hsz); to = (*buf)->data + hsz; if (len && memcpy_fromiovecend(to, msg_sect, 0, dsz)) { kfree_skb(*buf); *buf = NULL; return -EFAULT; } return dsz; }
static int raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) { struct icmphdr icmph; int err; if (fl->proto != IPPROTO_ICMP) return 0; /* We only need the first two bytes. */ err = memcpy_fromiovecend((void *)&icmph, msg->msg_iov, 0, 2); if (err) return err; fl->fl_icmp_type = icmph.type; fl->fl_icmp_code = icmph.code; return 0; }
static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, void *from, size_t length, struct rtable **rtp, unsigned int flags) { struct inet_sock *inet = inet_sk(sk); struct net *net = sock_net(sk); struct iphdr *iph; struct sk_buff *skb; unsigned int iphlen; int err; struct rtable *rt = *rtp; int hlen, tlen; if (length > rt->dst.dev->mtu) { ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, rt->dst.dev->mtu); return -EMSGSIZE; } if (flags&MSG_PROBE) goto out; hlen = LL_RESERVED_SPACE(rt->dst.dev); tlen = rt->dst.dev->needed_tailroom; skb = sock_alloc_send_skb(sk, length + hlen + tlen + 15, flags & MSG_DONTWAIT, &err); if (skb == NULL) goto error; skb_reserve(skb, hlen); skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; skb_dst_set(skb, &rt->dst); *rtp = NULL; skb_reset_network_header(skb); iph = ip_hdr(skb); skb_put(skb, length); skb->ip_summed = CHECKSUM_NONE; skb->transport_header = skb->network_header; err = -EFAULT; if (memcpy_fromiovecend((void *)iph, from, 0, length)) goto error_free; iphlen = iph->ihl * 4; /* * We don't want to modify the ip header, but we do need to * be sure that it won't cause problems later along the network * stack. Specifically we want to make sure that iph->ihl is a * sane value. If ihl points beyond the length of the buffer passed * in, reject the frame as invalid */ err = -EINVAL; if (iphlen > length) goto error_free; if (iphlen >= sizeof(*iph)) { if (!iph->saddr) iph->saddr = fl4->saddr; iph->check = 0; iph->tot_len = htons(length); if (!iph->id) ip_select_ident(skb, NULL); iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); } if (iph->protocol == IPPROTO_ICMP) icmp_out_count(net, ((struct icmphdr *) skb_transport_header(skb))->type); err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL, rt->dst.dev, dst_output); if (err > 0) err = net_xmit_errno(err); if (err) goto error; out: return 0; error_free: kfree_skb(skb); error: IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); if (err == -ENOBUFS && !inet->recverr) err = 0; return err; }
static int raw_send_hdrinc(struct sock *sk, void *from, size_t length, struct rtable *rt, unsigned int flags) { struct inet_sock *inet = inet_sk(sk); struct net *net = sock_net(sk); struct iphdr *iph; struct sk_buff *skb; unsigned int iphlen; int err; if (length > rt->u.dst.dev->mtu) { ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport, rt->u.dst.dev->mtu); return -EMSGSIZE; } if (flags&MSG_PROBE) goto out; skb = sock_alloc_send_skb(sk, length + LL_ALLOCATED_SPACE(rt->u.dst.dev) + 15, flags & MSG_DONTWAIT, &err); if (skb == NULL) goto error; skb_reserve(skb, LL_RESERVED_SPACE(rt->u.dst.dev)); skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; skb_dst_set(skb, dst_clone(&rt->u.dst)); skb_reset_network_header(skb); iph = ip_hdr(skb); skb_put(skb, length); skb->ip_summed = CHECKSUM_NONE; skb->transport_header = skb->network_header; err = memcpy_fromiovecend((void *)iph, from, 0, length); if (err) goto error_fault; /* We don't modify invalid header */ iphlen = iph->ihl * 4; if (iphlen >= sizeof(*iph) && iphlen <= length) { if (!iph->saddr) iph->saddr = rt->rt_src; iph->check = 0; iph->tot_len = htons(length); if (!iph->id) ip_select_ident(iph, &rt->u.dst, NULL); iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); } if (iph->protocol == IPPROTO_ICMP) icmp_out_count(net, ((struct icmphdr *) skb_transport_header(skb))->type); err = NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); if (err > 0) err = net_xmit_errno(err); if (err) goto error; out: return 0; error_fault: err = -EFAULT; kfree_skb(skb); error: IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); if (err == -ENOBUFS && !inet->recverr) err = 0; return err; }
static int raw_send_hdrinc(struct sock *sk, void *from, int length, struct rtable *rt, unsigned int flags) { struct inet_sock *inet = inet_sk(sk); int hh_len; struct iphdr *iph; struct sk_buff *skb; int err; if (length > rt->u.dst.dev->mtu) { ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport, rt->u.dst.dev->mtu); return -EMSGSIZE; } if (flags&MSG_PROBE) goto out; hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); skb = sock_alloc_send_skb(sk, length+hh_len+15, flags&MSG_DONTWAIT, &err); if (skb == NULL) goto error; skb_reserve(skb, hh_len); skb->priority = sk->sk_priority; skb->dst = dst_clone(&rt->u.dst); skb->nh.iph = iph = (struct iphdr *)skb_put(skb, length); skb->ip_summed = CHECKSUM_NONE; skb->h.raw = skb->nh.raw; err = memcpy_fromiovecend((void *)iph, from, 0, length); if (err) goto error_fault; /* We don't modify invalid header */ if (length >= sizeof(*iph) && iph->ihl * 4 <= length) { if (!iph->saddr) iph->saddr = rt->rt_src; iph->check = 0; iph->tot_len = htons(length); if (!iph->id) ip_select_ident(iph, &rt->u.dst, NULL); iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); } err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); if (err > 0) err = inet->recverr ? net_xmit_errno(err) : 0; if (err) goto error; out: return 0; error_fault: err = -EFAULT; kfree_skb(skb); error: IP_INC_STATS(IPSTATS_MIB_OUTDISCARDS); return err; }
static inline int kni_vhost_net_tx(struct kni_dev *kni, struct msghdr *m, unsigned offset, unsigned len) { struct rte_kni_mbuf *pkt_kva = NULL; struct rte_kni_mbuf *pkt_va = NULL; int ret; KNI_DBG_TX("tx offset=%d, len=%d, iovlen=%d\n", #ifdef HAVE_IOV_ITER_MSGHDR offset, len, (int)m->msg_iter.iov->iov_len); #else offset, len, (int)m->msg_iov->iov_len); #endif /** * Check if it has at least one free entry in tx_q and * one entry in alloc_q. */ if (kni_fifo_free_count(kni->tx_q) == 0 || kni_fifo_count(kni->alloc_q) == 0) { /** * If no free entry in tx_q or no entry in alloc_q, * drops skb and goes out. */ goto drop; } /* dequeue a mbuf from alloc_q */ ret = kni_fifo_get(kni->alloc_q, (void **)&pkt_va, 1); if (likely(ret == 1)) { void *data_kva; pkt_kva = (void *)pkt_va - kni->mbuf_va + kni->mbuf_kva; data_kva = pkt_kva->buf_addr + pkt_kva->data_off - kni->mbuf_va + kni->mbuf_kva; #ifdef HAVE_IOV_ITER_MSGHDR copy_from_iter(data_kva, len, &m->msg_iter); #else memcpy_fromiovecend(data_kva, m->msg_iov, offset, len); #endif if (unlikely(len < ETH_ZLEN)) { memset(data_kva + len, 0, ETH_ZLEN - len); len = ETH_ZLEN; } pkt_kva->pkt_len = len; pkt_kva->data_len = len; /* enqueue mbuf into tx_q */ ret = kni_fifo_put(kni->tx_q, (void **)&pkt_va, 1); if (unlikely(ret != 1)) { /* Failing should not happen */ KNI_ERR("Fail to enqueue mbuf into tx_q\n"); goto drop; } } else { /* Failing should not happen */ KNI_ERR("Fail to dequeue mbuf from alloc_q\n"); goto drop; } /* update statistics */ kni->stats.tx_bytes += len; kni->stats.tx_packets++; return 0; drop: /* update statistics */ kni->stats.tx_dropped++; return 0; }
static int raw_getfrag(const void *p, char *to, unsigned int offset, unsigned int fraglen, struct sk_buff *skb) { struct rawfakehdr *rfh = (struct rawfakehdr *) p; return memcpy_fromiovecend(to, rfh->iov, offset, fraglen); }