svn cleanup
[anytun.git] / openvpn / mtu.c
blob14df3b675e1bb2ac916f547dd6ee1868b1ca7ab7
1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
8 * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #ifdef WIN32
26 #include "config-win32.h"
27 #else
28 #include "config.h"
29 #endif
31 #include "syshead.h"
33 #include "common.h"
34 #include "buffer.h"
35 #include "error.h"
36 #include "integer.h"
37 #include "mtu.h"
39 #include "memdbg.h"
41 /* allocate a buffer for socket or tun layer */
42 void
43 alloc_buf_sock_tun (struct buffer *buf,
44 const struct frame *frame,
45 const bool tuntap_buffer,
46 const unsigned int align_mask)
48 /* allocate buffer for overlapped I/O */
49 *buf = alloc_buf (BUF_SIZE (frame));
50 ASSERT (buf_init (buf, FRAME_HEADROOM_ADJ (frame, align_mask)));
51 buf->len = tuntap_buffer ? MAX_RW_SIZE_TUN (frame) : MAX_RW_SIZE_LINK (frame);
52 ASSERT (buf_safe (buf, 0));
55 void
56 frame_finalize (struct frame *frame,
57 bool link_mtu_defined,
58 int link_mtu,
59 bool tun_mtu_defined,
60 int tun_mtu)
62 /* Set link_mtu based on command line options */
63 if (tun_mtu_defined)
65 ASSERT (!link_mtu_defined);
66 frame->link_mtu = tun_mtu + TUN_LINK_DELTA (frame);
68 else
70 ASSERT (link_mtu_defined);
71 frame->link_mtu = link_mtu;
74 if (TUN_MTU_SIZE (frame) < TUN_MTU_MIN)
76 msg (M_WARN, "TUN MTU value (%d) must be at least %d", TUN_MTU_SIZE (frame), TUN_MTU_MIN);
77 frame_print (frame, M_FATAL, "MTU is too small");
80 frame->link_mtu_dynamic = frame->link_mtu;
82 frame->extra_buffer += PAYLOAD_ALIGN;
86 * Set the tun MTU dynamically.
88 void
89 frame_set_mtu_dynamic (struct frame *frame, int mtu, unsigned int flags)
92 #ifdef ENABLE_DEBUG
93 const int orig_mtu = mtu;
94 const int orig_link_mtu_dynamic = frame->link_mtu_dynamic;
95 #endif
97 ASSERT (mtu >= 0);
99 if (flags & SET_MTU_TUN)
100 mtu += TUN_LINK_DELTA (frame);
102 if (!(flags & SET_MTU_UPPER_BOUND) || mtu < frame->link_mtu_dynamic)
104 frame->link_mtu_dynamic = constrain_int (
105 mtu,
106 EXPANDED_SIZE_MIN (frame),
107 EXPANDED_SIZE (frame));
110 dmsg (D_MTU_DEBUG, "MTU DYNAMIC mtu=%d, flags=%u, %d -> %d",
111 orig_mtu,
112 flags,
113 orig_link_mtu_dynamic,
114 frame->link_mtu_dynamic);
118 * Move extra_frame octets into extra_tun. Used by fragmenting code
119 * to adjust frame relative to its position in the buffer processing
120 * queue.
122 void
123 frame_subtract_extra (struct frame *frame, const struct frame *src)
125 frame->extra_frame -= src->extra_frame;
126 frame->extra_tun += src->extra_frame;
129 void
130 frame_print (const struct frame *frame,
131 int level,
132 const char *prefix)
134 struct gc_arena gc = gc_new ();
135 struct buffer out = alloc_buf_gc (256, &gc);
136 if (prefix)
137 buf_printf (&out, "%s ", prefix);
138 buf_printf (&out, "[");
139 buf_printf (&out, " L:%d", frame->link_mtu);
140 buf_printf (&out, " D:%d", frame->link_mtu_dynamic);
141 buf_printf (&out, " EF:%d", frame->extra_frame);
142 buf_printf (&out, " EB:%d", frame->extra_buffer);
143 buf_printf (&out, " ET:%d", frame->extra_tun);
144 buf_printf (&out, " EL:%d", frame->extra_link);
145 if (frame->align_flags && frame->align_adjust)
146 buf_printf (&out, " AF:%u/%d", frame->align_flags, frame->align_adjust);
147 buf_printf (&out, " ]");
149 msg (level, "%s", out.data);
150 gc_free (&gc);
153 #define MTUDISC_NOT_SUPPORTED_MSG "--mtu-disc is not supported on this OS"
155 void
156 set_mtu_discover_type (int sd, int mtu_type)
158 if (mtu_type >= 0)
160 #if defined(HAVE_SETSOCKOPT) && defined(SOL_IP) && defined(IP_MTU_DISCOVER)
161 if (setsockopt
162 (sd, SOL_IP, IP_MTU_DISCOVER, &mtu_type, sizeof (mtu_type)))
163 msg (M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket",
164 mtu_type);
165 #else
166 msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG);
167 #endif
172 translate_mtu_discover_type_name (const char *name)
174 #if defined(IP_PMTUDISC_DONT) && defined(IP_PMTUDISC_WANT) && defined(IP_PMTUDISC_DO)
175 if (!strcmp (name, "yes"))
176 return IP_PMTUDISC_DO;
177 if (!strcmp (name, "maybe"))
178 return IP_PMTUDISC_WANT;
179 if (!strcmp (name, "no"))
180 return IP_PMTUDISC_DONT;
181 msg (M_FATAL,
182 "invalid --mtu-disc type: '%s' -- valid types are 'yes', 'maybe', or 'no'",
183 name);
184 #else
185 msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG);
186 #endif
187 return -1; /* NOTREACHED */
190 #if EXTENDED_SOCKET_ERROR_CAPABILITY
194 * The following code is adapted from tracepath
195 * under the terms of the GPL.
196 * Copyright (C) Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>.
199 struct probehdr
201 uint32_t ttl;
202 struct timeval tv;
205 const char *
206 format_extended_socket_error (int fd, int *mtu, struct gc_arena *gc)
208 int res;
209 struct probehdr rcvbuf;
210 struct iovec iov;
211 struct msghdr msg;
212 struct cmsghdr *cmsg;
213 struct sock_extended_err *e;
214 struct sockaddr_in addr;
215 struct buffer out = alloc_buf_gc (256, gc);
216 char *cbuf = (char *) gc_malloc (256, false, gc);
218 *mtu = 0;
220 while (true)
222 memset (&rcvbuf, -1, sizeof (rcvbuf));
223 iov.iov_base = &rcvbuf;
224 iov.iov_len = sizeof (rcvbuf);
225 msg.msg_name = (uint8_t *) &addr;
226 msg.msg_namelen = sizeof (addr);
227 msg.msg_iov = &iov;
228 msg.msg_iovlen = 1;
229 msg.msg_flags = 0;
230 msg.msg_control = cbuf;
231 msg.msg_controllen = 256; /* size of cbuf */
233 res = recvmsg (fd, &msg, MSG_ERRQUEUE);
234 if (res < 0)
235 goto exit;
237 e = NULL;
239 for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg))
241 if (cmsg->cmsg_level == SOL_IP)
243 if (cmsg->cmsg_type == IP_RECVERR)
245 e = (struct sock_extended_err *) CMSG_DATA (cmsg);
247 else
249 buf_printf (&out ,"CMSG=%d|", cmsg->cmsg_type);
253 if (e == NULL)
255 buf_printf (&out, "NO-INFO|");
256 goto exit;
259 switch (e->ee_errno)
261 case ETIMEDOUT:
262 buf_printf (&out, "ETIMEDOUT|");
263 break;
264 case EMSGSIZE:
265 buf_printf (&out, "EMSGSIZE Path-MTU=%d|", e->ee_info);
266 *mtu = e->ee_info;
267 break;
268 case ECONNREFUSED:
269 buf_printf (&out, "ECONNREFUSED|");
270 break;
271 case EPROTO:
272 buf_printf (&out, "EPROTO|");
273 break;
274 case EHOSTUNREACH:
275 buf_printf (&out, "EHOSTUNREACH|");
276 break;
277 case ENETUNREACH:
278 buf_printf (&out, "ENETUNREACH|");
279 break;
280 case EACCES:
281 buf_printf (&out, "EACCES|");
282 break;
283 default:
284 buf_printf (&out, "UNKNOWN|");
285 break;
289 exit:
290 buf_rmtail (&out, '|');
291 return BSTR (&out);
294 void
295 set_sock_extended_error_passing (int sd)
297 int on = 1;
298 if (setsockopt (sd, SOL_IP, IP_RECVERR, &on, sizeof (on)))
299 msg (M_WARN | M_ERRNO,
300 "Note: enable extended error passing on TCP/UDP socket failed (IP_RECVERR)");
303 #endif