|
@@ -1267,9 +1267,9 @@ static void ip_cork_release(struct inet_cork *cork)
|
|
|
* Combined all pending IP fragments on the socket as one IP datagram
|
|
|
* and push them out.
|
|
|
*/
|
|
|
-static int __ip_push_pending_frames(struct sock *sk,
|
|
|
- struct sk_buff_head *queue,
|
|
|
- struct inet_cork *cork)
|
|
|
+struct sk_buff *__ip_make_skb(struct sock *sk,
|
|
|
+ struct sk_buff_head *queue,
|
|
|
+ struct inet_cork *cork)
|
|
|
{
|
|
|
struct sk_buff *skb, *tmp_skb;
|
|
|
struct sk_buff **tail_skb;
|
|
@@ -1280,7 +1280,6 @@ static int __ip_push_pending_frames(struct sock *sk,
|
|
|
struct iphdr *iph;
|
|
|
__be16 df = 0;
|
|
|
__u8 ttl;
|
|
|
- int err = 0;
|
|
|
|
|
|
if ((skb = __skb_dequeue(queue)) == NULL)
|
|
|
goto out;
|
|
@@ -1351,28 +1350,37 @@ static int __ip_push_pending_frames(struct sock *sk,
|
|
|
icmp_out_count(net, ((struct icmphdr *)
|
|
|
skb_transport_header(skb))->type);
|
|
|
|
|
|
- /* Netfilter gets whole the not fragmented skb. */
|
|
|
+ ip_cork_release(cork);
|
|
|
+out:
|
|
|
+ return skb;
|
|
|
+}
|
|
|
+
|
|
|
+int ip_send_skb(struct sk_buff *skb)
|
|
|
+{
|
|
|
+ struct net *net = sock_net(skb->sk);
|
|
|
+ int err;
|
|
|
+
|
|
|
err = ip_local_out(skb);
|
|
|
if (err) {
|
|
|
if (err > 0)
|
|
|
err = net_xmit_errno(err);
|
|
|
if (err)
|
|
|
- goto error;
|
|
|
+ IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
|
|
|
}
|
|
|
|
|
|
-out:
|
|
|
- ip_cork_release(cork);
|
|
|
return err;
|
|
|
-
|
|
|
-error:
|
|
|
- IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
|
|
|
- goto out;
|
|
|
}
|
|
|
|
|
|
int ip_push_pending_frames(struct sock *sk)
|
|
|
{
|
|
|
- return __ip_push_pending_frames(sk, &sk->sk_write_queue,
|
|
|
- &inet_sk(sk)->cork);
|
|
|
+ struct sk_buff *skb;
|
|
|
+
|
|
|
+ skb = ip_finish_skb(sk);
|
|
|
+ if (!skb)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* Netfilter gets whole the not fragmented skb. */
|
|
|
+ return ip_send_skb(skb);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1395,6 +1403,35 @@ void ip_flush_pending_frames(struct sock *sk)
|
|
|
__ip_flush_pending_frames(sk, &sk->sk_write_queue, &inet_sk(sk)->cork);
|
|
|
}
|
|
|
|
|
|
+struct sk_buff *ip_make_skb(struct sock *sk,
|
|
|
+ int getfrag(void *from, char *to, int offset,
|
|
|
+ int len, int odd, struct sk_buff *skb),
|
|
|
+ void *from, int length, int transhdrlen,
|
|
|
+ struct ipcm_cookie *ipc, struct rtable **rtp,
|
|
|
+ unsigned int flags)
|
|
|
+{
|
|
|
+ struct inet_cork cork = {};
|
|
|
+ struct sk_buff_head queue;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (flags & MSG_PROBE)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ __skb_queue_head_init(&queue);
|
|
|
+
|
|
|
+ err = ip_setup_cork(sk, &cork, ipc, rtp);
|
|
|
+ if (err)
|
|
|
+ return ERR_PTR(err);
|
|
|
+
|
|
|
+ err = __ip_append_data(sk, &queue, &cork, getfrag,
|
|
|
+ from, length, transhdrlen, flags);
|
|
|
+ if (err) {
|
|
|
+ __ip_flush_pending_frames(sk, &queue, &cork);
|
|
|
+ return ERR_PTR(err);
|
|
|
+ }
|
|
|
+
|
|
|
+ return __ip_make_skb(sk, &queue, &cork);
|
|
|
+}
|
|
|
|
|
|
/*
|
|
|
* Fetch data from kernel space and fill in checksum if needed.
|