]>
Commit | Line | Data |
---|---|---|
17926a79 DH |
1 | /* RxRPC packet transmission |
2 | * | |
3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
4 | * Written by David Howells (dhowells@redhat.com) | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
10 | */ | |
11 | ||
9b6d5398 JP |
12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
13 | ||
17926a79 | 14 | #include <linux/net.h> |
5a0e3ad6 | 15 | #include <linux/gfp.h> |
17926a79 | 16 | #include <linux/skbuff.h> |
bc3b2d7f | 17 | #include <linux/export.h> |
17926a79 DH |
18 | #include <net/sock.h> |
19 | #include <net/af_rxrpc.h> | |
20 | #include "ar-internal.h" | |
21 | ||
17926a79 DH |
22 | /* |
23 | * send a packet through the transport endpoint | |
24 | */ | |
985a5c82 | 25 | int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb) |
17926a79 DH |
26 | { |
27 | struct kvec iov[1]; | |
28 | struct msghdr msg; | |
29 | int ret, opt; | |
30 | ||
31 | _enter(",{%d}", skb->len); | |
32 | ||
33 | iov[0].iov_base = skb->head; | |
34 | iov[0].iov_len = skb->len; | |
35 | ||
985a5c82 DH |
36 | msg.msg_name = &conn->params.peer->srx.transport; |
37 | msg.msg_namelen = conn->params.peer->srx.transport_len; | |
17926a79 DH |
38 | msg.msg_control = NULL; |
39 | msg.msg_controllen = 0; | |
40 | msg.msg_flags = 0; | |
41 | ||
42 | /* send the packet with the don't fragment bit set if we currently | |
43 | * think it's small enough */ | |
985a5c82 DH |
44 | if (skb->len - sizeof(struct rxrpc_wire_header) < conn->params.peer->maxdata) { |
45 | down_read(&conn->params.local->defrag_sem); | |
17926a79 DH |
46 | /* send the packet by UDP |
47 | * - returns -EMSGSIZE if UDP would have to fragment the packet | |
48 | * to go out of the interface | |
49 | * - in which case, we'll have processed the ICMP error | |
50 | * message and update the peer record | |
51 | */ | |
985a5c82 | 52 | ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 1, |
17926a79 DH |
53 | iov[0].iov_len); |
54 | ||
985a5c82 | 55 | up_read(&conn->params.local->defrag_sem); |
17926a79 DH |
56 | if (ret == -EMSGSIZE) |
57 | goto send_fragmentable; | |
58 | ||
985a5c82 | 59 | _leave(" = %d [%u]", ret, conn->params.peer->maxdata); |
17926a79 DH |
60 | return ret; |
61 | } | |
62 | ||
63 | send_fragmentable: | |
64 | /* attempt to send this message with fragmentation enabled */ | |
65 | _debug("send fragment"); | |
66 | ||
985a5c82 DH |
67 | down_write(&conn->params.local->defrag_sem); |
68 | ||
69 | switch (conn->params.local->srx.transport.family) { | |
70 | case AF_INET: | |
71 | opt = IP_PMTUDISC_DONT; | |
72 | ret = kernel_setsockopt(conn->params.local->socket, | |
73 | SOL_IP, IP_MTU_DISCOVER, | |
74 | (char *)&opt, sizeof(opt)); | |
75 | if (ret == 0) { | |
76 | ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 1, | |
77 | iov[0].iov_len); | |
78 | ||
79 | opt = IP_PMTUDISC_DO; | |
80 | kernel_setsockopt(conn->params.local->socket, SOL_IP, | |
81 | IP_MTU_DISCOVER, | |
82 | (char *)&opt, sizeof(opt)); | |
83 | } | |
84 | break; | |
17926a79 DH |
85 | } |
86 | ||
985a5c82 DH |
87 | up_write(&conn->params.local->defrag_sem); |
88 | _leave(" = %d [frag %u]", ret, conn->params.peer->maxdata); | |
17926a79 DH |
89 | return ret; |
90 | } |