1ab25eeb5Syz /*
2ab25eeb5Syz  * Copyright (C) 2002-2003 by Darren Reed
3ab25eeb5Syz  *
4ab25eeb5Syz  * Simple PPTP transparent proxy for in-kernel use.  For use with the NAT
5ab25eeb5Syz  * code.
6ab25eeb5Syz  *
7ab25eeb5Syz  * $Id: ip_pptp_pxy.c,v 2.10.2.10 2005/07/15 21:56:52 darrenr Exp $
8ab25eeb5Syz  *
9*f4b3ec61Sdh  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
10ab25eeb5Syz  * Use is subject to license terms.
11ab25eeb5Syz  */
12ab25eeb5Syz 
13ab25eeb5Syz #pragma ident	"%Z%%M%	%I%	%E% SMI"
14ab25eeb5Syz 
15ab25eeb5Syz #define	IPF_PPTP_PROXY
16ab25eeb5Syz 
17*f4b3ec61Sdh typedef struct ifs_pptppxy {
18*f4b3ec61Sdh 	frentry_t	pptpfr;
19*f4b3ec61Sdh 	int		pptp_proxy_init;
20*f4b3ec61Sdh } ifs_pptppxy_t;
21*f4b3ec61Sdh 
22ab25eeb5Syz typedef	struct pptp_hdr {
23ab25eeb5Syz 	u_short	pptph_len;
24ab25eeb5Syz 	u_short	pptph_type;
25ab25eeb5Syz 	u_32_t	pptph_cookie;
26ab25eeb5Syz } pptp_hdr_t;
27ab25eeb5Syz 
28ab25eeb5Syz #define	PPTP_MSGTYPE_CTL	1
29ab25eeb5Syz #define	PPTP_MTCTL_STARTREQ	1
30ab25eeb5Syz #define	PPTP_MTCTL_STARTREP	2
31ab25eeb5Syz #define	PPTP_MTCTL_STOPREQ	3
32ab25eeb5Syz #define	PPTP_MTCTL_STOPREP	4
33ab25eeb5Syz #define	PPTP_MTCTL_ECHOREQ	5
34ab25eeb5Syz #define	PPTP_MTCTL_ECHOREP	6
35ab25eeb5Syz #define	PPTP_MTCTL_OUTREQ	7
36ab25eeb5Syz #define	PPTP_MTCTL_OUTREP	8
37ab25eeb5Syz #define	PPTP_MTCTL_INREQ	9
38ab25eeb5Syz #define	PPTP_MTCTL_INREP	10
39ab25eeb5Syz #define	PPTP_MTCTL_INCONNECT	11
40ab25eeb5Syz #define	PPTP_MTCTL_CLEAR	12
41ab25eeb5Syz #define	PPTP_MTCTL_DISCONNECT	13
42ab25eeb5Syz #define	PPTP_MTCTL_WANERROR	14
43ab25eeb5Syz #define	PPTP_MTCTL_LINKINFO	15
44ab25eeb5Syz 
45ab25eeb5Syz 
46*f4b3ec61Sdh int ippr_pptp_init __P((void **, ipf_stack_t *));
47*f4b3ec61Sdh void ippr_pptp_fini __P((void **, ipf_stack_t *));
48*f4b3ec61Sdh int ippr_pptp_new __P((fr_info_t *, ap_session_t *, nat_t *, void *));
49*f4b3ec61Sdh void ippr_pptp_del __P((ap_session_t *, void *, ipf_stack_t *));
50*f4b3ec61Sdh int ippr_pptp_inout __P((fr_info_t *, ap_session_t *, nat_t *, void *));
51*f4b3ec61Sdh void ippr_pptp_donatstate __P((fr_info_t *, nat_t *, pptp_pxy_t *, ifs_pptppxy_t *));
52*f4b3ec61Sdh int ippr_pptp_message __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *, ifs_pptppxy_t *));
53*f4b3ec61Sdh int ippr_pptp_nextmessage __P((fr_info_t *, nat_t *, pptp_pxy_t *, int, ifs_pptppxy_t *));
54*f4b3ec61Sdh int ippr_pptp_mctl __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *, ifs_pptppxy_t *));
55ab25eeb5Syz 
56*f4b3ec61Sdh int	ippr_pptp_debug = 0;			/* It never changes */
57*f4b3ec61Sdh int	ippr_pptp_gretimeout = IPF_TTLVAL(120);	/* 2 minutes, never changes */
58ab25eeb5Syz 
59ab25eeb5Syz /*
60ab25eeb5Syz  * PPTP application proxy initialization.
61ab25eeb5Syz  */
62*f4b3ec61Sdh /*ARGSUSED*/
63*f4b3ec61Sdh int ippr_pptp_init(private, ifs)
64*f4b3ec61Sdh void **private;
65*f4b3ec61Sdh ipf_stack_t *ifs;
66ab25eeb5Syz {
67*f4b3ec61Sdh 	ifs_pptppxy_t *ifspptp;
68*f4b3ec61Sdh 
69*f4b3ec61Sdh 	KMALLOC(ifspptp, ifs_pptppxy_t *);
70*f4b3ec61Sdh 	if (ifspptp == NULL)
71*f4b3ec61Sdh 		return -1;
72*f4b3ec61Sdh 
73*f4b3ec61Sdh 	bzero((char *)&ifspptp->pptpfr, sizeof(ifspptp->pptpfr));
74*f4b3ec61Sdh 	ifspptp->pptpfr.fr_ref = 1;
75*f4b3ec61Sdh 	ifspptp->pptpfr.fr_age[0] = ippr_pptp_gretimeout;
76*f4b3ec61Sdh 	ifspptp->pptpfr.fr_age[1] = ippr_pptp_gretimeout;
77*f4b3ec61Sdh 	ifspptp->pptpfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
78*f4b3ec61Sdh 	MUTEX_INIT(&ifspptp->pptpfr.fr_lock, "PPTP proxy rule lock");
79*f4b3ec61Sdh 	ifspptp->pptp_proxy_init = 1;
80*f4b3ec61Sdh 
81*f4b3ec61Sdh 	*private = (void *)ifspptp;
82ab25eeb5Syz 
83ab25eeb5Syz 	return 0;
84ab25eeb5Syz }
85ab25eeb5Syz 
86ab25eeb5Syz 
87*f4b3ec61Sdh /*ARGSUSED*/
88*f4b3ec61Sdh void ippr_pptp_fini(private, ifs)
89*f4b3ec61Sdh void **private;
90*f4b3ec61Sdh ipf_stack_t *ifs;
91ab25eeb5Syz {
92*f4b3ec61Sdh 	ifs_pptppxy_t *ifspptp = *((ifs_pptppxy_t **)private);
93*f4b3ec61Sdh 
94*f4b3ec61Sdh 	if (ifspptp->pptp_proxy_init == 1) {
95*f4b3ec61Sdh 		MUTEX_DESTROY(&ifspptp->pptpfr.fr_lock);
96*f4b3ec61Sdh 		ifspptp->pptp_proxy_init = 0;
97ab25eeb5Syz 	}
98*f4b3ec61Sdh 
99*f4b3ec61Sdh 	KFREE(ifspptp);
100*f4b3ec61Sdh 	*private = NULL;
101ab25eeb5Syz }
102ab25eeb5Syz 
103ab25eeb5Syz 
104ab25eeb5Syz /*
105ab25eeb5Syz  * Setup for a new PPTP proxy.
106ab25eeb5Syz  */
107*f4b3ec61Sdh /*ARGSUSED*/
108*f4b3ec61Sdh int ippr_pptp_new(fin, aps, nat, private)
109ab25eeb5Syz fr_info_t *fin;
110ab25eeb5Syz ap_session_t *aps;
111ab25eeb5Syz nat_t *nat;
112*f4b3ec61Sdh void *private;
113ab25eeb5Syz {
114ab25eeb5Syz 	pptp_pxy_t *pptp;
115ab25eeb5Syz 	ipnat_t *ipn;
116ab25eeb5Syz 	ip_t *ip;
117ab25eeb5Syz 
118ab25eeb5Syz 	ip = fin->fin_ip;
119ab25eeb5Syz 
120ab25eeb5Syz 	if (nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_inip,
121ab25eeb5Syz 			  ip->ip_dst) != NULL) {
122ab25eeb5Syz 		if (ippr_pptp_debug > 0)
123ab25eeb5Syz 			printf("ippr_pptp_new: GRE session already exists\n");
124ab25eeb5Syz 		return -1;
125ab25eeb5Syz 	}
126ab25eeb5Syz 
127ab25eeb5Syz 	aps->aps_psiz = sizeof(*pptp);
128ab25eeb5Syz 	KMALLOCS(aps->aps_data, pptp_pxy_t *, sizeof(*pptp));
129ab25eeb5Syz 	if (aps->aps_data == NULL) {
130ab25eeb5Syz 		if (ippr_pptp_debug > 0)
131ab25eeb5Syz 			printf("ippr_pptp_new: malloc for aps_data failed\n");
132ab25eeb5Syz 		return -1;
133ab25eeb5Syz 	}
134ab25eeb5Syz 
135ab25eeb5Syz 	/*
136ab25eeb5Syz 	 * Create NAT rule against which the tunnel/transport mapping is
137ab25eeb5Syz 	 * created.  This is required because the current NAT rule does not
138ab25eeb5Syz 	 * describe GRE but TCP instead.
139ab25eeb5Syz 	 */
140ab25eeb5Syz 	pptp = aps->aps_data;
141ab25eeb5Syz 	bzero((char *)pptp, sizeof(*pptp));
142ab25eeb5Syz 	ipn = &pptp->pptp_rule;
143ab25eeb5Syz 	ipn->in_ifps[0] = fin->fin_ifp;
144ab25eeb5Syz 	ipn->in_apr = NULL;
145ab25eeb5Syz 	ipn->in_use = 1;
146ab25eeb5Syz 	ipn->in_hits = 1;
147ab25eeb5Syz 	ipn->in_ippip = 1;
148ab25eeb5Syz 	if (nat->nat_dir == NAT_OUTBOUND) {
149ab25eeb5Syz 		ipn->in_nip = ntohl(nat->nat_outip.s_addr);
150ab25eeb5Syz 		ipn->in_outip = fin->fin_saddr;
151ab25eeb5Syz 		ipn->in_redir = NAT_MAP;
152ab25eeb5Syz 	} else if (nat->nat_dir == NAT_INBOUND) {
153ab25eeb5Syz 		ipn->in_nip = 0;
154ab25eeb5Syz 		ipn->in_outip = nat->nat_outip.s_addr;
155ab25eeb5Syz 		ipn->in_redir = NAT_REDIRECT;
156ab25eeb5Syz 	}
157ab25eeb5Syz 	ipn->in_inip = nat->nat_inip.s_addr;
158ab25eeb5Syz 	ipn->in_inmsk = 0xffffffff;
159ab25eeb5Syz 	ipn->in_outmsk = 0xffffffff;
160ab25eeb5Syz 	ipn->in_srcip = fin->fin_saddr;
161ab25eeb5Syz 	ipn->in_srcmsk = 0xffffffff;
162ab25eeb5Syz 	bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0],
163ab25eeb5Syz 	      sizeof(ipn->in_ifnames[0]));
164ab25eeb5Syz 	ipn->in_p = IPPROTO_GRE;
165ab25eeb5Syz 
166ab25eeb5Syz 	pptp->pptp_side[0].pptps_wptr = pptp->pptp_side[0].pptps_buffer;
167ab25eeb5Syz 	pptp->pptp_side[1].pptps_wptr = pptp->pptp_side[1].pptps_buffer;
168ab25eeb5Syz 	return 0;
169ab25eeb5Syz }
170ab25eeb5Syz 
171ab25eeb5Syz 
172*f4b3ec61Sdh void ippr_pptp_donatstate(fin, nat, pptp, ifspptp)
173ab25eeb5Syz fr_info_t *fin;
174ab25eeb5Syz nat_t *nat;
175ab25eeb5Syz pptp_pxy_t *pptp;
176*f4b3ec61Sdh ifs_pptppxy_t *ifspptp;
177ab25eeb5Syz {
178ab25eeb5Syz 	fr_info_t fi;
179ab25eeb5Syz 	grehdr_t gre;
180ab25eeb5Syz 	nat_t *nat2;
181ab25eeb5Syz 	u_char p;
182ab25eeb5Syz 	ip_t *ip;
183*f4b3ec61Sdh 	ipf_stack_t *ifs = fin->fin_ifs;
184ab25eeb5Syz 
185ab25eeb5Syz 	ip = fin->fin_ip;
186ab25eeb5Syz 	p = ip->ip_p;
187ab25eeb5Syz 
188ab25eeb5Syz 	nat2 = pptp->pptp_nat;
189ab25eeb5Syz 	if ((nat2 == NULL) || (pptp->pptp_state == NULL)) {
190ab25eeb5Syz 		bcopy((char *)fin, (char *)&fi, sizeof(fi));
191ab25eeb5Syz 		bzero((char *)&gre, sizeof(gre));
192ab25eeb5Syz 		fi.fin_state = NULL;
193ab25eeb5Syz 		fi.fin_nat = NULL;
194ab25eeb5Syz 		fi.fin_fi.fi_p = IPPROTO_GRE;
195*f4b3ec61Sdh 		fi.fin_fr = &ifspptp->pptpfr;
196ab25eeb5Syz 		if ((nat->nat_dir == NAT_OUTBOUND && fin->fin_out) ||
197ab25eeb5Syz 		    (nat->nat_dir == NAT_INBOUND && !fin->fin_out)) {
198ab25eeb5Syz 			fi.fin_data[0] = pptp->pptp_call[0];
199ab25eeb5Syz 			fi.fin_data[1] = pptp->pptp_call[1];
200ab25eeb5Syz 		} else {
201ab25eeb5Syz 			fi.fin_data[0] = pptp->pptp_call[1];
202ab25eeb5Syz 			fi.fin_data[1] = pptp->pptp_call[0];
203ab25eeb5Syz 		}
204ab25eeb5Syz 		ip = fin->fin_ip;
205ab25eeb5Syz 		ip->ip_p = IPPROTO_GRE;
206ab25eeb5Syz 		fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
207ab25eeb5Syz 		fi.fin_flx |= FI_IGNORE;
208ab25eeb5Syz 		fi.fin_dp = &gre;
209ab25eeb5Syz 		gre.gr_flags = htons(1 << 13);
210ab25eeb5Syz 		if (fin->fin_out && nat->nat_dir == NAT_INBOUND) {
211ab25eeb5Syz 			fi.fin_fi.fi_saddr = fin->fin_fi.fi_daddr;
212ab25eeb5Syz 			fi.fin_fi.fi_daddr = nat->nat_outip.s_addr;
213ab25eeb5Syz 		} else if (!fin->fin_out && nat->nat_dir == NAT_OUTBOUND) {
214ab25eeb5Syz 			fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
215ab25eeb5Syz 			fi.fin_fi.fi_daddr = fin->fin_fi.fi_saddr;
216ab25eeb5Syz 		}
217ab25eeb5Syz 	}
218ab25eeb5Syz 
219ab25eeb5Syz 	/*
220ab25eeb5Syz 	 * Update NAT timeout/create NAT if missing.
221ab25eeb5Syz 	 */
222ab25eeb5Syz 	if (nat2 != NULL)
223*f4b3ec61Sdh 		fr_queueback(&nat2->nat_tqe, ifs);
224ab25eeb5Syz 	else {
225ab25eeb5Syz 		nat2 = nat_new(&fi, &pptp->pptp_rule, &pptp->pptp_nat,
226ab25eeb5Syz 			       NAT_SLAVE, nat->nat_dir);
227ab25eeb5Syz 		pptp->pptp_nat = nat2;
228ab25eeb5Syz 		if (nat2 != NULL) {
229ab25eeb5Syz 			(void) nat_proto(&fi, nat2, 0);
230ab25eeb5Syz 			nat_update(&fi, nat2, nat2->nat_ptr);
231ab25eeb5Syz 		}
232ab25eeb5Syz 	}
233ab25eeb5Syz 
234*f4b3ec61Sdh 	READ_ENTER(&ifs->ifs_ipf_state);
235ab25eeb5Syz 	if (pptp->pptp_state != NULL) {
236*f4b3ec61Sdh 		fr_queueback(&pptp->pptp_state->is_sti, ifs);
237*f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_state);
238ab25eeb5Syz 	} else {
239*f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_state);
240ab25eeb5Syz 		if (nat->nat_dir == NAT_INBOUND)
241ab25eeb5Syz 			fi.fin_fi.fi_daddr = nat2->nat_inip.s_addr;
242ab25eeb5Syz 		else
243ab25eeb5Syz 			fi.fin_fi.fi_saddr = nat2->nat_inip.s_addr;
244ab25eeb5Syz 		fi.fin_ifp = NULL;
245ab25eeb5Syz 		pptp->pptp_state = fr_addstate(&fi, &pptp->pptp_state,
246ab25eeb5Syz 					       0);
247ab25eeb5Syz 		if (fi.fin_state != NULL)
248*f4b3ec61Sdh 			fr_statederef(&fi, (ipstate_t **)&fi.fin_state, ifs);
249ab25eeb5Syz 	}
250ab25eeb5Syz 	ip->ip_p = p;
251ab25eeb5Syz 	return;
252ab25eeb5Syz }
253ab25eeb5Syz 
254ab25eeb5Syz 
255ab25eeb5Syz /*
256ab25eeb5Syz  * Try and build up the next PPTP message in the TCP stream and if we can
257ab25eeb5Syz  * build it up completely (fits in our buffer) then pass it off to the message
258ab25eeb5Syz  * parsing function.
259ab25eeb5Syz  */
260*f4b3ec61Sdh int ippr_pptp_nextmessage(fin, nat, pptp, rev, ifspptp)
261ab25eeb5Syz fr_info_t *fin;
262ab25eeb5Syz nat_t *nat;
263ab25eeb5Syz pptp_pxy_t *pptp;
264ab25eeb5Syz int rev;
265*f4b3ec61Sdh ifs_pptppxy_t *ifspptp;
266ab25eeb5Syz {
267ab25eeb5Syz 	static char *funcname = "ippr_pptp_nextmessage";
268ab25eeb5Syz 	pptp_side_t *pptps;
269ab25eeb5Syz 	u_32_t start, end;
270ab25eeb5Syz 	pptp_hdr_t *hdr;
271ab25eeb5Syz 	tcphdr_t *tcp;
272ab25eeb5Syz 	int dlen, off;
273ab25eeb5Syz 	u_short len;
274ab25eeb5Syz 	char *msg;
275ab25eeb5Syz 
276ab25eeb5Syz 	tcp = fin->fin_dp;
277ab25eeb5Syz 	dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
278ab25eeb5Syz 	start = ntohl(tcp->th_seq);
279ab25eeb5Syz 	pptps = &pptp->pptp_side[rev];
280ab25eeb5Syz 	off = (char *)tcp - (char *)fin->fin_ip + (TCP_OFF(tcp) << 2) +
281ab25eeb5Syz 	      fin->fin_ipoff;
282ab25eeb5Syz 
283ab25eeb5Syz 	if (dlen <= 0)
284ab25eeb5Syz 		return 0;
285ab25eeb5Syz 	/*
286ab25eeb5Syz 	 * If the complete data packet is before what we expect to see
287ab25eeb5Syz 	 * "next", just ignore it as the chances are we've already seen it.
288ab25eeb5Syz 	 * The next if statement following this one really just causes packets
289ab25eeb5Syz 	 * ahead of what we've seen to be dropped, implying that something in
290ab25eeb5Syz 	 * the middle went missing and we want to see that first.
291ab25eeb5Syz 	 */
292ab25eeb5Syz 	end = start + dlen;
293ab25eeb5Syz 	if (pptps->pptps_next > end && pptps->pptps_next > start)
294ab25eeb5Syz 		return 0;
295ab25eeb5Syz 
296ab25eeb5Syz 	if (pptps->pptps_next != start) {
297ab25eeb5Syz 		if (ippr_pptp_debug > 5)
298ab25eeb5Syz 			printf("%s: next (%x) != start (%x)\n", funcname,
299ab25eeb5Syz 				pptps->pptps_next, start);
300ab25eeb5Syz 		return -1;
301ab25eeb5Syz 	}
302ab25eeb5Syz 
303ab25eeb5Syz 	msg = (char *)fin->fin_dp + (TCP_OFF(tcp) << 2);
304ab25eeb5Syz 
305ab25eeb5Syz 	while (dlen > 0) {
306ab25eeb5Syz 		off += pptps->pptps_bytes;
307ab25eeb5Syz 		if (pptps->pptps_gothdr == 0) {
308ab25eeb5Syz 			/*
309ab25eeb5Syz 			 * PPTP has an 8 byte header that inclues the cookie.
310ab25eeb5Syz 			 * The start of every message should include one and
311ab25eeb5Syz 			 * it should match 1a2b3c4d.  Byte order is ignored,
312ab25eeb5Syz 			 * deliberately, when printing out the error.
313ab25eeb5Syz 			 */
314ab25eeb5Syz 			len = MIN(8 - pptps->pptps_bytes, dlen);
315ab25eeb5Syz 			COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr);
316ab25eeb5Syz 			pptps->pptps_bytes += len;
317ab25eeb5Syz 			pptps->pptps_wptr += len;
318ab25eeb5Syz 			hdr = (pptp_hdr_t *)pptps->pptps_buffer;
319ab25eeb5Syz 			if (pptps->pptps_bytes == 8) {
320ab25eeb5Syz 				pptps->pptps_next += 8;
321ab25eeb5Syz 				if (ntohl(hdr->pptph_cookie) != 0x1a2b3c4d) {
322ab25eeb5Syz 					if (ippr_pptp_debug > 1)
323ab25eeb5Syz 						printf("%s: bad cookie (%x)\n",
324ab25eeb5Syz 						       funcname,
325ab25eeb5Syz 						       hdr->pptph_cookie);
326ab25eeb5Syz 					return -1;
327ab25eeb5Syz 				}
328ab25eeb5Syz 			}
329ab25eeb5Syz 			dlen -= len;
330ab25eeb5Syz 			msg += len;
331ab25eeb5Syz 			off += len;
332ab25eeb5Syz 
333ab25eeb5Syz 			pptps->pptps_gothdr = 1;
334ab25eeb5Syz 			len = ntohs(hdr->pptph_len);
335ab25eeb5Syz 			pptps->pptps_len = len;
336ab25eeb5Syz 			pptps->pptps_nexthdr += len;
337ab25eeb5Syz 
338ab25eeb5Syz 			/*
339ab25eeb5Syz 			 * If a message is too big for the buffer, just set
340ab25eeb5Syz 			 * the fields for the next message to come along.
341ab25eeb5Syz 			 * The messages defined in RFC 2637 will not exceed
342ab25eeb5Syz 			 * 512 bytes (in total length) so this is likely a
343ab25eeb5Syz 			 * bad data packet, anyway.
344ab25eeb5Syz 			 */
345ab25eeb5Syz 			if (len > sizeof(pptps->pptps_buffer)) {
346ab25eeb5Syz 				if (ippr_pptp_debug > 3)
347ab25eeb5Syz 					printf("%s: message too big (%d)\n",
348ab25eeb5Syz 					       funcname, len);
349ab25eeb5Syz 				pptps->pptps_next = pptps->pptps_nexthdr;
350ab25eeb5Syz 				pptps->pptps_wptr = pptps->pptps_buffer;
351ab25eeb5Syz 				pptps->pptps_gothdr = 0;
352ab25eeb5Syz 				pptps->pptps_bytes = 0;
353ab25eeb5Syz 				pptps->pptps_len = 0;
354ab25eeb5Syz 				break;
355ab25eeb5Syz 			}
356ab25eeb5Syz 		}
357ab25eeb5Syz 
358ab25eeb5Syz 		len = MIN(pptps->pptps_len - pptps->pptps_bytes, dlen);
359ab25eeb5Syz 		COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr);
360ab25eeb5Syz 		pptps->pptps_bytes += len;
361ab25eeb5Syz 		pptps->pptps_wptr += len;
362ab25eeb5Syz 		pptps->pptps_next += len;
363ab25eeb5Syz 
364ab25eeb5Syz 		if (pptps->pptps_len > pptps->pptps_bytes)
365ab25eeb5Syz 			break;
366ab25eeb5Syz 
367*f4b3ec61Sdh 		(void) ippr_pptp_message(fin, nat, pptp, pptps, ifspptp);
368ab25eeb5Syz 		pptps->pptps_wptr = pptps->pptps_buffer;
369ab25eeb5Syz 		pptps->pptps_gothdr = 0;
370ab25eeb5Syz 		pptps->pptps_bytes = 0;
371ab25eeb5Syz 		pptps->pptps_len = 0;
372ab25eeb5Syz 
373ab25eeb5Syz 		start += len;
374ab25eeb5Syz 		msg += len;
375ab25eeb5Syz 		dlen -= len;
376ab25eeb5Syz 	}
377ab25eeb5Syz 
378ab25eeb5Syz 	return 0;
379ab25eeb5Syz }
380ab25eeb5Syz 
381ab25eeb5Syz 
382ab25eeb5Syz /*
383ab25eeb5Syz  * handle a complete PPTP message
384ab25eeb5Syz  */
385*f4b3ec61Sdh int ippr_pptp_message(fin, nat, pptp, pptps, ifspptp)
386ab25eeb5Syz fr_info_t *fin;
387ab25eeb5Syz nat_t *nat;
388ab25eeb5Syz pptp_pxy_t *pptp;
389ab25eeb5Syz pptp_side_t *pptps;
390*f4b3ec61Sdh ifs_pptppxy_t *ifspptp;
391ab25eeb5Syz {
392ab25eeb5Syz 	pptp_hdr_t *hdr = (pptp_hdr_t *)pptps->pptps_buffer;
393ab25eeb5Syz 
394ab25eeb5Syz 	switch (ntohs(hdr->pptph_type))
395ab25eeb5Syz 	{
396ab25eeb5Syz 	case PPTP_MSGTYPE_CTL :
397*f4b3ec61Sdh 		(void) ippr_pptp_mctl(fin, nat, pptp, pptps, ifspptp);
398ab25eeb5Syz 		break;
399ab25eeb5Syz 
400ab25eeb5Syz 	default :
401ab25eeb5Syz 		break;
402ab25eeb5Syz 	}
403ab25eeb5Syz 	return 0;
404ab25eeb5Syz }
405ab25eeb5Syz 
406ab25eeb5Syz 
407ab25eeb5Syz /*
408ab25eeb5Syz  * handle a complete PPTP control message
409ab25eeb5Syz  */
410*f4b3ec61Sdh int ippr_pptp_mctl(fin, nat, pptp, pptps, ifspptp)
411ab25eeb5Syz fr_info_t *fin;
412ab25eeb5Syz nat_t *nat;
413ab25eeb5Syz pptp_pxy_t *pptp;
414ab25eeb5Syz pptp_side_t *pptps;
415*f4b3ec61Sdh ifs_pptppxy_t *ifspptp;
416ab25eeb5Syz {
417ab25eeb5Syz 	u_short *buffer = (u_short *)(pptps->pptps_buffer);
418ab25eeb5Syz 	pptp_side_t *pptpo;
419ab25eeb5Syz 
420ab25eeb5Syz 	if (pptps == &pptp->pptp_side[0])
421ab25eeb5Syz 		pptpo = &pptp->pptp_side[1];
422ab25eeb5Syz 	else
423ab25eeb5Syz 		pptpo = &pptp->pptp_side[0];
424ab25eeb5Syz 
425ab25eeb5Syz 	/*
426ab25eeb5Syz 	 * Breakout to handle all the various messages.  Most are just state
427ab25eeb5Syz 	 * transition.
428ab25eeb5Syz 	 */
429ab25eeb5Syz 	switch (ntohs(buffer[4]))
430ab25eeb5Syz 	{
431ab25eeb5Syz 	case PPTP_MTCTL_STARTREQ :
432ab25eeb5Syz 		pptps->pptps_state = PPTP_MTCTL_STARTREQ;
433ab25eeb5Syz 		break;
434ab25eeb5Syz 	case PPTP_MTCTL_STARTREP :
435ab25eeb5Syz 		if (pptpo->pptps_state == PPTP_MTCTL_STARTREQ)
436ab25eeb5Syz 			pptps->pptps_state = PPTP_MTCTL_STARTREP;
437ab25eeb5Syz 		break;
438ab25eeb5Syz 	case PPTP_MTCTL_STOPREQ :
439ab25eeb5Syz 		pptps->pptps_state = PPTP_MTCTL_STOPREQ;
440ab25eeb5Syz 		break;
441ab25eeb5Syz 	case PPTP_MTCTL_STOPREP :
442ab25eeb5Syz 		if (pptpo->pptps_state == PPTP_MTCTL_STOPREQ)
443ab25eeb5Syz 			pptps->pptps_state = PPTP_MTCTL_STOPREP;
444ab25eeb5Syz 		break;
445ab25eeb5Syz 	case PPTP_MTCTL_ECHOREQ :
446ab25eeb5Syz 		pptps->pptps_state = PPTP_MTCTL_ECHOREQ;
447ab25eeb5Syz 		break;
448ab25eeb5Syz 	case PPTP_MTCTL_ECHOREP :
449ab25eeb5Syz 		if (pptpo->pptps_state == PPTP_MTCTL_ECHOREQ)
450ab25eeb5Syz 			pptps->pptps_state = PPTP_MTCTL_ECHOREP;
451ab25eeb5Syz 		break;
452ab25eeb5Syz 	case PPTP_MTCTL_OUTREQ :
453ab25eeb5Syz 		pptps->pptps_state = PPTP_MTCTL_OUTREQ;
454ab25eeb5Syz 		break;
455ab25eeb5Syz 	case PPTP_MTCTL_OUTREP :
456ab25eeb5Syz 		if (pptpo->pptps_state == PPTP_MTCTL_OUTREQ) {
457ab25eeb5Syz 			pptps->pptps_state = PPTP_MTCTL_OUTREP;
458ab25eeb5Syz 			pptp->pptp_call[0] = buffer[7];
459ab25eeb5Syz 			pptp->pptp_call[1] = buffer[6];
460*f4b3ec61Sdh 			ippr_pptp_donatstate(fin, nat, pptp, ifspptp);
461ab25eeb5Syz 		}
462ab25eeb5Syz 		break;
463ab25eeb5Syz 	case PPTP_MTCTL_INREQ :
464ab25eeb5Syz 		pptps->pptps_state = PPTP_MTCTL_INREQ;
465ab25eeb5Syz 		break;
466ab25eeb5Syz 	case PPTP_MTCTL_INREP :
467ab25eeb5Syz 		if (pptpo->pptps_state == PPTP_MTCTL_INREQ) {
468ab25eeb5Syz 			pptps->pptps_state = PPTP_MTCTL_INREP;
469ab25eeb5Syz 			pptp->pptp_call[0] = buffer[7];
470ab25eeb5Syz 			pptp->pptp_call[1] = buffer[6];
471*f4b3ec61Sdh 			ippr_pptp_donatstate(fin, nat, pptp, ifspptp);
472ab25eeb5Syz 		}
473ab25eeb5Syz 		break;
474ab25eeb5Syz 	case PPTP_MTCTL_INCONNECT :
475ab25eeb5Syz 		pptps->pptps_state = PPTP_MTCTL_INCONNECT;
476ab25eeb5Syz 		break;
477ab25eeb5Syz 	case PPTP_MTCTL_CLEAR :
478ab25eeb5Syz 		pptps->pptps_state = PPTP_MTCTL_CLEAR;
479ab25eeb5Syz 		break;
480ab25eeb5Syz 	case PPTP_MTCTL_DISCONNECT :
481ab25eeb5Syz 		pptps->pptps_state = PPTP_MTCTL_DISCONNECT;
482ab25eeb5Syz 		break;
483ab25eeb5Syz 	case PPTP_MTCTL_WANERROR :
484ab25eeb5Syz 		pptps->pptps_state = PPTP_MTCTL_WANERROR;
485ab25eeb5Syz 		break;
486ab25eeb5Syz 	case PPTP_MTCTL_LINKINFO :
487ab25eeb5Syz 		pptps->pptps_state = PPTP_MTCTL_LINKINFO;
488ab25eeb5Syz 		break;
489ab25eeb5Syz 	}
490ab25eeb5Syz 
491ab25eeb5Syz 	return 0;
492ab25eeb5Syz }
493ab25eeb5Syz 
494ab25eeb5Syz 
495ab25eeb5Syz /*
496ab25eeb5Syz  * For outgoing PPTP packets.  refresh timeouts for NAT & state entries, if
497ab25eeb5Syz  * we can.  If they have disappeared, recreate them.
498ab25eeb5Syz  */
499*f4b3ec61Sdh int ippr_pptp_inout(fin, aps, nat, private)
500ab25eeb5Syz fr_info_t *fin;
501ab25eeb5Syz ap_session_t *aps;
502ab25eeb5Syz nat_t *nat;
503*f4b3ec61Sdh void *private;
504ab25eeb5Syz {
505ab25eeb5Syz 	pptp_pxy_t *pptp;
506ab25eeb5Syz 	tcphdr_t *tcp;
507ab25eeb5Syz 	int rev;
508ab25eeb5Syz 
509ab25eeb5Syz 	if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND))
510ab25eeb5Syz 		rev = 1;
511ab25eeb5Syz 	else if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND))
512ab25eeb5Syz 		rev = 1;
513ab25eeb5Syz 	else
514ab25eeb5Syz 		rev = 0;
515ab25eeb5Syz 
516ab25eeb5Syz 	tcp = (tcphdr_t *)fin->fin_dp;
517ab25eeb5Syz 	if ((tcp->th_flags & TH_OPENING) == TH_OPENING) {
518ab25eeb5Syz 		pptp = (pptp_pxy_t *)aps->aps_data;
519ab25eeb5Syz 		pptp->pptp_side[1 - rev].pptps_next = ntohl(tcp->th_ack);
520ab25eeb5Syz 		pptp->pptp_side[1 - rev].pptps_nexthdr = ntohl(tcp->th_ack);
521ab25eeb5Syz 		pptp->pptp_side[rev].pptps_next = ntohl(tcp->th_seq) + 1;
522ab25eeb5Syz 		pptp->pptp_side[rev].pptps_nexthdr = ntohl(tcp->th_seq) + 1;
523ab25eeb5Syz 	}
524ab25eeb5Syz 	return ippr_pptp_nextmessage(fin, nat, (pptp_pxy_t *)aps->aps_data,
525*f4b3ec61Sdh 				     rev, (ifs_pptppxy_t *)private);
526ab25eeb5Syz }
527ab25eeb5Syz 
528ab25eeb5Syz 
529ab25eeb5Syz /*
530ab25eeb5Syz  * clean up after ourselves.
531ab25eeb5Syz  */
532*f4b3ec61Sdh /*ARGSUSED*/
533*f4b3ec61Sdh void ippr_pptp_del(aps, private, ifs)
534ab25eeb5Syz ap_session_t *aps;
535*f4b3ec61Sdh void *private;
536*f4b3ec61Sdh ipf_stack_t *ifs;
537ab25eeb5Syz {
538ab25eeb5Syz 	pptp_pxy_t *pptp;
539ab25eeb5Syz 
540ab25eeb5Syz 	pptp = aps->aps_data;
541ab25eeb5Syz 
542ab25eeb5Syz 	if (pptp != NULL) {
543ab25eeb5Syz 		/*
544ab25eeb5Syz 		 * Don't bother changing any of the NAT structure details,
545ab25eeb5Syz 		 * *_del() is on a callback from aps_free(), from nat_delete()
546ab25eeb5Syz 		 */
547ab25eeb5Syz 
548*f4b3ec61Sdh 		READ_ENTER(&ifs->ifs_ipf_state);
549ab25eeb5Syz 		if (pptp->pptp_state != NULL) {
550*f4b3ec61Sdh 			pptp->pptp_state->is_die = ifs->ifs_fr_ticks + 1;
551ab25eeb5Syz 			pptp->pptp_state->is_me = NULL;
552ab25eeb5Syz 			fr_queuefront(&pptp->pptp_state->is_sti);
553ab25eeb5Syz 		}
554*f4b3ec61Sdh 		RWLOCK_EXIT(&ifs->ifs_ipf_state);
555ab25eeb5Syz 
556ab25eeb5Syz 		pptp->pptp_state = NULL;
557ab25eeb5Syz 		pptp->pptp_nat = NULL;
558*f4b3ec61Sdh 
559ab25eeb5Syz 	}
560ab25eeb5Syz }
561