1/***********************************************************************
2*
3* session.c
4*
5* Code for managing L2TP sessions
6*
7* Copyright (C) 2001 by Roaring Penguin Software Inc.
8*
9* This software may be distributed under the terms of the GNU General
10* Public License, Version 2, or (at your option) any later version.
11*
12* LIC: GPL
13*
14***********************************************************************/
15
16static char const RCSID[] =
17"$Id: session.c,v 1.1.1.1 2008/10/15 03:31:00 james26_jang Exp $";
18
19#include "l2tp.h"
20#include <stddef.h>
21#include <string.h>
22#include <stdarg.h>
23#include <stdio.h>
24
25static uint16_t session_make_sid(l2tp_tunnel *tunnel);
26static void session_set_state(l2tp_session *session, int state);
27static void session_send_sli(l2tp_session *session);
28
29/* Registered LNS incoming-call handlers */
30static l2tp_lns_handler *lns_handlers = NULL;
31
32/* Registered LAC handlers */
33static l2tp_lac_handler *lac_handlers = NULL;
34
35static uint32_t call_serial_number = 0;
36
37static char *state_names[] = {
38    "idle", "wait-tunnel", "wait-reply", "wait-connect", "established"
39};
40
41/**********************************************************************
42* %FUNCTION: session_compute_hash
43* %ARGUMENTS:
44*  data -- a session
45* %RETURNS:
46*  The session ID
47* %DESCRIPTION:
48*  Returns a hash value for a session
49***********************************************************************/
50static unsigned int
51session_compute_hash(void *data)
52{
53    return (unsigned int) ((l2tp_session *) data)->my_id;
54}
55
56
57/**********************************************************************
58* %FUNCTION: session_compare
59* %ARGUMENTS:
60*  d1, d2 -- two sessions
61* %RETURNS:
62*  0 if sids are equal, non-zero otherwise
63* %DESCRIPTION:
64*  Compares two sessions
65***********************************************************************/
66static int
67session_compare(void *d1, void *d2)
68{
69    return ((l2tp_session *) d1)->my_id != ((l2tp_session *) d2)->my_id;
70}
71
72/**********************************************************************
73* %FUNCTION: session_hash_init
74* %ARGUMENTS:
75*  tab -- hash table
76* %RETURNS:
77*  Nothing
78* %DESCRIPTION:
79*  Initializes hash table of sessions
80***********************************************************************/
81void
82l2tp_session_hash_init(hash_table *tab)
83{
84    hash_init(tab, offsetof(l2tp_session, hash_by_my_id),
85	      session_compute_hash, session_compare);
86}
87
88/**********************************************************************
89* %FUNCTION: session_free
90* %ARGUMENTS:
91*  ses -- a session to free
92* %RETURNS:
93*  Nothing
94* %DESCRIPTION:
95*  Frees a session, closing down all resources associated with it.
96***********************************************************************/
97void
98l2tp_session_free(l2tp_session *ses, char const *reason, int may_reestablish)
99{
100    session_set_state(ses, SESSION_IDLE);
101    DBG(l2tp_db(DBG_SESSION, "session_free(%s) %s\n",
102	   l2tp_debug_session_to_str(ses), reason));
103    if (ses->call_ops && ses->call_ops->close) {
104	ses->call_ops->close(ses, reason, may_reestablish);
105    }
106    memset(ses, 0, sizeof(l2tp_session));
107    free(ses);
108}
109
110/**********************************************************************
111* %FUNCTION: session_call_lns
112* %ARGUMENTS:
113*  peer -- L2TP peer
114*  calling_number -- calling phone number (or MAC address or whatever...)
115*  private -- private data to be stored in session structure
116* %RETURNS:
117*  A newly-allocated session, or NULL if session could not be created
118* %DESCRIPTION:
119*  Initiates session setup.  Once call is active, established() will be
120*  called.
121***********************************************************************/
122l2tp_session *
123l2tp_session_call_lns(l2tp_peer *peer,
124		      char const *calling_number,
125		      EventSelector *es,
126		      void *private)
127{
128    l2tp_session *ses;
129    l2tp_tunnel *tunnel;
130
131    /* Find a tunnel to the peer */
132    tunnel = l2tp_tunnel_find_for_peer(peer, es);
133    if (!tunnel) return NULL;
134
135    /* Do we have call ops? */
136    if (!peer->lac_ops) {
137	l2tp_set_errmsg("Cannot act as LAC for peer");
138	return NULL;
139    }
140
141    /* Allocate session */
142    ses = malloc(sizeof(l2tp_session));
143    if (!ses) {
144	l2tp_set_errmsg("session_call_lns: out of memory");
145	return NULL;
146    }
147
148    /* Init fields */
149    memset(ses, 0, sizeof(l2tp_session));
150    ses->we_are_lac = 1;
151    ses->tunnel = tunnel;
152    ses->my_id = session_make_sid(tunnel);
153    ses->call_ops = peer->lac_ops;
154    ses->state = SESSION_WAIT_TUNNEL;
155    strncpy(ses->calling_number, calling_number, MAX_HOSTNAME);
156    ses->calling_number[MAX_HOSTNAME-1] = 0;
157    ses->private = private;
158    ses->snooping = 1;
159    ses->send_accm = 0xFFFFFFFF;
160    ses->recv_accm = 0xFFFFFFFF;
161
162    /* Add it to the tunnel */
163    l2tp_tunnel_add_session(ses);
164
165    return ses;
166}
167
168/**********************************************************************
169* %FUNCTION: session_make_sid
170* %ARGUMENTS:
171*  tunnel -- an L2TP tunnel
172* %RETURNS:
173*  An unused random session ID
174***********************************************************************/
175static uint16_t
176session_make_sid(l2tp_tunnel *tunnel)
177{
178    uint16_t sid;
179    while(1) {
180	L2TP_RANDOM_FILL(sid);
181	if (!sid) continue;
182	if (!l2tp_tunnel_find_session(tunnel, sid)) return sid;
183    }
184}
185
186/**********************************************************************
187* %FUNCTION: session_notify_open
188* %ARGUMENTS:
189*  ses -- an L2TP session
190* %RETURNS:
191*  Nothing
192* %DESCRIPTION:
193*  Called when tunnel has been established
194***********************************************************************/
195void
196l2tp_session_notify_tunnel_open(l2tp_session *ses)
197{
198    uint16_t u16;
199    uint32_t u32;
200    l2tp_dgram *dgram;
201    l2tp_tunnel *tunnel = ses->tunnel;
202
203    if (ses->state != SESSION_WAIT_TUNNEL) return;
204
205    /* Send ICRQ */
206    DBG(l2tp_db(DBG_SESSION, "Session %s tunnel open\n",
207	   l2tp_debug_session_to_str(ses)));
208
209    dgram = l2tp_dgram_new_control(MESSAGE_ICRQ, ses->tunnel->assigned_id,
210			      0);
211    if (!dgram) {
212	l2tp_set_errmsg("Could not establish session - out of memory");
213	l2tp_tunnel_delete_session(ses, "Out of memory", 0);
214	return;
215    }
216
217    /* assigned session ID */
218    u16 = htons(ses->my_id);
219    l2tp_dgram_add_avp(dgram, tunnel, MANDATORY,
220		  sizeof(u16), VENDOR_IETF, AVP_ASSIGNED_SESSION_ID, &u16);
221
222    /* Call serial number */
223    u32 = htonl(call_serial_number);
224    call_serial_number++;
225    l2tp_dgram_add_avp(dgram, tunnel, MANDATORY,
226		  sizeof(u32), VENDOR_IETF, AVP_CALL_SERIAL_NUMBER, &u32);
227
228    /* Ship it out */
229    l2tp_tunnel_xmit_control_message(tunnel, dgram);
230
231    session_set_state(ses, SESSION_WAIT_REPLY);
232}
233
234/**********************************************************************
235* %FUNCTION: session_set_state
236* %ARGUMENTS:
237*  session -- the session
238*  state -- new state
239* %RETURNS:
240*  Nothing
241***********************************************************************/
242static void
243session_set_state(l2tp_session *session, int state)
244{
245    if (state == session->state) return;
246    DBG(l2tp_db(DBG_SESSION, "session(%s) state %s -> %s\n",
247	   l2tp_debug_session_to_str(session),
248	   state_names[session->state],
249	   state_names[state]));
250    session->state = state;
251}
252
253/**********************************************************************
254* %FUNCTION: session_register_lns_handler
255* %ARGUMENTS:
256*  handler -- LNS handler
257* %RETURNS:
258*  -1 on error, 0 if all is OK
259* %DESCRIPTION:
260*  Registers an LNS handler for incoming call requests
261***********************************************************************/
262int
263l2tp_session_register_lns_handler(l2tp_lns_handler *handler)
264{
265    l2tp_lns_handler *prev = lns_handlers;
266
267    if (l2tp_session_find_lns_handler(handler->handler_name)) {
268	l2tp_set_errmsg("LNS Handler named %s already exists",
269		   handler->handler_name);
270	return -1;
271    }
272    /* Add to end of handler list */
273    handler->next = NULL;
274    if (!prev) {
275	lns_handlers = handler;
276	return 0;
277    }
278    while (prev->next) {
279	prev = prev->next;
280    }
281    prev->next = handler;
282    return 0;
283}
284
285/**********************************************************************
286* %FUNCTION: session_register_lac_handler
287* %ARGUMENTS:
288*  handler -- LAC handler
289* %RETURNS:
290*  -1 on error, 0 if all is OK
291* %DESCRIPTION:
292*  Registers an LAC handler for incoming call requests
293***********************************************************************/
294int
295l2tp_session_register_lac_handler(l2tp_lac_handler *handler)
296{
297    l2tp_lac_handler *prev = lac_handlers;
298
299    if (l2tp_session_find_lac_handler(handler->handler_name)) {
300	l2tp_set_errmsg("LAC Handler named %s already exists",
301		   handler->handler_name);
302	return -1;
303    }
304    /* Add to end of handler list */
305    handler->next = NULL;
306    if (!prev) {
307	lac_handlers = handler;
308	return 0;
309    }
310    while (prev->next) {
311	prev = prev->next;
312    }
313    prev->next = handler;
314    return 0;
315}
316
317/**********************************************************************
318* %FUNCTION: session_send_CDN
319* %ARGUMENTS:
320*  ses -- which session to terminate
321*  result_code -- result code
322*  error_code -- error code
323*  fmt -- printf-style format string for error message
324* %RETURNS:
325*  Nothing
326* %DESCRIPTION:
327*  Sends CDN with specified result code and message.
328***********************************************************************/
329void
330l2tp_session_send_CDN(l2tp_session *ses,
331		      int result_code,
332		      int error_code,
333		      char const *fmt, ...)
334{
335    char buf[256];
336    va_list ap;
337    l2tp_tunnel *tunnel = ses->tunnel;
338    uint16_t len;
339    l2tp_dgram *dgram;
340    uint16_t u16;
341
342    /* Build the buffer for the result-code AVP */
343    buf[0] = result_code / 256;
344    buf[1] = result_code & 255;
345    buf[2] = error_code / 256;
346    buf[3] = error_code & 255;
347
348    va_start(ap, fmt);
349    vsnprintf(buf+4, 256-4, fmt, ap);
350    buf[255] = 0;
351    va_end(ap);
352
353    DBG(l2tp_db(DBG_SESSION, "session_send_CDN(%s): %s\n",
354	   l2tp_debug_session_to_str(ses), buf+4));
355
356    len = 4 + strlen(buf+4);
357    /* Build the datagram */
358    dgram = l2tp_dgram_new_control(MESSAGE_CDN, tunnel->assigned_id,
359			      ses->assigned_id);
360    if (!dgram) return;
361
362    /* Add assigned session ID */
363    u16 = htons(ses->my_id);
364    l2tp_dgram_add_avp(dgram, tunnel, MANDATORY,
365		  sizeof(u16), VENDOR_IETF, AVP_ASSIGNED_SESSION_ID, &u16);
366
367    /* Add result code */
368    l2tp_dgram_add_avp(dgram, tunnel, MANDATORY,
369		  len, VENDOR_IETF, AVP_RESULT_CODE, buf);
370
371    /* TODO: Clean up */
372    session_set_state(ses, SESSION_IDLE);
373
374    /* Ship it out */
375    l2tp_tunnel_xmit_control_message(tunnel, dgram);
376
377    /* Free session */
378    l2tp_tunnel_delete_session(ses, buf+4, 0);
379}
380
381/**********************************************************************
382* %FUNCTION: session_lns_handle_incoming_call
383* %ARGUMENTS:
384*  tunnel -- tunnel on which ICRQ arrived
385*  sid -- assigned session ID
386*  dgram -- the ICRQ datagram
387* %RETURNS:
388*  Nothing
389* %DESCRIPTION:
390*  Handles ICRQ.  If we find an LNS handler willing to take the call,
391*  send ICRP.  Otherwise, send CDN.
392***********************************************************************/
393void
394l2tp_session_lns_handle_incoming_call(l2tp_tunnel *tunnel,
395				      uint16_t sid,
396				      l2tp_dgram *dgram,
397				      char const *calling_number)
398{
399    l2tp_call_ops *ops = tunnel->peer->lns_ops;
400    l2tp_session *ses;
401    uint16_t u16;
402
403    /* Allocate a session */
404    ses = malloc(sizeof(l2tp_session));
405    if (!ses) {
406	l2tp_set_errmsg("session_lns_handle_incoming_call: out of memory");
407	return;
408    }
409    /* Init fields */
410    memset(ses, 0, sizeof(l2tp_session));
411    ses->we_are_lac = 0;
412    ses->tunnel = tunnel;
413    ses->my_id = session_make_sid(tunnel);
414    ses->assigned_id = sid;
415    ses->state = SESSION_IDLE;
416    strncpy(ses->calling_number, calling_number, MAX_HOSTNAME);
417    ses->calling_number[MAX_HOSTNAME-1] = 0;
418    ses->private = NULL;
419    ses->snooping = 1;
420    ses->send_accm = 0xFFFFFFFF;
421    ses->recv_accm = 0xFFFFFFFF;
422
423    l2tp_tunnel_add_session(ses);
424
425    if (!ops || !ops->establish) {
426	l2tp_session_send_CDN(ses, RESULT_GENERAL_ERROR,
427			 ERROR_OUT_OF_RESOURCES,
428			 "No LNS handler willing to accept call");
429	return;
430    }
431
432    ses->call_ops = ops;
433
434    /* Send ICRP */
435    dgram = l2tp_dgram_new_control(MESSAGE_ICRP, ses->tunnel->assigned_id,
436			      ses->assigned_id);
437    if (!dgram) {
438	/* Ugh... not much chance of this working... */
439	l2tp_session_send_CDN(ses, RESULT_GENERAL_ERROR, ERROR_OUT_OF_RESOURCES,
440			 "Out of memory");
441	return;
442    }
443
444    /* Add assigned session ID */
445    u16 = htons(ses->my_id);
446    l2tp_dgram_add_avp(dgram, tunnel, MANDATORY,
447		  sizeof(u16), VENDOR_IETF, AVP_ASSIGNED_SESSION_ID, &u16);
448
449    /* Set session state */
450    session_set_state(ses, SESSION_WAIT_CONNECT);
451
452    /* Ship ICRP */
453    l2tp_tunnel_xmit_control_message(tunnel, dgram);
454}
455
456/**********************************************************************
457* %FUNCTION: session_handle_CDN
458* %ARGUMENTS:
459*  ses -- the session
460*  dgram -- the datagram
461* %RETURNS:
462*  Nothing
463* %DESCRIPTION:
464*  Handles a CDN by destroying session
465***********************************************************************/
466void
467l2tp_session_handle_CDN(l2tp_session *ses,
468			l2tp_dgram *dgram)
469{
470    char buf[1024];
471    unsigned char *val;
472    uint16_t len;
473    val = l2tp_dgram_search_avp(dgram, ses->tunnel, NULL, NULL, &len,
474				VENDOR_IETF, AVP_RESULT_CODE);
475    if (!val || len < 4) {
476	l2tp_tunnel_delete_session(ses, "Received CDN", 1);
477    } else {
478	uint16_t result_code, error_code;
479	char *msg;
480	result_code = ((uint16_t) val[0]) * 256 + (uint16_t) val[1];
481	error_code = ((uint16_t) val[2]) * 256 + (uint16_t) val[3];
482	if (len > 4) {
483	    msg = (char *) &val[4];
484	} else {
485	    msg = "";
486	}
487	snprintf(buf, sizeof(buf), "Received CDN: result-code = %d, error-code = %d, message = '%.*s'", result_code, error_code, (int) len-4, msg);
488	buf[1023] = 0;
489	l2tp_tunnel_delete_session(ses, buf, 1);
490    }
491}
492
493/**********************************************************************
494* %FUNCTION: session_handle_ICRP
495* %ARGUMENTS:
496*  ses -- the session
497*  dgram -- the datagram
498* %RETURNS:
499*  Nothing
500* %DESCRIPTION:
501*  Handles an ICRP
502***********************************************************************/
503void
504l2tp_session_handle_ICRP(l2tp_session *ses,
505			 l2tp_dgram *dgram)
506{
507    uint16_t u16;
508    unsigned char *val;
509    uint16_t len;
510    uint32_t u32;
511
512    int mandatory, hidden;
513    l2tp_tunnel *tunnel = ses->tunnel;
514
515    /* Get assigned session ID */
516    val = l2tp_dgram_search_avp(dgram, tunnel, &mandatory, &hidden, &len,
517			   VENDOR_IETF, AVP_ASSIGNED_SESSION_ID);
518    if (!val) {
519	l2tp_set_errmsg("No assigned session-ID in ICRP");
520	return;
521    }
522    if (!l2tp_dgram_validate_avp(VENDOR_IETF, AVP_ASSIGNED_SESSION_ID,
523			    len, mandatory)) {
524	l2tp_set_errmsg("Invalid assigned session-ID in ICRP");
525	return;
526    }
527
528    /* Set assigned session ID */
529    u16 = ((uint16_t) val[0]) * 256 + (uint16_t) val[1];
530
531    if (!u16) {
532	l2tp_set_errmsg("Invalid assigned session-ID in ICRP");
533	return;
534    }
535
536    ses->assigned_id = u16;
537
538    /* If state is not WAIT_REPLY, fubar */
539    if (ses->state != SESSION_WAIT_REPLY) {
540	l2tp_session_send_CDN(ses, RESULT_FSM_ERROR, 0, "Received ICRP for session in state %s", state_names[ses->state]);
541	return;
542    }
543
544    /* Tell PPP code that call has been established */
545    if (ses->call_ops && ses->call_ops->establish) {
546	if (ses->call_ops->establish(ses) < 0) {
547	    l2tp_session_send_CDN(ses, RESULT_GENERAL_ERROR, ERROR_VENDOR_SPECIFIC,
548			     "%s", l2tp_get_errmsg());
549	    return;
550	}
551    }
552
553    /* Send ICCN */
554    dgram = l2tp_dgram_new_control(MESSAGE_ICCN, tunnel->assigned_id,
555			      ses->assigned_id);
556    if (!dgram) {
557	/* Ugh... not much chance of this working... */
558	l2tp_session_send_CDN(ses, RESULT_GENERAL_ERROR, ERROR_OUT_OF_RESOURCES,
559			 "Out of memory");
560	return;
561    }
562
563    /* TODO: Speed, etc. are faked for now. */
564
565    /* Connect speed */
566    u32 = htonl(57600);
567    l2tp_dgram_add_avp(dgram, tunnel, MANDATORY,
568		  sizeof(u32), VENDOR_IETF, AVP_TX_CONNECT_SPEED, &u32);
569
570    /* Framing Type */
571    u32 = htonl(1);
572    l2tp_dgram_add_avp(dgram, tunnel, MANDATORY,
573		  sizeof(u32), VENDOR_IETF, AVP_FRAMING_TYPE, &u32);
574
575    /* Ship it out */
576    l2tp_tunnel_xmit_control_message(tunnel, dgram);
577
578    /* Set session state */
579    session_set_state(ses, SESSION_ESTABLISHED);
580    ses->tunnel->peer->fail = 0;
581
582}
583
584/**********************************************************************
585* %FUNCTION: session_handle_ICCN
586* %ARGUMENTS:
587*  ses -- the session
588*  dgram -- the datagram
589* %RETURNS:
590*  Nothing
591* %DESCRIPTION:
592*  Handles an ICCN
593***********************************************************************/
594void
595l2tp_session_handle_ICCN(l2tp_session *ses,
596			 l2tp_dgram *dgram)
597{
598    unsigned char *val;
599    int mandatory, hidden;
600    uint16_t len, vendor, type;
601    int err = 0;
602
603    l2tp_tunnel *tunnel = ses->tunnel;
604
605    /* If state is not WAIT_CONNECT, fubar */
606    if (ses->state != SESSION_WAIT_CONNECT) {
607	l2tp_session_send_CDN(ses, RESULT_FSM_ERROR, 0,
608			 "Received ICCN for session in state %s",
609			 state_names[ses->state]);
610	return;
611    }
612
613    /* Set session state */
614    session_set_state(ses, SESSION_ESTABLISHED);
615    ses->tunnel->peer->fail = 0;
616
617    /* Pull out and examine AVP's */
618    while(1) {
619	val = l2tp_dgram_pull_avp(dgram, tunnel, &mandatory, &hidden,
620				  &len, &vendor, &type, &err);
621	if (!val) {
622	    if (err) {
623		l2tp_session_send_CDN(ses, RESULT_GENERAL_ERROR,
624				      ERROR_BAD_VALUE, "%s", l2tp_get_errmsg());
625		return;
626	    }
627	    break;
628	}
629	if (vendor != VENDOR_IETF) {
630	    if (!mandatory) continue;
631	    l2tp_session_send_CDN(ses, RESULT_GENERAL_ERROR,
632				  ERROR_UNKNOWN_AVP_WITH_M_BIT,
633				  "Unknown mandatory attribute (vendor=%d, type=%d) in %s",
634				  (int) vendor, (int) type,
635				  l2tp_debug_avp_type_to_str(dgram->msg_type));
636	    return;
637	}
638	switch(type) {
639	case AVP_SEQUENCING_REQUIRED:
640	    ses->sequencing_required = 1;
641	    break;
642	}
643
644    }
645
646    /* Start the call */
647    if (ses->call_ops->establish(ses) < 0) {
648	l2tp_session_send_CDN(ses, RESULT_GENERAL_ERROR,
649			 ERROR_OUT_OF_RESOURCES,
650			 "No LNS handler willing to accept call");
651	return;
652    }
653
654}
655
656/**********************************************************************
657* %FUNCTION: session_find_lns_handler
658* %ARGUMENTS:
659*  name -- name of handler
660* %RETURNS:
661*  Pointer to the handler if found, NULL if not
662* %DESCRIPTION:
663*  Searches for an LNS handler by name
664***********************************************************************/
665l2tp_lns_handler *
666l2tp_session_find_lns_handler(char const *name)
667{
668    l2tp_lns_handler *cur = lns_handlers;
669    while(cur) {
670	if (!strcmp(name, cur->handler_name)) return cur;
671	cur = cur->next;
672    }
673    return NULL;
674}
675
676/**********************************************************************
677* %FUNCTION: session_find_lac_handler
678* %ARGUMENTS:
679*  name -- name of handler
680* %RETURNS:
681*  Pointer to the handler if found, NULL if not
682* %DESCRIPTION:
683*  Searches for an LAC handler by name
684***********************************************************************/
685l2tp_lac_handler *
686l2tp_session_find_lac_handler(char const *name)
687{
688    l2tp_lac_handler *cur = lac_handlers;
689    while(cur) {
690	if (!strcmp(name, cur->handler_name)) return cur;
691	cur = cur->next;
692    }
693    return NULL;
694}
695
696/**********************************************************************
697* %FUNCTION: l2tp_session_state_name
698* %ARGUMENTS:
699*  ses -- the session
700* %RETURNS:
701*  The name of the session's state
702***********************************************************************/
703char const *
704l2tp_session_state_name(l2tp_session *ses)
705{
706    return state_names[ses->state];
707}
708
709/**********************************************************************
710* %FUNCTION: l2tp_session_lcp_snoop
711* %ARGUMENTS:
712*  ses -- L2TP session structure
713*  buf -- PPP frame
714*  len -- length of PPP frame
715*  incoming -- if 1, frame is coming from L2TP tunnel.  If 0, frame is
716*              going to L2TP tunnel.
717* %RETURNS:
718*  Nothing
719* %DESCRIPTION:
720*  Snoops on LCP negotiation.  Used to send SLI to LAC if we're an LNS.
721***********************************************************************/
722void
723l2tp_session_lcp_snoop(l2tp_session *ses,
724		       unsigned char const *buf,
725		       int len,
726		       int incoming)
727{
728    unsigned int protocol;
729    int stated_len;
730    int opt, opt_len;
731    int reject;
732    unsigned char const *opt_data;
733    uint32_t accm;
734
735    /* If we are LAC, do not snoop */
736    if (ses->we_are_lac) {
737	DBG(l2tp_db(DBG_SNOOP, "Turning off snooping: We are LAC.\n"));
738	ses->snooping = 0;
739	return;
740    }
741
742    /* Get protocol */
743    if (buf[0] & 0x01) {
744	/* Compressed protcol field */
745	protocol = buf[0];
746    } else {
747	protocol = ((unsigned int) buf[0]) * 256 + buf[1];
748    }
749
750    /* If it's a network protocol, stop snooping */
751    if (protocol <= 0x3fff) {
752	DBG(l2tp_db(DBG_SNOOP, "Turning off snooping: Network protocol %04x found.\n", protocol));
753	ses->snooping = 0;
754	return;
755    }
756
757    /* If it's not LCP, do not snoop */
758    if (protocol != 0xc021) {
759	return;
760    }
761
762    /* Skip protocol; go to packet data */
763    buf += 2;
764    len -= 2;
765
766    /* Unreasonably short frame?? */
767    if (len <= 0) return;
768
769    /* Look for Configure-Ack or Configure-Reject code */
770    if (buf[0] != 2 && buf[0] != 4) return;
771
772    reject = (buf[0] == 4);
773
774    stated_len = ((unsigned int) buf[2]) * 256 + buf[3];
775
776    /* Something fishy with length field? */
777    if (stated_len > len) return;
778
779    /* Skip to options */
780    len = stated_len - 4;
781    buf += 4;
782
783    while (len > 0) {
784	/* Pull off an option */
785	opt = buf[0];
786	opt_len = buf[1];
787	opt_data = &buf[2];
788	if (opt_len > len || opt_len < 2) break;
789	len -= opt_len;
790	buf += opt_len;
791	DBG(l2tp_db(DBG_SNOOP, "Found option type %02x; len %d\n",
792		    opt, opt_len));
793	/* We are specifically interested in ACCM */
794	if (opt == 0x02 && opt_len == 0x06) {
795	    if (reject) {
796		/* ACCM negotiation REJECTED; use default */
797		accm = 0xFFFFFFFF;
798		DBG(l2tp_db(DBG_SNOOP, "Rejected ACCM negotiation; defaulting (%s)\n", incoming ? "incoming" : "outgoing"));
799		/* ??? Is this right? */
800		ses->recv_accm = accm;
801		ses->send_accm = accm;
802		ses->got_recv_accm = 1;
803		ses->got_send_accm = 1;
804	    } else {
805		memcpy(&accm, opt_data, sizeof(accm));
806		DBG(l2tp_db(DBG_SNOOP, "Found ACCM of %08x (%s)\n", accm, incoming ? "incoming" : "outgoing"));
807		if (incoming) {
808		    ses->recv_accm = accm;
809		    ses->got_recv_accm = 1;
810		} else {
811		    ses->send_accm = accm;
812		    ses->got_send_accm = 1;
813		}
814	    }
815
816	    if (ses->got_recv_accm && ses->got_send_accm) {
817		DBG(l2tp_db(DBG_SNOOP, "Sending SLI: Send ACCM = %08x; Receive ACCM = %08x\n", ses->send_accm, ses->recv_accm));
818		session_send_sli(ses);
819		ses->got_recv_accm = 0;
820		ses->got_send_accm = 0;
821	    }
822	}
823    }
824}
825/**********************************************************************
826* %FUNCTION: session_send_sli
827* %ARGUMENTS:
828*  ses -- the session
829* %RETURNS:
830*  Nothing
831* %DESCRIPTION:
832*  Sends an SLI message with send/receive ACCM's.
833***********************************************************************/
834void
835session_send_sli(l2tp_session *ses)
836{
837    l2tp_dgram *dgram;
838
839    unsigned char buf[10];
840    memset(buf, 0, 2);
841    memcpy(buf+2, &ses->send_accm, 4);
842    memcpy(buf+6, &ses->recv_accm, 4);
843
844    dgram = l2tp_dgram_new_control(MESSAGE_SLI, ses->tunnel->assigned_id,
845				   ses->assigned_id);
846    if (!dgram) return;
847
848    /* Add ACCM */
849    l2tp_dgram_add_avp(dgram, ses->tunnel, MANDATORY,
850		       sizeof(buf), VENDOR_IETF, AVP_ACCM, buf);
851
852    /* Ship it out */
853    l2tp_tunnel_xmit_control_message(ses->tunnel, dgram);
854    ses->sent_sli = 1;
855}
856