1*0a66de84SNuno Antunes /*-
2*0a66de84SNuno Antunes * ng_tcpmss.c
3*0a66de84SNuno Antunes *
4*0a66de84SNuno Antunes * Copyright (c) 2004, Alexey Popov <lollypop@flexuser.ru>
5*0a66de84SNuno Antunes * All rights reserved.
6*0a66de84SNuno Antunes *
7*0a66de84SNuno Antunes * Redistribution and use in source and binary forms, with or without
8*0a66de84SNuno Antunes * modification, are permitted provided that the following conditions
9*0a66de84SNuno Antunes * are met:
10*0a66de84SNuno Antunes * 1. Redistributions of source code must retain the above copyright
11*0a66de84SNuno Antunes * notice unmodified, this list of conditions, and the following
12*0a66de84SNuno Antunes * disclaimer.
13*0a66de84SNuno Antunes * 2. Redistributions in binary form must reproduce the above copyright
14*0a66de84SNuno Antunes * notice, this list of conditions and the following disclaimer in the
15*0a66de84SNuno Antunes * documentation and/or other materials provided with the distribution.
16*0a66de84SNuno Antunes *
17*0a66de84SNuno Antunes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*0a66de84SNuno Antunes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*0a66de84SNuno Antunes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*0a66de84SNuno Antunes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*0a66de84SNuno Antunes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*0a66de84SNuno Antunes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*0a66de84SNuno Antunes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*0a66de84SNuno Antunes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*0a66de84SNuno Antunes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*0a66de84SNuno Antunes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*0a66de84SNuno Antunes * SUCH DAMAGE.
28*0a66de84SNuno Antunes *
29*0a66de84SNuno Antunes * This software includes fragments of the following programs:
30*0a66de84SNuno Antunes * tcpmssd Ruslan Ermilov <ru@FreeBSD.org>
31*0a66de84SNuno Antunes *
32*0a66de84SNuno Antunes * $FreeBSD: src/sys/netgraph/ng_tcpmss.c,v 1.4 2007/01/15 05:01:31 glebius Exp $
33*0a66de84SNuno Antunes * $DragonFly: src/sys/netgraph7/ng_tcpmss.c,v 1.2 2008/06/26 23:05:35 dillon Exp $
34*0a66de84SNuno Antunes */
35*0a66de84SNuno Antunes
36*0a66de84SNuno Antunes /*
37*0a66de84SNuno Antunes * This node is netgraph tool for workaround of PMTUD problem. It acts
38*0a66de84SNuno Antunes * like filter for IP packets. If configured, it reduces MSS of TCP SYN
39*0a66de84SNuno Antunes * packets.
40*0a66de84SNuno Antunes *
41*0a66de84SNuno Antunes * Configuration can be done by sending NGM_TCPMSS_CONFIG message. The
42*0a66de84SNuno Antunes * message sets filter for incoming packets on hook 'inHook'. Packet's
43*0a66de84SNuno Antunes * TCP MSS field is lowered to 'maxMSS' parameter and resulting packet
44*0a66de84SNuno Antunes * is sent to 'outHook'.
45*0a66de84SNuno Antunes *
46*0a66de84SNuno Antunes * XXX: statistics are updated not atomically, so they may broke on SMP.
47*0a66de84SNuno Antunes */
48*0a66de84SNuno Antunes
49*0a66de84SNuno Antunes #include <sys/param.h>
50*0a66de84SNuno Antunes #include <sys/systm.h>
51*0a66de84SNuno Antunes #include <sys/errno.h>
52*0a66de84SNuno Antunes #include <sys/kernel.h>
53*0a66de84SNuno Antunes #include <sys/malloc.h>
54*0a66de84SNuno Antunes #include <sys/mbuf.h>
55*0a66de84SNuno Antunes
56*0a66de84SNuno Antunes #include <netinet/in.h>
57*0a66de84SNuno Antunes #include <netinet/in_systm.h>
58*0a66de84SNuno Antunes #include <netinet/ip.h>
59*0a66de84SNuno Antunes #include <netinet/tcp.h>
60*0a66de84SNuno Antunes
61*0a66de84SNuno Antunes #include <netgraph7/ng_message.h>
62*0a66de84SNuno Antunes #include <netgraph7/netgraph.h>
63*0a66de84SNuno Antunes #include <netgraph7/ng_parse.h>
64*0a66de84SNuno Antunes #include "ng_tcpmss.h"
65*0a66de84SNuno Antunes
66*0a66de84SNuno Antunes /* Per hook info. */
67*0a66de84SNuno Antunes typedef struct {
68*0a66de84SNuno Antunes hook_p outHook;
69*0a66de84SNuno Antunes struct ng_tcpmss_hookstat stats;
70*0a66de84SNuno Antunes } *hpriv_p;
71*0a66de84SNuno Antunes
72*0a66de84SNuno Antunes /* Netgraph methods. */
73*0a66de84SNuno Antunes static ng_constructor_t ng_tcpmss_constructor;
74*0a66de84SNuno Antunes static ng_rcvmsg_t ng_tcpmss_rcvmsg;
75*0a66de84SNuno Antunes static ng_newhook_t ng_tcpmss_newhook;
76*0a66de84SNuno Antunes static ng_rcvdata_t ng_tcpmss_rcvdata;
77*0a66de84SNuno Antunes static ng_disconnect_t ng_tcpmss_disconnect;
78*0a66de84SNuno Antunes
79*0a66de84SNuno Antunes static int correct_mss(struct tcphdr *, int, uint16_t, int);
80*0a66de84SNuno Antunes
81*0a66de84SNuno Antunes /* Parse type for struct ng_tcpmss_hookstat. */
82*0a66de84SNuno Antunes static const struct ng_parse_struct_field ng_tcpmss_hookstat_type_fields[]
83*0a66de84SNuno Antunes = NG_TCPMSS_HOOKSTAT_INFO;
84*0a66de84SNuno Antunes static const struct ng_parse_type ng_tcpmss_hookstat_type = {
85*0a66de84SNuno Antunes &ng_parse_struct_type,
86*0a66de84SNuno Antunes &ng_tcpmss_hookstat_type_fields
87*0a66de84SNuno Antunes };
88*0a66de84SNuno Antunes
89*0a66de84SNuno Antunes /* Parse type for struct ng_tcpmss_config. */
90*0a66de84SNuno Antunes static const struct ng_parse_struct_field ng_tcpmss_config_type_fields[]
91*0a66de84SNuno Antunes = NG_TCPMSS_CONFIG_INFO;
92*0a66de84SNuno Antunes static const struct ng_parse_type ng_tcpmss_config_type = {
93*0a66de84SNuno Antunes &ng_parse_struct_type,
94*0a66de84SNuno Antunes ng_tcpmss_config_type_fields
95*0a66de84SNuno Antunes };
96*0a66de84SNuno Antunes
97*0a66de84SNuno Antunes /* List of commands and how to convert arguments to/from ASCII. */
98*0a66de84SNuno Antunes static const struct ng_cmdlist ng_tcpmss_cmds[] = {
99*0a66de84SNuno Antunes {
100*0a66de84SNuno Antunes NGM_TCPMSS_COOKIE,
101*0a66de84SNuno Antunes NGM_TCPMSS_GET_STATS,
102*0a66de84SNuno Antunes "getstats",
103*0a66de84SNuno Antunes &ng_parse_hookbuf_type,
104*0a66de84SNuno Antunes &ng_tcpmss_hookstat_type
105*0a66de84SNuno Antunes },
106*0a66de84SNuno Antunes {
107*0a66de84SNuno Antunes NGM_TCPMSS_COOKIE,
108*0a66de84SNuno Antunes NGM_TCPMSS_CLR_STATS,
109*0a66de84SNuno Antunes "clrstats",
110*0a66de84SNuno Antunes &ng_parse_hookbuf_type,
111*0a66de84SNuno Antunes NULL
112*0a66de84SNuno Antunes },
113*0a66de84SNuno Antunes {
114*0a66de84SNuno Antunes NGM_TCPMSS_COOKIE,
115*0a66de84SNuno Antunes NGM_TCPMSS_GETCLR_STATS,
116*0a66de84SNuno Antunes "getclrstats",
117*0a66de84SNuno Antunes &ng_parse_hookbuf_type,
118*0a66de84SNuno Antunes &ng_tcpmss_hookstat_type
119*0a66de84SNuno Antunes },
120*0a66de84SNuno Antunes {
121*0a66de84SNuno Antunes NGM_TCPMSS_COOKIE,
122*0a66de84SNuno Antunes NGM_TCPMSS_CONFIG,
123*0a66de84SNuno Antunes "config",
124*0a66de84SNuno Antunes &ng_tcpmss_config_type,
125*0a66de84SNuno Antunes NULL
126*0a66de84SNuno Antunes },
127*0a66de84SNuno Antunes { 0 }
128*0a66de84SNuno Antunes };
129*0a66de84SNuno Antunes
130*0a66de84SNuno Antunes /* Netgraph type descriptor. */
131*0a66de84SNuno Antunes static struct ng_type ng_tcpmss_typestruct = {
132*0a66de84SNuno Antunes .version = NG_ABI_VERSION,
133*0a66de84SNuno Antunes .name = NG_TCPMSS_NODE_TYPE,
134*0a66de84SNuno Antunes .constructor = ng_tcpmss_constructor,
135*0a66de84SNuno Antunes .rcvmsg = ng_tcpmss_rcvmsg,
136*0a66de84SNuno Antunes .newhook = ng_tcpmss_newhook,
137*0a66de84SNuno Antunes .rcvdata = ng_tcpmss_rcvdata,
138*0a66de84SNuno Antunes .disconnect = ng_tcpmss_disconnect,
139*0a66de84SNuno Antunes .cmdlist = ng_tcpmss_cmds,
140*0a66de84SNuno Antunes };
141*0a66de84SNuno Antunes
142*0a66de84SNuno Antunes NETGRAPH_INIT(tcpmss, &ng_tcpmss_typestruct);
143*0a66de84SNuno Antunes
144*0a66de84SNuno Antunes #define ERROUT(x) { error = (x); goto done; }
145*0a66de84SNuno Antunes
146*0a66de84SNuno Antunes /*
147*0a66de84SNuno Antunes * Node constructor. No special actions required.
148*0a66de84SNuno Antunes */
149*0a66de84SNuno Antunes static int
ng_tcpmss_constructor(node_p node)150*0a66de84SNuno Antunes ng_tcpmss_constructor(node_p node)
151*0a66de84SNuno Antunes {
152*0a66de84SNuno Antunes return (0);
153*0a66de84SNuno Antunes }
154*0a66de84SNuno Antunes
155*0a66de84SNuno Antunes /*
156*0a66de84SNuno Antunes * Add a hook. Any unique name is OK.
157*0a66de84SNuno Antunes */
158*0a66de84SNuno Antunes static int
ng_tcpmss_newhook(node_p node,hook_p hook,const char * name)159*0a66de84SNuno Antunes ng_tcpmss_newhook(node_p node, hook_p hook, const char *name)
160*0a66de84SNuno Antunes {
161*0a66de84SNuno Antunes hpriv_p priv;
162*0a66de84SNuno Antunes
163*0a66de84SNuno Antunes priv = kmalloc(sizeof(*priv), M_NETGRAPH,
164*0a66de84SNuno Antunes M_WAITOK | M_NULLOK | M_ZERO);
165*0a66de84SNuno Antunes if (priv == NULL)
166*0a66de84SNuno Antunes return (ENOMEM);
167*0a66de84SNuno Antunes
168*0a66de84SNuno Antunes NG_HOOK_SET_PRIVATE(hook, priv);
169*0a66de84SNuno Antunes
170*0a66de84SNuno Antunes return (0);
171*0a66de84SNuno Antunes }
172*0a66de84SNuno Antunes
173*0a66de84SNuno Antunes /*
174*0a66de84SNuno Antunes * Receive a control message.
175*0a66de84SNuno Antunes */
176*0a66de84SNuno Antunes static int
ng_tcpmss_rcvmsg(node_p node,item_p item,hook_p lasthook)177*0a66de84SNuno Antunes ng_tcpmss_rcvmsg
178*0a66de84SNuno Antunes (node_p node, item_p item, hook_p lasthook)
179*0a66de84SNuno Antunes {
180*0a66de84SNuno Antunes struct ng_mesg *msg, *resp = NULL;
181*0a66de84SNuno Antunes int error = 0;
182*0a66de84SNuno Antunes
183*0a66de84SNuno Antunes NGI_GET_MSG(item, msg);
184*0a66de84SNuno Antunes
185*0a66de84SNuno Antunes switch (msg->header.typecookie) {
186*0a66de84SNuno Antunes case NGM_TCPMSS_COOKIE:
187*0a66de84SNuno Antunes switch (msg->header.cmd) {
188*0a66de84SNuno Antunes case NGM_TCPMSS_GET_STATS:
189*0a66de84SNuno Antunes case NGM_TCPMSS_CLR_STATS:
190*0a66de84SNuno Antunes case NGM_TCPMSS_GETCLR_STATS:
191*0a66de84SNuno Antunes {
192*0a66de84SNuno Antunes hook_p hook;
193*0a66de84SNuno Antunes hpriv_p priv;
194*0a66de84SNuno Antunes
195*0a66de84SNuno Antunes /* Check that message is long enough. */
196*0a66de84SNuno Antunes if (msg->header.arglen != NG_HOOKSIZ)
197*0a66de84SNuno Antunes ERROUT(EINVAL);
198*0a66de84SNuno Antunes
199*0a66de84SNuno Antunes /* Find this hook. */
200*0a66de84SNuno Antunes hook = ng_findhook(node, (char *)msg->data);
201*0a66de84SNuno Antunes if (hook == NULL)
202*0a66de84SNuno Antunes ERROUT(ENOENT);
203*0a66de84SNuno Antunes
204*0a66de84SNuno Antunes priv = NG_HOOK_PRIVATE(hook);
205*0a66de84SNuno Antunes
206*0a66de84SNuno Antunes /* Create response. */
207*0a66de84SNuno Antunes if (msg->header.cmd != NGM_TCPMSS_CLR_STATS) {
208*0a66de84SNuno Antunes NG_MKRESPONSE(resp, msg,
209*0a66de84SNuno Antunes sizeof(struct ng_tcpmss_hookstat), M_WAITOK | M_NULLOK);
210*0a66de84SNuno Antunes if (resp == NULL)
211*0a66de84SNuno Antunes ERROUT(ENOMEM);
212*0a66de84SNuno Antunes bcopy(&priv->stats, resp->data,
213*0a66de84SNuno Antunes sizeof(struct ng_tcpmss_hookstat));
214*0a66de84SNuno Antunes }
215*0a66de84SNuno Antunes
216*0a66de84SNuno Antunes if (msg->header.cmd != NGM_TCPMSS_GET_STATS)
217*0a66de84SNuno Antunes bzero(&priv->stats,
218*0a66de84SNuno Antunes sizeof(struct ng_tcpmss_hookstat));
219*0a66de84SNuno Antunes break;
220*0a66de84SNuno Antunes }
221*0a66de84SNuno Antunes case NGM_TCPMSS_CONFIG:
222*0a66de84SNuno Antunes {
223*0a66de84SNuno Antunes struct ng_tcpmss_config *set;
224*0a66de84SNuno Antunes hook_p in, out;
225*0a66de84SNuno Antunes hpriv_p priv;
226*0a66de84SNuno Antunes
227*0a66de84SNuno Antunes /* Check that message is long enough. */
228*0a66de84SNuno Antunes if (msg->header.arglen !=
229*0a66de84SNuno Antunes sizeof(struct ng_tcpmss_config))
230*0a66de84SNuno Antunes ERROUT(EINVAL);
231*0a66de84SNuno Antunes
232*0a66de84SNuno Antunes set = (struct ng_tcpmss_config *)msg->data;
233*0a66de84SNuno Antunes in = ng_findhook(node, set->inHook);
234*0a66de84SNuno Antunes out = ng_findhook(node, set->outHook);
235*0a66de84SNuno Antunes if (in == NULL || out == NULL)
236*0a66de84SNuno Antunes ERROUT(ENOENT);
237*0a66de84SNuno Antunes
238*0a66de84SNuno Antunes /* Configure MSS hack. */
239*0a66de84SNuno Antunes priv = NG_HOOK_PRIVATE(in);
240*0a66de84SNuno Antunes priv->outHook = out;
241*0a66de84SNuno Antunes priv->stats.maxMSS = set->maxMSS;
242*0a66de84SNuno Antunes
243*0a66de84SNuno Antunes break;
244*0a66de84SNuno Antunes }
245*0a66de84SNuno Antunes default:
246*0a66de84SNuno Antunes error = EINVAL;
247*0a66de84SNuno Antunes break;
248*0a66de84SNuno Antunes }
249*0a66de84SNuno Antunes break;
250*0a66de84SNuno Antunes default:
251*0a66de84SNuno Antunes error = EINVAL;
252*0a66de84SNuno Antunes break;
253*0a66de84SNuno Antunes }
254*0a66de84SNuno Antunes
255*0a66de84SNuno Antunes done:
256*0a66de84SNuno Antunes NG_RESPOND_MSG(error, node, item, resp);
257*0a66de84SNuno Antunes NG_FREE_MSG(msg);
258*0a66de84SNuno Antunes
259*0a66de84SNuno Antunes return (error);
260*0a66de84SNuno Antunes }
261*0a66de84SNuno Antunes
262*0a66de84SNuno Antunes /*
263*0a66de84SNuno Antunes * Receive data on a hook, and hack MSS.
264*0a66de84SNuno Antunes *
265*0a66de84SNuno Antunes */
266*0a66de84SNuno Antunes static int
ng_tcpmss_rcvdata(hook_p hook,item_p item)267*0a66de84SNuno Antunes ng_tcpmss_rcvdata(hook_p hook, item_p item)
268*0a66de84SNuno Antunes {
269*0a66de84SNuno Antunes hpriv_p priv = NG_HOOK_PRIVATE(hook);
270*0a66de84SNuno Antunes struct mbuf *m = NULL;
271*0a66de84SNuno Antunes struct ip *ip;
272*0a66de84SNuno Antunes struct tcphdr *tcp;
273*0a66de84SNuno Antunes int iphlen, tcphlen, pktlen;
274*0a66de84SNuno Antunes int pullup_len = 0;
275*0a66de84SNuno Antunes int error = 0;
276*0a66de84SNuno Antunes
277*0a66de84SNuno Antunes /* Drop packets if filter is not configured on this hook. */
278*0a66de84SNuno Antunes if (priv->outHook == NULL)
279*0a66de84SNuno Antunes goto done;
280*0a66de84SNuno Antunes
281*0a66de84SNuno Antunes NGI_GET_M(item, m);
282*0a66de84SNuno Antunes
283*0a66de84SNuno Antunes /* Update stats on incoming hook. */
284*0a66de84SNuno Antunes pktlen = m->m_pkthdr.len;
285*0a66de84SNuno Antunes priv->stats.Octets += pktlen;
286*0a66de84SNuno Antunes priv->stats.Packets++;
287*0a66de84SNuno Antunes
288*0a66de84SNuno Antunes /* Check whether we configured to fix MSS. */
289*0a66de84SNuno Antunes if (priv->stats.maxMSS == 0)
290*0a66de84SNuno Antunes goto send;
291*0a66de84SNuno Antunes
292*0a66de84SNuno Antunes #define M_CHECK(length) do { \
293*0a66de84SNuno Antunes pullup_len += length; \
294*0a66de84SNuno Antunes if ((m)->m_pkthdr.len < pullup_len) \
295*0a66de84SNuno Antunes goto send; \
296*0a66de84SNuno Antunes if ((m)->m_len < pullup_len && \
297*0a66de84SNuno Antunes (((m) = m_pullup((m), pullup_len)) == NULL)) \
298*0a66de84SNuno Antunes ERROUT(ENOBUFS); \
299*0a66de84SNuno Antunes } while (0)
300*0a66de84SNuno Antunes
301*0a66de84SNuno Antunes /* Check mbuf packet size and arrange for IP header. */
302*0a66de84SNuno Antunes M_CHECK(sizeof(struct ip));
303*0a66de84SNuno Antunes ip = mtod(m, struct ip *);
304*0a66de84SNuno Antunes
305*0a66de84SNuno Antunes /* Check IP version. */
306*0a66de84SNuno Antunes if (ip->ip_v != IPVERSION)
307*0a66de84SNuno Antunes ERROUT(EINVAL);
308*0a66de84SNuno Antunes
309*0a66de84SNuno Antunes /* Check IP header length. */
310*0a66de84SNuno Antunes iphlen = ip->ip_hl << 2;
311*0a66de84SNuno Antunes if (iphlen < sizeof(struct ip) || iphlen > pktlen )
312*0a66de84SNuno Antunes ERROUT(EINVAL);
313*0a66de84SNuno Antunes
314*0a66de84SNuno Antunes /* Check if it is TCP. */
315*0a66de84SNuno Antunes if (!(ip->ip_p == IPPROTO_TCP))
316*0a66de84SNuno Antunes goto send;
317*0a66de84SNuno Antunes
318*0a66de84SNuno Antunes /* Check mbuf packet size and arrange for IP+TCP header */
319*0a66de84SNuno Antunes M_CHECK(iphlen - sizeof(struct ip) + sizeof(struct tcphdr));
320*0a66de84SNuno Antunes ip = mtod(m, struct ip *);
321*0a66de84SNuno Antunes tcp = (struct tcphdr *)((caddr_t )ip + iphlen);
322*0a66de84SNuno Antunes
323*0a66de84SNuno Antunes /* Check TCP header length. */
324*0a66de84SNuno Antunes tcphlen = tcp->th_off << 2;
325*0a66de84SNuno Antunes if (tcphlen < sizeof(struct tcphdr) || tcphlen > pktlen - iphlen)
326*0a66de84SNuno Antunes ERROUT(EINVAL);
327*0a66de84SNuno Antunes
328*0a66de84SNuno Antunes /* Check SYN packet and has options. */
329*0a66de84SNuno Antunes if (!(tcp->th_flags & TH_SYN) || tcphlen == sizeof(struct tcphdr))
330*0a66de84SNuno Antunes goto send;
331*0a66de84SNuno Antunes
332*0a66de84SNuno Antunes /* Update SYN stats. */
333*0a66de84SNuno Antunes priv->stats.SYNPkts++;
334*0a66de84SNuno Antunes
335*0a66de84SNuno Antunes M_CHECK(tcphlen - sizeof(struct tcphdr));
336*0a66de84SNuno Antunes ip = mtod(m, struct ip *);
337*0a66de84SNuno Antunes tcp = (struct tcphdr *)((caddr_t )ip + iphlen);
338*0a66de84SNuno Antunes
339*0a66de84SNuno Antunes #undef M_CHECK
340*0a66de84SNuno Antunes
341*0a66de84SNuno Antunes /* Fix MSS and update stats. */
342*0a66de84SNuno Antunes if (correct_mss(tcp, tcphlen, priv->stats.maxMSS,
343*0a66de84SNuno Antunes m->m_pkthdr.csum_flags))
344*0a66de84SNuno Antunes priv->stats.FixedPkts++;
345*0a66de84SNuno Antunes
346*0a66de84SNuno Antunes send:
347*0a66de84SNuno Antunes /* Deliver frame out destination hook. */
348*0a66de84SNuno Antunes NG_FWD_NEW_DATA(error, item, priv->outHook, m);
349*0a66de84SNuno Antunes
350*0a66de84SNuno Antunes return (error);
351*0a66de84SNuno Antunes
352*0a66de84SNuno Antunes done:
353*0a66de84SNuno Antunes NG_FREE_ITEM(item);
354*0a66de84SNuno Antunes NG_FREE_M(m);
355*0a66de84SNuno Antunes
356*0a66de84SNuno Antunes return (error);
357*0a66de84SNuno Antunes }
358*0a66de84SNuno Antunes
359*0a66de84SNuno Antunes /*
360*0a66de84SNuno Antunes * Hook disconnection.
361*0a66de84SNuno Antunes * We must check all hooks, since they may reference this one.
362*0a66de84SNuno Antunes */
363*0a66de84SNuno Antunes static int
ng_tcpmss_disconnect(hook_p hook)364*0a66de84SNuno Antunes ng_tcpmss_disconnect(hook_p hook)
365*0a66de84SNuno Antunes {
366*0a66de84SNuno Antunes node_p node = NG_HOOK_NODE(hook);
367*0a66de84SNuno Antunes hook_p hook2;
368*0a66de84SNuno Antunes
369*0a66de84SNuno Antunes LIST_FOREACH(hook2, &node->nd_hooks, hk_hooks) {
370*0a66de84SNuno Antunes hpriv_p priv = NG_HOOK_PRIVATE(hook2);
371*0a66de84SNuno Antunes
372*0a66de84SNuno Antunes if (priv->outHook == hook)
373*0a66de84SNuno Antunes priv->outHook = NULL;
374*0a66de84SNuno Antunes }
375*0a66de84SNuno Antunes
376*0a66de84SNuno Antunes kfree(NG_HOOK_PRIVATE(hook), M_NETGRAPH);
377*0a66de84SNuno Antunes
378*0a66de84SNuno Antunes if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
379*0a66de84SNuno Antunes ng_rmnode_self(NG_HOOK_NODE(hook));
380*0a66de84SNuno Antunes
381*0a66de84SNuno Antunes return (0);
382*0a66de84SNuno Antunes }
383*0a66de84SNuno Antunes
384*0a66de84SNuno Antunes /*
385*0a66de84SNuno Antunes * Code from tcpmssd.
386*0a66de84SNuno Antunes */
387*0a66de84SNuno Antunes
388*0a66de84SNuno Antunes /*-
389*0a66de84SNuno Antunes * The following macro is used to update an
390*0a66de84SNuno Antunes * internet checksum. "acc" is a 32-bit
391*0a66de84SNuno Antunes * accumulation of all the changes to the
392*0a66de84SNuno Antunes * checksum (adding in old 16-bit words and
393*0a66de84SNuno Antunes * subtracting out new words), and "cksum"
394*0a66de84SNuno Antunes * is the checksum value to be updated.
395*0a66de84SNuno Antunes */
396*0a66de84SNuno Antunes #define TCPMSS_ADJUST_CHECKSUM(acc, cksum) do { \
397*0a66de84SNuno Antunes acc += cksum; \
398*0a66de84SNuno Antunes if (acc < 0) { \
399*0a66de84SNuno Antunes acc = -acc; \
400*0a66de84SNuno Antunes acc = (acc >> 16) + (acc & 0xffff); \
401*0a66de84SNuno Antunes acc += acc >> 16; \
402*0a66de84SNuno Antunes cksum = (u_short) ~acc; \
403*0a66de84SNuno Antunes } else { \
404*0a66de84SNuno Antunes acc = (acc >> 16) + (acc & 0xffff); \
405*0a66de84SNuno Antunes acc += acc >> 16; \
406*0a66de84SNuno Antunes cksum = (u_short) acc; \
407*0a66de84SNuno Antunes } \
408*0a66de84SNuno Antunes } while (0);
409*0a66de84SNuno Antunes
410*0a66de84SNuno Antunes static int
correct_mss(struct tcphdr * tc,int hlen,uint16_t maxmss,int flags)411*0a66de84SNuno Antunes correct_mss(struct tcphdr *tc, int hlen, uint16_t maxmss, int flags)
412*0a66de84SNuno Antunes {
413*0a66de84SNuno Antunes int olen, optlen;
414*0a66de84SNuno Antunes u_char *opt;
415*0a66de84SNuno Antunes uint16_t *mss;
416*0a66de84SNuno Antunes int accumulate;
417*0a66de84SNuno Antunes int res = 0;
418*0a66de84SNuno Antunes
419*0a66de84SNuno Antunes for (olen = hlen - sizeof(struct tcphdr), opt = (u_char *)(tc + 1);
420*0a66de84SNuno Antunes olen > 0; olen -= optlen, opt += optlen) {
421*0a66de84SNuno Antunes if (*opt == TCPOPT_EOL)
422*0a66de84SNuno Antunes break;
423*0a66de84SNuno Antunes else if (*opt == TCPOPT_NOP)
424*0a66de84SNuno Antunes optlen = 1;
425*0a66de84SNuno Antunes else {
426*0a66de84SNuno Antunes optlen = *(opt + 1);
427*0a66de84SNuno Antunes if (optlen <= 0 || optlen > olen)
428*0a66de84SNuno Antunes break;
429*0a66de84SNuno Antunes if (*opt == TCPOPT_MAXSEG) {
430*0a66de84SNuno Antunes if (optlen != TCPOLEN_MAXSEG)
431*0a66de84SNuno Antunes continue;
432*0a66de84SNuno Antunes mss = (uint16_t *)(opt + 2);
433*0a66de84SNuno Antunes if (ntohs(*mss) > maxmss) {
434*0a66de84SNuno Antunes accumulate = *mss;
435*0a66de84SNuno Antunes *mss = htons(maxmss);
436*0a66de84SNuno Antunes accumulate -= *mss;
437*0a66de84SNuno Antunes if ((flags & CSUM_TCP) == 0)
438*0a66de84SNuno Antunes TCPMSS_ADJUST_CHECKSUM(accumulate, tc->th_sum);
439*0a66de84SNuno Antunes res = 1;
440*0a66de84SNuno Antunes }
441*0a66de84SNuno Antunes }
442*0a66de84SNuno Antunes }
443*0a66de84SNuno Antunes }
444*0a66de84SNuno Antunes return (res);
445*0a66de84SNuno Antunes }
446