Upgrade ofono to 1.2
[profile/ivi/ofono.git] / gatchat / ppp_cp.c
1 /*
2  *
3  *  PPP library with GLib integration
4  *
5  *  Copyright (C) 2009-2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <termios.h>
31 #include <glib.h>
32 #include <arpa/inet.h>
33
34 #include "gatppp.h"
35 #include "ppp.h"
36
37 static const char *pppcp_state_strings[] = {
38         "INITIAL", "STARTING", "CLOSED", "STOPPED", "CLOSING", "STOPPING",
39         "REQSENT", "ACKRCVD", "ACKSENT", "OPENED"
40 };
41
42 static const char *pppcp_event_strings[] = {
43         "Up", "Down", "Open", "Close", "TO+", "TO-", "RCR+", "RCR-",
44         "RCA", "RCN", "RTR", "RTA", "RUC", "RXJ+", "RXJ-", "RXR"
45 };
46
47 #define pppcp_trace(p) do { \
48         char *str = g_strdup_printf("%s: %s: current state %d:%s", \
49                                 p->driver->name, __FUNCTION__, \
50                                 p->state, pppcp_state_strings[p->state]); \
51         ppp_debug(p->ppp, str); \
52         g_free(str); \
53 } while (0);
54
55 #define pppcp_trace_event(p, type, actions, state) do { \
56         char *str = g_strdup_printf("event: %d (%s), " \
57                                 "action: %x, new_state: %d (%s)", \
58                                 type, pppcp_event_strings[type], \
59                                 actions, state, pppcp_state_strings[state]); \
60         ppp_debug(p->ppp, str); \
61         g_free(str); \
62 } while (0);
63
64 #define pppcp_to_ppp_packet(p) \
65         (((guint8 *) p) - sizeof(struct ppp_header))
66
67 #define INITIAL_RESTART_TIMEOUT 3       /* restart interval in seconds */
68 #define MAX_TERMINATE           2
69 #define MAX_CONFIGURE           10
70 #define MAX_FAILURE             5
71 #define CP_HEADER_SZ            4
72
73 enum pppcp_state {
74         INITIAL         = 0,
75         STARTING        = 1,
76         CLOSED          = 2,
77         STOPPED         = 3,
78         CLOSING         = 4,
79         STOPPING        = 5,
80         REQSENT         = 6,
81         ACKRCVD         = 7,
82         ACKSENT         = 8,
83         OPENED          = 9,
84 };
85
86 enum actions {
87         INV = 0x10,
88         IRC = 0x20,
89         ZRC = 0x40,
90         TLU = 0x100,
91         TLD = 0x200,
92         TLS = 0x400,
93         TLF = 0x800,
94         SCR = 0x1000,
95         SCA = 0x2000,
96         SCN = 0x4000,
97         STR = 0x8000,
98         STA = 0x10000,
99         SCJ = 0x20000,
100         SER = 0x40000,
101 };
102
103 /*
104  * Transition table straight from RFC 1661 Section 4.1
105  * Y coordinate is the events, while X coordinate is the state
106  *
107  * Magic of bitwise operations allows the table to describe all state
108  * transitions defined in the specification
109  */
110 static int cp_transitions[16][10] = {
111 /* Up */
112 { 2, IRC|SCR|6, INV, INV, INV, INV, INV, INV, INV, INV },
113 /* Down */
114 { INV, INV, 0, TLS|1, 0, 1, 1, 1, 1, TLD|1 },
115 /* Open */
116 { TLS|1, 1, IRC|SCR|6, 3, 5, 5, 6, 7, 8, 9 },
117 /* Close */
118 { 0, TLF|0, 2, 2, 4, 4, IRC|STR|4, IRC|STR|4, IRC|STR|4, TLD|IRC|STR|4 },
119 /* TO+ */
120 { INV, INV, INV, INV, STR|4, STR|5, SCR|6, SCR|6, SCR|8, INV },
121 /* TO- */
122 { INV, INV, INV, INV, TLF|2, TLF|3, TLF|3, TLF|3, TLF|3, INV },
123 /* RCR+ */
124 { INV, INV, STA|2, IRC|SCR|SCA|8, 4, 5, SCA|8, SCA|TLU|9, SCA|8, TLD|SCR|SCA|8 },
125 /* RCR- */
126 { INV, INV, STA|2, IRC|SCR|SCN|6, 4, 5, SCN|6, SCN|7, SCN|6, TLD|SCR|SCN|6 },
127 /* RCA */
128 { INV, INV, STA|2, STA|3, 4, 5, IRC|7, SCR|6, IRC|TLU|9, TLD|SCR|6 },
129 /* RCN */
130 { INV, INV, STA|2, STA|3, 4, 5, IRC|SCR|6, SCR|6, IRC|SCR|8, TLD|SCR|6 },
131 /* RTR */
132 { INV, INV, STA|2, STA|3, STA|4, STA|5, STA|6, STA|6, STA|6, TLD|ZRC|STA|5 },
133 /* RTA */
134 { INV, INV, 2, 3, TLF|2, TLF|3, 6, 6, 8, TLD|SCR|6 },
135 /* RUC */
136 { INV, INV, SCJ|2, SCJ|3, SCJ|4, SCJ|5, SCJ|6, SCJ|7, SCJ|8, SCJ|9 },
137 /* RXJ+ */
138 { INV, INV, 2, 3, 4, 5, 6, 6, 8, 9 },
139 /* RXJ- */
140 { INV, INV, TLF|2, TLF|3, TLF|2, TLF|3, TLF|3, TLF|3, TLF|3, TLD|IRC|STR|5 },
141 /* RXR */
142 { INV, INV, 2, 3, 4, 5, 6, 7, 8, SER|9 },
143 };
144
145 enum pppcp_event_type {
146         UP              = 0,
147         DOWN            = 1,
148         OPEN            = 2,
149         CLOSE           = 3,
150         TO_PLUS         = 4,
151         TO_MINUS        = 5,
152         RCR_PLUS        = 6,
153         RCR_MINUS       = 7,
154         RCA             = 8,
155         RCN             = 9,
156         RTR             = 10,
157         RTA             = 11,
158         RUC             = 12,
159         RXJ_PLUS        = 13,
160         RXJ_MINUS       = 14,
161         RXR             = 15,
162 };
163
164 struct pppcp_timer_data {
165         struct pppcp_data *data;
166         guint restart_counter;
167         guint restart_interval;
168         guint max_counter;
169         guint restart_timer;
170 };
171
172 struct pppcp_data {
173         unsigned char state;
174         struct pppcp_timer_data config_timer_data;
175         struct pppcp_timer_data terminate_timer_data;
176         guint max_failure;
177         guint failure_counter;
178         GAtPPP *ppp;
179         guint8 config_identifier;
180         guint8 terminate_identifier;
181         guint8 reject_identifier;
182         const guint8 *local_options;
183         guint16 local_options_len;
184         guint8 *peer_options;
185         guint16 peer_options_len;
186         gboolean send_reject;
187         const struct pppcp_proto *driver;
188         gpointer priv;
189 };
190
191 static void pppcp_generate_event(struct pppcp_data *data,
192                                 enum pppcp_event_type event_type,
193                                 const guint8 *packet, guint len);
194
195 static void pppcp_packet_free(struct pppcp_packet *packet)
196 {
197         g_free(pppcp_to_ppp_packet(packet));
198 }
199
200 static struct pppcp_packet *pppcp_packet_new(struct pppcp_data *data,
201                                                 guint type, guint bufferlen)
202 {
203         struct pppcp_packet *packet;
204         struct ppp_header *ppp_packet;
205         guint16 packet_length = bufferlen + sizeof(*packet);
206
207         ppp_packet = ppp_packet_new(packet_length, data->driver->proto);
208         if (ppp_packet == NULL)
209                 return NULL;
210
211         /* advance past protocol to add CP header information */
212         packet = (struct pppcp_packet *) (ppp_packet->info);
213
214         packet->length = htons(packet_length);
215         packet->code = type;
216         return packet;
217 }
218
219 void ppp_option_iter_init(struct ppp_option_iter *iter,
220                                         const struct pppcp_packet *packet)
221 {
222         iter->max = ntohs(packet->length) - CP_HEADER_SZ;
223         iter->pdata = packet->data;
224         iter->pos = 0;
225         iter->type = 0;
226         iter->len = 0;
227         iter->option_data = NULL;
228 }
229
230 gboolean ppp_option_iter_next(struct ppp_option_iter *iter)
231 {
232         const guint8 *cur = iter->pdata + iter->pos;
233         const guint8 *end = iter->pdata + iter->max;
234
235         if (cur + 1 > end)
236                 return FALSE;
237
238         if (cur + cur[1] > end)
239                 return FALSE;
240
241         iter->type = cur[0];
242         iter->len = cur[1] - 2;
243         iter->option_data = cur + 2;
244
245         iter->pos += cur[1];
246
247         return TRUE;
248 }
249
250 guint8 ppp_option_iter_get_type(struct ppp_option_iter *iter)
251 {
252         return iter->type;
253 }
254
255 guint8 ppp_option_iter_get_length(struct ppp_option_iter *iter)
256 {
257         return iter->len;
258 }
259
260 const guint8 *ppp_option_iter_get_data(struct ppp_option_iter *iter)
261 {
262         return iter->option_data;
263 }
264
265 guint8 pppcp_get_code(const guint8 *data)
266 {
267         struct ppp_header *ppp_packet = (struct ppp_header *) data;
268         struct pppcp_packet *packet = (struct pppcp_packet *) ppp_packet->info;
269
270         return packet->code;
271 }
272
273 static gboolean pppcp_timeout(gpointer user_data)
274 {
275         struct pppcp_timer_data *timer_data = user_data;
276
277         pppcp_trace(timer_data->data);
278
279         timer_data->restart_timer = 0;
280
281         if (timer_data->restart_counter > 0)
282                 pppcp_generate_event(timer_data->data, TO_PLUS, NULL, 0);
283         else
284                 pppcp_generate_event(timer_data->data, TO_MINUS, NULL, 0);
285
286         return FALSE;
287 }
288
289 static void pppcp_stop_timer(struct pppcp_timer_data *timer_data)
290 {
291         if (timer_data->restart_timer > 0) {
292                 g_source_remove(timer_data->restart_timer);
293                 timer_data->restart_timer = 0;
294         }
295 }
296
297 static void pppcp_start_timer(struct pppcp_timer_data *timer_data)
298 {
299         pppcp_stop_timer(timer_data);
300
301         timer_data->restart_timer =
302                 g_timeout_add_seconds(timer_data->restart_interval,
303                                 pppcp_timeout, timer_data);
304 }
305
306 static gboolean is_first_request(struct pppcp_timer_data *timer_data)
307 {
308         return (timer_data->restart_counter == timer_data->max_counter);
309 }
310
311 /* actions */
312 /* log an illegal event, but otherwise do nothing */
313 static void pppcp_illegal_event(GAtPPP *ppp, guint8 state, guint8 type)
314 {
315         DBG(ppp, "Illegal event %d while in state %d", type, state);
316 }
317
318 static void pppcp_this_layer_up(struct pppcp_data *data)
319 {
320         if (data->driver->this_layer_up)
321                 data->driver->this_layer_up(data);
322 }
323
324 static void pppcp_this_layer_down(struct pppcp_data *data)
325 {
326         if (data->driver->this_layer_down)
327                 data->driver->this_layer_down(data);
328 }
329
330 static void pppcp_this_layer_started(struct pppcp_data *data)
331 {
332         if (data->driver->this_layer_started)
333                 data->driver->this_layer_started(data);
334 }
335
336 static void pppcp_this_layer_finished(struct pppcp_data *data)
337 {
338         pppcp_trace(data);
339         if (data->driver->this_layer_finished)
340                 data->driver->this_layer_finished(data);
341 }
342
343 /*
344  * set the restart counter to either max-terminate
345  * or max-configure.  The counter is decremented for
346  * each transmission, including the first.
347  */
348 static void pppcp_initialize_restart_count(struct pppcp_timer_data *timer_data)
349 {
350         struct pppcp_data *data = timer_data->data;
351
352         pppcp_trace(data);
353
354         timer_data->restart_counter = timer_data->max_counter;
355 }
356
357 /*
358  * set restart counter to zero
359  */
360 static void pppcp_zero_restart_count(struct pppcp_timer_data *timer_data)
361 {
362         timer_data->restart_counter = 0;
363 }
364
365 /*
366  * TBD - generate new identifier for packet
367  */
368 static guint8 new_identity(struct pppcp_data *data, guint prev_identifier)
369 {
370         return prev_identifier + 1;
371 }
372
373 /*
374  * transmit a Configure-Request packet
375  * start the restart timer
376  * decrement the restart counter
377  */
378 static void pppcp_send_configure_request(struct pppcp_data *pppcp)
379 {
380         struct pppcp_packet *packet;
381         struct pppcp_timer_data *timer_data = &pppcp->config_timer_data;
382
383         pppcp_trace(pppcp);
384
385         packet = pppcp_packet_new(pppcp, PPPCP_CODE_TYPE_CONFIGURE_REQUEST,
386                                         pppcp->local_options_len);
387         memcpy(packet->data, pppcp->local_options, pppcp->local_options_len);
388
389         /*
390          * if this is the first request, we need a new identifier.
391          * if this is a retransmission, leave the identifier alone.
392          */
393         if (is_first_request(timer_data))
394                 pppcp->config_identifier =
395                         new_identity(pppcp, pppcp->config_identifier);
396         packet->identifier = pppcp->config_identifier;
397
398         ppp_transmit(pppcp->ppp, pppcp_to_ppp_packet(packet),
399                         ntohs(packet->length));
400
401         pppcp_packet_free(packet);
402
403         /* start timer for retransmission */
404         timer_data->restart_counter--;
405         pppcp_start_timer(timer_data);
406 }
407
408 /*
409  * transmit a Configure-Ack packet
410  */
411 static void pppcp_send_configure_ack(struct pppcp_data *pppcp,
412                                         const guint8 *request)
413 {
414         struct pppcp_packet *packet;
415         struct pppcp_packet *cr_req = (struct pppcp_packet *) request;
416         guint16 len;
417
418         pppcp_trace(pppcp);
419
420         pppcp->failure_counter = 0;
421
422         /* subtract for header. */
423         len = ntohs(cr_req->length) - CP_HEADER_SZ;
424
425         packet = pppcp_packet_new(pppcp, PPPCP_CODE_TYPE_CONFIGURE_ACK, len);
426
427         memcpy(packet->data, cr_req->data, len);
428         packet->identifier = cr_req->identifier;
429         ppp_transmit(pppcp->ppp, pppcp_to_ppp_packet(packet),
430                         ntohs(packet->length));
431         pppcp_packet_free(packet);
432 }
433
434 /*
435  * transmit a Configure-Nak or Configure-Reject packet
436  */
437 static void pppcp_send_configure_nak(struct pppcp_data *pppcp,
438                                         const guint8 *request)
439 {
440         struct pppcp_packet *packet;
441         struct pppcp_packet *cr_req = (struct pppcp_packet *) request;
442
443         pppcp_trace(pppcp);
444
445         /*
446          * if we have exceeded our Max-Failure counter, we simply reject all
447          * the options.
448          */
449         if (pppcp->failure_counter >= pppcp->max_failure) {
450                 guint16 len = ntohs(cr_req->length) - CP_HEADER_SZ;
451
452                 packet = pppcp_packet_new(pppcp,
453                                         PPPCP_CODE_TYPE_CONFIGURE_REJECT, len);
454                 memcpy(packet->data, cr_req->data, len);
455         } else {
456                 enum pppcp_code code = PPPCP_CODE_TYPE_CONFIGURE_NAK;
457
458                 if (pppcp->send_reject == TRUE)
459                         code = PPPCP_CODE_TYPE_CONFIGURE_REJECT;
460                 else
461                         pppcp->failure_counter++;
462
463                 packet = pppcp_packet_new(pppcp, code, pppcp->peer_options_len);
464                 memcpy(packet->data, pppcp->peer_options,
465                                                 pppcp->peer_options_len);
466         }
467
468         packet->identifier = cr_req->identifier;
469         ppp_transmit(pppcp->ppp, pppcp_to_ppp_packet(packet),
470                         ntohs(packet->length));
471
472         pppcp_packet_free(packet);
473
474         g_free(pppcp->peer_options);
475         pppcp->peer_options = NULL;
476         pppcp->peer_options_len = 0;
477 }
478
479 /*
480  * transmit a Terminate-Request packet.
481  * start the restart timer.
482  * decrement the restart counter
483  */
484 static void pppcp_send_terminate_request(struct pppcp_data *data)
485 {
486         struct pppcp_packet *packet;
487         struct pppcp_timer_data *timer_data = &data->terminate_timer_data;
488
489         pppcp_trace(data);
490
491         /*
492          * the data field can be used by the sender (us).
493          * leave this empty for now.
494          */
495         packet = pppcp_packet_new(data, PPPCP_CODE_TYPE_TERMINATE_REQUEST, 0);
496
497         /*
498          * Is this a retransmission?  If so, do not change
499          * the identifier.  If not, we need a fresh identity.
500          */
501         if (is_first_request(timer_data))
502                 data->terminate_identifier =
503                         new_identity(data, data->terminate_identifier);
504         packet->identifier = data->terminate_identifier;
505         ppp_transmit(data->ppp, pppcp_to_ppp_packet(packet),
506                         ntohs(packet->length));
507
508         pppcp_packet_free(packet);
509         timer_data->restart_counter--;
510         pppcp_start_timer(timer_data);
511 }
512
513 /*
514  * transmit a Terminate-Ack packet
515  */
516 static void pppcp_send_terminate_ack(struct pppcp_data *data,
517                                         const guint8 *request)
518 {
519         struct pppcp_packet *packet;
520         struct pppcp_packet *pppcp_header = (struct pppcp_packet *) request;
521         struct pppcp_timer_data *timer_data = &data->terminate_timer_data;
522
523         pppcp_trace(data);
524
525         packet = pppcp_packet_new(data, PPPCP_CODE_TYPE_TERMINATE_ACK, 0);
526
527         /* match identifier of the request */
528         packet->identifier = pppcp_header->identifier;
529
530         ppp_transmit(data->ppp, pppcp_to_ppp_packet(packet),
531                         ntohs(pppcp_header->length));
532
533         pppcp_packet_free(packet);
534         pppcp_start_timer(timer_data);
535 }
536
537 /*
538  * transmit a Code-Reject packet
539  *
540  * XXX this seg faults.
541  */
542 static void pppcp_send_code_reject(struct pppcp_data *data,
543                                         const guint8 *rejected_packet)
544 {
545         struct pppcp_packet *packet;
546         const struct pppcp_packet *old_packet =
547                                 (const struct pppcp_packet *) rejected_packet;
548
549         pppcp_trace(data);
550
551         packet = pppcp_packet_new(data, PPPCP_CODE_TYPE_CODE_REJECT,
552                                                 ntohs(old_packet->length));
553
554         /*
555          * Identifier must be changed for each Code-Reject sent
556          */
557         packet->identifier = new_identity(data, data->reject_identifier);
558
559         /*
560          * rejected packet should be copied in, but it should be
561          * truncated if it needs to be to comply with mtu requirement
562          */
563         memcpy(packet->data, rejected_packet,
564                         ntohs(packet->length) - CP_HEADER_SZ);
565
566         ppp_transmit(data->ppp, pppcp_to_ppp_packet(packet),
567                         ntohs(packet->length));
568
569         pppcp_packet_free(packet);
570 }
571
572 /*
573  * transmit an Echo-Reply packet
574  */
575 static void pppcp_send_echo_reply(struct pppcp_data *data,
576                                                 const guint8 *request)
577 {
578         struct pppcp_packet *packet;
579         struct pppcp_packet *header = (struct pppcp_packet *) request;
580
581         /*
582          * 0 bytes for data, 4 bytes for magic number
583          */
584         packet = pppcp_packet_new(data, PPPCP_CODE_TYPE_ECHO_REPLY, 4);
585
586         /*
587          * match identifier of request
588          */
589         packet->identifier = header->identifier;
590
591         /* magic number will always be zero */
592         ppp_transmit(data->ppp, pppcp_to_ppp_packet(packet),
593                         ntohs(packet->length));
594
595         pppcp_packet_free(packet);
596 }
597
598 static void pppcp_transition_state(enum pppcp_state new_state,
599                                         struct pppcp_data *data)
600 {
601         /*
602          * if switching from a state where
603          * TO events occur, to one where they
604          * may not, shut off the timer
605          */
606         switch (new_state) {
607         case INITIAL:
608         case STARTING:
609         case CLOSED:
610         case STOPPED:
611         case OPENED:
612                 pppcp_stop_timer(&data->config_timer_data);
613                 pppcp_stop_timer(&data->terminate_timer_data);
614                 break;
615         case CLOSING:
616         case STOPPING:
617         case REQSENT:
618         case ACKRCVD:
619         case ACKSENT:
620                 break;
621         }
622         data->state = new_state;
623 }
624
625 /*
626  * send the event handler a new event to process
627  */
628 static void pppcp_generate_event(struct pppcp_data *data,
629                                 enum pppcp_event_type event_type,
630                                 const guint8 *packet, guint len)
631 {
632         int actions;
633         unsigned char new_state;
634
635         if (event_type > RXR)
636                 goto error;
637
638         pppcp_trace(data);
639
640         actions = cp_transitions[event_type][data->state];
641         new_state = actions & 0xf;
642
643         pppcp_trace_event(data, event_type, actions, new_state);
644
645         if (actions & INV)
646                 goto error;
647
648         if (actions & IRC) {
649                 struct pppcp_timer_data *timer_data;
650
651                 if (new_state == CLOSING || new_state == STOPPING)
652                         timer_data = &data->terminate_timer_data;
653                 else
654                         timer_data = &data->config_timer_data;
655
656                 pppcp_initialize_restart_count(timer_data);
657         } else if (actions & ZRC)
658                 pppcp_zero_restart_count(&data->terminate_timer_data);
659
660         if (actions & SCR)
661                 pppcp_send_configure_request(data);
662
663         if (actions & SCA)
664                 pppcp_send_configure_ack(data, packet);
665         else if (actions & SCN)
666                 pppcp_send_configure_nak(data, packet);
667
668         if (actions & STR)
669                 pppcp_send_terminate_request(data);
670         else if (actions & STA)
671                 pppcp_send_terminate_ack(data, packet);
672
673         if (actions & SCJ)
674                 pppcp_send_code_reject(data, packet);
675
676         if (actions & SER)
677                 pppcp_send_echo_reply(data, packet);
678
679         pppcp_transition_state(new_state, data);
680
681         if (actions & TLS)
682                 pppcp_this_layer_started(data);
683         else if (actions & TLU)
684                 pppcp_this_layer_up(data);
685         else if (actions & TLD)
686                 pppcp_this_layer_down(data);
687         else if (actions & TLF)
688                 pppcp_this_layer_finished(data);
689
690         return;
691
692 error:
693         pppcp_illegal_event(data->ppp, data->state, event_type);
694 }
695
696 void pppcp_signal_open(struct pppcp_data *data)
697 {
698         pppcp_generate_event(data, OPEN, NULL, 0);
699 }
700
701 void pppcp_signal_close(struct pppcp_data *data)
702 {
703         pppcp_generate_event(data, CLOSE, NULL, 0);
704 }
705
706 void pppcp_signal_up(struct pppcp_data *data)
707 {
708         pppcp_generate_event(data, UP, NULL, 0);
709 }
710
711 void pppcp_signal_down(struct pppcp_data *data)
712 {
713         pppcp_generate_event(data, DOWN, NULL, 0);
714 }
715
716 static guint8 pppcp_process_configure_request(struct pppcp_data *pppcp,
717                                         const struct pppcp_packet *packet)
718 {
719         pppcp_trace(pppcp);
720
721         if (pppcp->failure_counter >= pppcp->max_failure)
722                 return RCR_MINUS;
723
724         if (pppcp->driver->rcr) {
725                 enum rcr_result res;
726
727                 res = pppcp->driver->rcr(pppcp, packet,
728                                                 &pppcp->peer_options,
729                                                 &pppcp->peer_options_len);
730
731                 if (res == RCR_REJECT) {
732                         pppcp->send_reject = TRUE;
733                         return RCR_MINUS;
734                 } else if (res == RCR_NAK) {
735                         pppcp->send_reject = FALSE;
736                         return RCR_MINUS;
737                 }
738         }
739
740         return RCR_PLUS;
741 }
742
743 static guint8 pppcp_process_configure_ack(struct pppcp_data *pppcp,
744                                         const struct pppcp_packet *packet)
745 {
746         gint len;
747
748         pppcp_trace(pppcp);
749
750         len = ntohs(packet->length) - CP_HEADER_SZ;
751
752         /* if identifiers don't match, we should silently discard */
753         if (packet->identifier != pppcp->config_identifier) {
754                 return 0;
755         }
756
757         /*
758          * First we must sanity check that all config options acked are
759          * equal to the config options sent and are in the same order.
760          * If this is not the case, then silently drop the packet
761          */
762         if (pppcp->local_options_len != len)
763                 return 0;
764
765         if (memcmp(pppcp->local_options, packet->data, len))
766                 return 0;
767
768         /* Otherwise, apply local options */
769         if (pppcp->driver->rca)
770                 pppcp->driver->rca(pppcp, packet);
771
772         return RCA;
773 }
774
775 static guint8 pppcp_process_configure_nak(struct pppcp_data *pppcp,
776                                         const struct pppcp_packet *packet)
777 {
778         pppcp_trace(pppcp);
779
780         /* if identifiers don't match, we should silently discard */
781         if (packet->identifier != pppcp->config_identifier)
782                 return 0;
783
784         if (pppcp->driver->rcn_nak)
785                 pppcp->driver->rcn_nak(pppcp, packet);
786
787         return RCN;
788 }
789
790 static guint8 pppcp_process_configure_reject(struct pppcp_data *pppcp,
791                                         const struct pppcp_packet *packet)
792 {
793         pppcp_trace(pppcp);
794
795         /*
796          * make sure identifier matches that of last sent configure
797          * request
798          */
799         if (packet->identifier != pppcp->config_identifier)
800                 return 0;
801
802         /*
803          * check to see which options were rejected
804          * Rejected options must be a subset of requested
805          * options and in the same order.
806          *
807          * when a new configure-request is sent, we may
808          * not request any of these options be negotiated
809          */
810         if (pppcp->driver->rcn_rej)
811                 pppcp->driver->rcn_rej(pppcp, packet);
812
813         return RCN;
814 }
815
816 static guint8 pppcp_process_terminate_request(struct pppcp_data *data,
817                                         const struct pppcp_packet *packet)
818 {
819         pppcp_trace(data);
820
821         return RTR;
822 }
823
824 static guint8 pppcp_process_terminate_ack(struct pppcp_data *data,
825                                         const struct pppcp_packet *packet)
826 {
827         /*
828          * if we wind up using the data field for anything, then
829          * we'd want to check the identifier.
830          * even if the identifiers don't match, we still handle
831          * a terminate ack, as it is allowed to be unelicited
832          */
833         pppcp_trace(data);
834
835         return RTA;
836 }
837
838 static guint8 pppcp_process_code_reject(struct pppcp_data *data,
839                                         const struct pppcp_packet *packet)
840 {
841         /*
842          * determine if the code reject is catastrophic or not.
843          * return RXJ_PLUS if this reject is acceptable, RXJ_MINUS if
844          * it is catastrophic.
845          *
846          * for now we always return RXJ_MINUS.  Any code
847          * reject will be catastrophic, since we only support the
848          * bare minimum number of codes necessary to function.
849          */
850         return RXJ_MINUS;
851 }
852
853 static guint8 pppcp_process_protocol_reject(struct pppcp_data *data,
854                                         const struct pppcp_packet *packet)
855 {
856         /*
857          * determine if the protocol reject is catastrophic or not.
858          * return RXJ_PLUS if this reject is acceptable, RXJ_MINUS if
859          * it is catastrophic.
860          *
861          * for now we always return RXJ_MINUS.  Any protocol
862          * reject will be catastrophic, since we only support the
863          * bare minimum number of protocols necessary to function.
864          */
865         return RXJ_MINUS;
866 }
867
868 /*
869  * For Echo-Request, Echo-Reply, and Discard-Request, we will not
870  * bother checking the magic number of the packet, because we will
871  * never send an echo or discard request.  We can't reliably detect
872  * loop back anyway, since we don't negotiate a magic number.
873  */
874 static guint8 pppcp_process_echo_request(struct pppcp_data *data,
875                                         const struct pppcp_packet *packet)
876 {
877         return RXR;
878 }
879
880 static guint8 pppcp_process_echo_reply(struct pppcp_data *data,
881                                         const struct pppcp_packet *packet)
882 {
883         return 0;
884 }
885
886 static guint8 pppcp_process_discard_request(struct pppcp_data *data,
887                                         const struct pppcp_packet *packet)
888 {
889         return 0;
890 }
891
892 static guint8 (*packet_ops[11])(struct pppcp_data *data,
893                                         const struct pppcp_packet *packet) = {
894         pppcp_process_configure_request,
895         pppcp_process_configure_ack,
896         pppcp_process_configure_nak,
897         pppcp_process_configure_reject,
898         pppcp_process_terminate_request,
899         pppcp_process_terminate_ack,
900         pppcp_process_code_reject,
901         pppcp_process_protocol_reject,
902         pppcp_process_echo_request,
903         pppcp_process_echo_reply,
904         pppcp_process_discard_request,
905 };
906
907 void pppcp_send_protocol_reject(struct pppcp_data *data,
908                                 const guint8 *rejected_packet, gsize len)
909 {
910         struct pppcp_packet *packet;
911
912         pppcp_trace(data);
913
914         /*
915          * Protocol-Reject can only be sent when we are in
916          * the OPENED state.  If in any other state, silently discard.
917          */
918         if (data->state != OPENED)
919                 return;
920
921         /*
922          * info should contain the old packet info, plus the 16bit
923          * protocol number we are rejecting.
924          */
925         packet = pppcp_packet_new(data, PPPCP_CODE_TYPE_PROTOCOL_REJECT,
926                                         len - 2);
927
928         /*
929          * Identifier must be changed for each Protocol-Reject sent
930          */
931         packet->identifier = new_identity(data, data->reject_identifier);
932
933         /*
934          * rejected packet should be copied in, but it should be
935          * truncated if it needs to be to comply with mtu requirement
936          */
937         memcpy(packet->data, rejected_packet + 2, len - 2);
938
939         ppp_transmit(data->ppp, pppcp_to_ppp_packet(packet),
940                         ntohs(packet->length));
941
942         pppcp_packet_free(packet);
943 }
944
945 /*
946  * parse the packet and determine which event this packet caused
947  */
948 void pppcp_process_packet(gpointer priv, const guint8 *new_packet, gsize len)
949 {
950         struct pppcp_data *data = priv;
951         const struct pppcp_packet *packet =
952                                 (const struct pppcp_packet *) new_packet;
953         guint8 event_type;
954         guint data_len = 0;
955
956         if (len < sizeof(struct pppcp_packet))
957                 return;
958
959         /* check flags to see if we support this code */
960         if (!(data->driver->supported_codes & (1 << packet->code)))
961                 event_type = RUC;
962         else
963                 event_type = packet_ops[packet->code-1](data, packet);
964
965         if (event_type) {
966                 data_len = ntohs(packet->length);
967                 pppcp_generate_event(data, event_type, new_packet, data_len);
968         }
969 }
970
971 void pppcp_free(struct pppcp_data *pppcp)
972 {
973         pppcp_stop_timer(&pppcp->config_timer_data);
974         pppcp_stop_timer(&pppcp->terminate_timer_data);
975         g_free(pppcp->peer_options);
976         g_free(pppcp);
977 }
978
979 void pppcp_set_data(struct pppcp_data *pppcp, gpointer data)
980 {
981         pppcp->priv = data;
982 }
983
984 gpointer pppcp_get_data(struct pppcp_data *pppcp)
985 {
986         return pppcp->priv;
987 }
988
989 GAtPPP *pppcp_get_ppp(struct pppcp_data *pppcp)
990 {
991         return pppcp->ppp;
992 }
993
994 void pppcp_set_local_options(struct pppcp_data *pppcp,
995                                         const guint8 *options, guint16 len)
996 {
997         pppcp->local_options = options;
998         pppcp->local_options_len = len;
999 }
1000
1001 struct pppcp_data *pppcp_new(GAtPPP *ppp, const struct pppcp_proto *proto,
1002                                 gboolean dormant, guint max_failure)
1003 {
1004         struct pppcp_data *data;
1005
1006         data = g_try_malloc0(sizeof(struct pppcp_data));
1007         if (data == NULL)
1008                 return NULL;
1009
1010         if (dormant)
1011                 data->state = STOPPED;
1012         else
1013                 data->state = INITIAL;
1014
1015         data->config_timer_data.restart_interval = INITIAL_RESTART_TIMEOUT;
1016         data->terminate_timer_data.restart_interval = INITIAL_RESTART_TIMEOUT;
1017         data->config_timer_data.max_counter = MAX_CONFIGURE;
1018         data->terminate_timer_data.max_counter = MAX_TERMINATE;
1019         data->config_timer_data.data = data;
1020         data->terminate_timer_data.data = data;
1021
1022         if (max_failure)
1023                 data->max_failure = max_failure;
1024         else
1025                 data->max_failure = MAX_FAILURE;
1026
1027         data->ppp = ppp;
1028         data->driver = proto;
1029
1030         return data;
1031 }