ipcp.c
Go to the documentation of this file.
1 /**
2  * @file ipcp.c
3  * @brief IPCP (PPP Internet Protocol Control Protocol)
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.0
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL PPP_TRACE_LEVEL
31 
32 //Dependencies
33 #include "core/net.h"
34 #include "ipv4/ipv4.h"
35 #include "ppp/ppp_fsm.h"
36 #include "ppp/ppp_misc.h"
37 #include "ppp/ppp_debug.h"
38 #include "ppp/ipcp.h"
39 #include "debug.h"
40 
41 //Check TCP/IP stack configuration
42 #if (PPP_SUPPORT == ENABLED && IPV4_SUPPORT == ENABLED)
43 
44 
45 /**
46  * @brief IPCP FSM callbacks
47  **/
48 
50 {
64  NULL
65 };
66 
67 
68 /**
69  * @brief IPCP Open event
70  * @param[in] context PPP context
71  * @return Error code
72  **/
73 
75 {
76  //Debug message
77  TRACE_INFO("\r\nIPCP Open event\r\n");
78 
79  //The link is administratively available for traffic
80  pppOpenEvent(context, &context->ipcpFsm, &ipcpCallbacks);
81  //The lower layer is ready to carry packets
82  pppUpEvent(context, &context->ipcpFsm, &ipcpCallbacks);
83 
84  //Successful processing
85  return NO_ERROR;
86 }
87 
88 
89 /**
90  * @brief IPCP Close event
91  * @param[in] context PPP context
92  * @return Error code
93  **/
94 
96 {
97  //Debug message
98  TRACE_INFO("\r\nIPCP Close event\r\n");
99 
100  //The lower layer is no longer ready to carry packets
101  pppDownEvent(context, &context->ipcpFsm, &ipcpCallbacks);
102  //The link is no longer available for traffic
103  pppCloseEvent(context, &context->ipcpFsm, &ipcpCallbacks);
104 
105  //Successful processing
106  return NO_ERROR;
107 }
108 
109 
110 /**
111  * @brief IPCP timer handler
112  *
113  * This routine must be periodically called by the TCP/IP stack to
114  * manage retransmissions
115  *
116  * @param[in] context PPP context
117  **/
118 
119 void ipcpTick(PppContext *context)
120 {
121  //Check whether the restart timer is running
122  if(context->ipcpFsm.state >= PPP_STATE_4_CLOSING &&
123  context->ipcpFsm.state <= PPP_STATE_8_ACK_SENT)
124  {
125  //Get current time
127 
128  //Check restart timer
129  if((time - context->ipcpFsm.timestamp) >= PPP_RESTART_TIMER)
130  {
131  //Debug message
132  TRACE_INFO("\r\nIPCP Timeout event\r\n");
133 
134  //The restart timer is used to retransmit Configure-Request
135  //and Terminate-Request packets
136  pppTimeoutEvent(context, &context->ipcpFsm, &ipcpCallbacks);
137  }
138  }
139 }
140 
141 
142 /**
143  * @brief Process an incoming IPCP packet
144  * @param[in] context PPP context
145  * @param[in] packet IPCP packet received from the peer
146  * @param[in] length Length of the packet, in bytes
147  **/
148 
149 void ipcpProcessPacket(PppContext *context, const PppPacket *packet, size_t length)
150 {
151  //Ensure the length of the incoming IPCP packet is valid
152  if(length < sizeof(PppPacket))
153  return;
154 
155  //Check the length field
156  if(ntohs(packet->length) > length)
157  return;
158  if(ntohs(packet->length) < sizeof(PppPacket))
159  return;
160 
161  //Save the length of the IPCP packet
162  length = ntohs(packet->length);
163 
164  //Debug message
165  TRACE_INFO("IPCP packet received (%" PRIuSIZE " bytes)...\r\n", length);
166  //Dump IPCP packet contents for debugging purpose
168 
169  //Check IPCP code field
170  switch(packet->code)
171  {
172  //Configure-Request packet?
174  //Process Configure-Request packet
175  ipcpProcessConfigureReq(context, (PppConfigurePacket *) packet);
176  break;
177  //Configure-Ack packet?
179  //Process Configure-Ack packet
180  ipcpProcessConfigureAck(context, (PppConfigurePacket *) packet);
181  break;
182  //Configure-Nak packet?
184  //Process Configure-Nak packet
185  ipcpProcessConfigureNak(context, (PppConfigurePacket *) packet);
186  break;
187  //Configure-Reject packet?
189  //Process Configure-Reject packet
190  ipcpProcessConfigureReject(context, (PppConfigurePacket *) packet);
191  break;
192  //Terminate-Request packet?
194  //Process Terminate-Request packet
195  ipcpProcessTerminateReq(context, (PppTerminatePacket *) packet);
196  break;
197  //Terminate-Ack packet?
199  //Process Terminate-Ack packet
200  ipcpProcessTerminateAck(context, (PppTerminatePacket *) packet);
201  break;
202  //Code-Reject packet?
203  case PPP_CODE_CODE_REJ:
204  //Process Code-Reject packet
205  ipcpProcessCodeRej(context, (PppCodeRejPacket *) packet);
206  break;
207  //Unknown code field
208  default:
209  //The packet is un-interpretable
210  ipcpProcessUnknownCode(context, packet);
211  break;
212  }
213 }
214 
215 
216 /**
217  * @brief Process Configure-Request packet
218  * @param[in] context PPP context
219  * @param[in] configureReqPacket Packet received from the peer
220  * @return Error code
221  **/
222 
224  const PppConfigurePacket *configureReqPacket)
225 {
226  error_t error;
227  size_t length;
228  bool_t notRecognizable;
229  bool_t notAcceptable;
230  PppOption *option;
231 
232  //Debug message
233  TRACE_INFO("\r\nIPCP Receive-Configure-Request event\r\n");
234 
235  //Initialize variables
236  error = NO_ERROR;
237  notRecognizable = FALSE;
238  notAcceptable = FALSE;
239 
240  //Retrieve the length of the option list
241  length = ntohs(configureReqPacket->length) - sizeof(PppConfigurePacket);
242  //Point to the first option
243  option = (PppOption *) configureReqPacket->options;
244 
245  //Parse configuration options
246  while(length > 0)
247  {
248  //Parse current option
249  error = ipcpParseOption(context, option, length, NULL);
250 
251  //Any error to report?
252  if(error == ERROR_INVALID_TYPE)
253  {
254  //Option not recognizable
255  notRecognizable = TRUE;
256  //Catch error
257  error = NO_ERROR;
258  }
259  else if(error == ERROR_INVALID_VALUE)
260  {
261  //Option not acceptable for configuration
262  notAcceptable = TRUE;
263  //Catch error
264  error = NO_ERROR;
265  }
266  else if(error)
267  {
268  //Malformed Configure-Request packet
269  break;
270  }
271 
272  //Remaining bytes to process
273  length -= option->length;
274  //Jump to the next option
275  option = (PppOption *) ((uint8_t *) option + option->length);
276  }
277 
278  //Valid Configure-Request packet received from the peer?
279  if(!error)
280  {
281  //Check flags
282  if(notRecognizable)
283  {
284  //If some configuration options received in the Configure-Request are not
285  //recognizable or not acceptable for negotiation, then the implementation
286  //must transmit a Configure-Reject
287  pppRcvConfigureReqEvent(context, &context->ipcpFsm, &ipcpCallbacks,
288  configureReqPacket, PPP_CODE_CONFIGURE_REJ);
289  }
290  else if(notAcceptable)
291  {
292  //If all configuration options are recognizable, but some values are not
293  //acceptable, then the implementation must transmit a Configure-Nak
294  pppRcvConfigureReqEvent(context, &context->ipcpFsm, &ipcpCallbacks,
295  configureReqPacket, PPP_CODE_CONFIGURE_NAK);
296  }
297  else
298  {
299  //If every configuration option received in the Configure-Request is
300  //recognizable and all values are acceptable, then the implementation
301  //must transmit a Configure-Ack
302  pppRcvConfigureReqEvent(context, &context->ipcpFsm, &ipcpCallbacks,
303  configureReqPacket, PPP_CODE_CONFIGURE_ACK);
304  }
305  }
306 
307  //Return status code
308  return error;
309 }
310 
311 
312 /**
313  * @brief Process Configure-Ack packet
314  * @param[in] context PPP context
315  * @param[in] configureAckPacket Packet received from the peer
316  * @return Error code
317  **/
318 
320  const PppConfigurePacket *configureAckPacket)
321 {
322  //Debug message
323  TRACE_INFO("\r\nIPCP Receive-Configure-Ack event\r\n");
324 
325  //When a packet is received with an invalid Identifier field, the
326  //packet is silently discarded without affecting the automaton
327  if(configureAckPacket->identifier != context->ipcpFsm.identifier)
328  return ERROR_WRONG_IDENTIFIER;
329 
330  //A valid Configure-Ack packet has been received from the peer
331  pppRcvConfigureAckEvent(context, &context->ipcpFsm, &ipcpCallbacks);
332 
333  //Successful processing
334  return NO_ERROR;
335 }
336 
337 
338 /**
339  * @brief Process Configure-Nak packet
340  * @param[in] context PPP context
341  * @param[in] configureNakPacket Packet received from the peer
342  * @return Error code
343  **/
344 
346  const PppConfigurePacket *configureNakPacket)
347 {
348  size_t length;
349  PppOption *option;
350 
351  //Debug message
352  TRACE_INFO("IPCP Receive-Configure-Nak event\r\n");
353 
354  //When a packet is received with an invalid Identifier field, the
355  //packet is silently discarded without affecting the automaton
356  if(configureNakPacket->identifier != context->ipcpFsm.identifier)
357  return ERROR_WRONG_IDENTIFIER;
358 
359  //Retrieve the length of the option list
360  length = ntohs(configureNakPacket->length) - sizeof(PppConfigurePacket);
361  //Point to the first option
362  option = (PppOption *) configureNakPacket->options;
363 
364  //Parse configuration options
365  while(length > 0)
366  {
367  //Check option length
368  if(option->length < sizeof(PppOption))
369  return ERROR_INVALID_LENGTH;
370  if(option->length > length)
371  return ERROR_INVALID_LENGTH;
372 
373  //IP-Address option?
374  if(option->type == IPCP_OPTION_IP_ADDRESS)
375  {
376  //Cast option
377  IpcpIpAddressOption *ipAddressOption = (IpcpIpAddressOption *) option;
378 
379  //Check option length
380  if(ipAddressOption->length != sizeof(IpcpIpAddressOption))
381  return ERROR_INVALID_LENGTH;
382 
383  //Save IP address
384  context->localConfig.ipAddr = ipAddressOption->ipAddr;
385  }
386  //Primary-DNS-Server-Address option?
387  else if(option->type == IPCP_OPTION_PRIMARY_DNS)
388  {
389  //Cast option
390  IpcpPrimaryDnsOption *primaryDns = (IpcpPrimaryDnsOption *) option;
391 
392  //Check option length
393  if(primaryDns->length != sizeof(IpcpPrimaryDnsOption))
394  return ERROR_INVALID_LENGTH;
395 
396  //Save primary DNS server address
397  context->localConfig.primaryDns = primaryDns->ipAddr;
398  }
399  //Secondary-DNS-Server-Address option?
400  else if(option->type == IPCP_OPTION_SECONDARY_DNS)
401  {
402  //Cast option
403  IpcpSecondaryDnsOption *secondaryDns = (IpcpSecondaryDnsOption *) option;
404 
405  //Check option length
406  if(secondaryDns->length != sizeof(IpcpSecondaryDnsOption))
407  return ERROR_INVALID_LENGTH;
408 
409  //Save secondary DNS server address
410  context->localConfig.secondaryDns = secondaryDns->ipAddr;
411  }
412 
413  //Remaining bytes to process
414  length -= option->length;
415  //Jump to the next option
416  option = (PppOption *) ((uint8_t *) option + option->length);
417  }
418 
419  //A valid Configure-Nak or Configure-Reject packet has been received from the peer
420  pppRcvConfigureNakEvent(context, &context->ipcpFsm, &ipcpCallbacks);
421 
422  //Successful processing
423  return NO_ERROR;
424 }
425 
426 
427 /**
428  * @brief Process Configure-Reject packet
429  * @param[in] context PPP context
430  * @param[in] configureRejPacket Packet received from the peer
431  * @return Error code
432  **/
433 
435  const PppConfigurePacket *configureRejPacket)
436 {
437  size_t length;
438  PppOption *option;
439 
440  //Debug message
441  TRACE_INFO("\r\nIPCP Receive-Configure-Reject event\r\n");
442 
443  //When a packet is received with an invalid Identifier field, the
444  //packet is silently discarded without affecting the automaton
445  if(configureRejPacket->identifier != context->ipcpFsm.identifier)
446  return ERROR_WRONG_IDENTIFIER;
447 
448  //Retrieve the length of the option list
449  length = ntohs(configureRejPacket->length) - sizeof(PppConfigurePacket);
450  //Point to the first option
451  option = (PppOption *) configureRejPacket->options;
452 
453  //Parse configuration options
454  while(length > 0)
455  {
456  //Check option length
457  if(option->length < sizeof(PppOption))
458  return ERROR_INVALID_LENGTH;
459  if(option->length > length)
460  return ERROR_INVALID_LENGTH;
461 
462  //IP-Address option?
463  if(option->type == IPCP_OPTION_IP_ADDRESS)
464  {
465  //The option is not recognized by the peer
466  context->localConfig.ipAddrRejected = TRUE;
467  }
468  //Primary-DNS-Server-Address option?
469  else if(option->type == IPCP_OPTION_PRIMARY_DNS)
470  {
471  //The option is not recognized by the peer
472  context->localConfig.primaryDnsRejected = TRUE;
473  }
474  //Secondary-DNS-Server-Address option?
475  else if(option->type == IPCP_OPTION_SECONDARY_DNS)
476  {
477  //The option is not recognized by the peer
478  context->localConfig.secondaryDnsRejected = TRUE;
479  }
480 
481  //Remaining bytes to process
482  length -= option->length;
483  //Jump to the next option
484  option = (PppOption *) ((uint8_t *) option + option->length);
485  }
486 
487  //A valid Configure-Nak or Configure-Reject packet has been received from the peer
488  pppRcvConfigureNakEvent(context, &context->ipcpFsm, &ipcpCallbacks);
489 
490  //Successful processing
491  return NO_ERROR;
492 }
493 
494 
495 /**
496  * @brief Process Terminate-Request packet
497  * @param[in] context PPP context
498  * @param[in] terminateReqPacket Packet received from the peer
499  * @return Error code
500  **/
501 
503  const PppTerminatePacket *terminateReqPacket)
504 {
505  //Debug message
506  TRACE_INFO("\r\nIPCP Receive-Terminate-Request event\r\n");
507 
508  //The Terminate-Request indicates the desire of the peer to close the connection
509  pppRcvTerminateReqEvent(context, &context->ipcpFsm,
510  &ipcpCallbacks, terminateReqPacket);
511 
512  //Successful processing
513  return NO_ERROR;
514 }
515 
516 
517 /**
518  * @brief Process Terminate-Ack packet
519  * @param[in] context PPP context
520  * @param[in] terminateAckPacket Packet received from the peer
521  * @return Error code
522  **/
523 
525  const PppTerminatePacket *terminateAckPacket)
526 {
527  //Debug message
528  TRACE_INFO("\r\nIPCP Receive-Terminate-Ack event\r\n");
529 
530  //The Terminate-Ack packet is usually a response to a Terminate-Request
531  //packet. This packet may also indicate that the peer is in Closed or
532  //Stopped states, and serves to re-synchronize the link configuration
533  pppRcvTerminateAckEvent(context, &context->ipcpFsm, &ipcpCallbacks);
534 
535  //Successful processing
536  return NO_ERROR;
537 }
538 
539 
540 /**
541  * @brief Process Code-Reject packet
542  * @param[in] context PPP context
543  * @param[in] codeRejPacket Packet received from the peer
544  * @return Error code
545  **/
546 
548  const PppCodeRejPacket *codeRejPacket)
549 {
550  size_t length;
551  PppPacket *packet;
552 
553  //Debug message
554  TRACE_INFO("\r\nIPCP Receive-Code-Reject event\r\n");
555 
556  //Point to the rejected packet
557  packet = (PppPacket *) codeRejPacket->rejectedPacket;
558  //Retrieve the length of the rejected packet
559  length = ntohs(codeRejPacket->length) - sizeof(PppCodeRejPacket);
560 
561  //Make sure the length of the rejected packet is valid
562  if(length < sizeof(PppPacket))
563  return ERROR_INVALID_LENGTH;
564 
565  //Check whether the rejected value is acceptable or catastrophic
566  if(packet->code < PPP_CODE_CONFIGURE_REQ ||
567  packet->code > PPP_CODE_CODE_REJ)
568  {
569  //The RXJ+ event arises when the rejected value is acceptable, such
570  //as a Code-Reject of an extended code, or a Protocol-Reject of a
571  //NCP. These are within the scope of normal operation
572  pppRcvCodeRejEvent(context, &context->ipcpFsm, &ipcpCallbacks, TRUE);
573  }
574  else
575  {
576  //The RXJ- event arises when the rejected value is catastrophic, such
577  //as a Code-Reject of Configure-Request! This event communicates an
578  //unrecoverable error that terminates the connection
579  pppRcvCodeRejEvent(context, &context->ipcpFsm, &ipcpCallbacks, FALSE);
580  }
581 
582  //Successful processing
583  return NO_ERROR;
584 }
585 
586 
587 /**
588  * @brief Process packet with unknown code
589  * @param[in] context PPP context
590  * @param[in] packet Un-interpretable packet received from the peer
591  * @return Error code
592  **/
593 
595  const PppPacket *packet)
596 {
597  //Debug message
598  TRACE_INFO("\r\nIPCP Receive-Unknown-Code event\r\n");
599 
600  //This event occurs when an un-interpretable packet is received from
601  //the peer. A Code-Reject packet is sent in response
602  pppRcvUnknownCodeEvent(context, &context->ipcpFsm, &ipcpCallbacks, packet);
603 
604  //Successful processing
605  return NO_ERROR;
606 }
607 
608 
609 /**
610  * @brief This-Layer-Up callback function
611  * @param[in] context PPP context
612  **/
613 
615 {
616  NetInterface *interface;
617 
618  //Debug message
619  TRACE_INFO("IPCP This-Layer-Up callback\r\n");
620 
621  //Debug message
622  TRACE_INFO(" Local IP Addr = %s\r\n", ipv4AddrToString(context->localConfig.ipAddr, NULL));
623  TRACE_INFO(" Peer IP Addr = %s\r\n", ipv4AddrToString(context->peerConfig.ipAddr, NULL));
624  TRACE_INFO(" Primary DNS = %s\r\n", ipv4AddrToString(context->localConfig.primaryDns, NULL));
625  TRACE_INFO(" Secondary DNS = %s\r\n", ipv4AddrToString(context->localConfig.secondaryDns, NULL));
626 
627  //Point to the underlying interface
628  interface = context->interface;
629 
630  //Update IPv4 configuration
631  interface->ipv4Context.addr = context->localConfig.ipAddr;
632  interface->ipv4Context.addrState = IPV4_ADDR_STATE_VALID;
633  interface->ipv4Context.defaultGateway = context->peerConfig.ipAddr;
634 
635  //Update the list of DNS servers
636  interface->ipv4Context.dnsServerList[0] = context->localConfig.primaryDns;
637 #if (IPV4_DNS_SERVER_LIST_SIZE >= 2)
638  interface->ipv4Context.dnsServerList[1] = context->localConfig.secondaryDns;
639 #endif
640 
641  //All the outgoing traffic will be routed to the other end of the link
642  interface->ipv4Context.subnetMask = IPCP_DEFAULT_SUBNET_MASK;
643 
644  //Link is up
645  interface->linkState = TRUE;
646 
647  //Disable interrupts
648  interface->nicDriver->disableIrq(interface);
649  //Process link state change event
650  nicNotifyLinkChange(interface);
651  //Re-enable interrupts
652  interface->nicDriver->enableIrq(interface);
653 }
654 
655 
656 /**
657  * @brief This-Layer-Down callback function
658  * @param[in] context PPP context
659  **/
660 
662 {
663  NetInterface *interface;
664 
665  //Debug message
666  TRACE_INFO("IPCP This-Layer-Down callback\r\n");
667 
668  //Point to the underlying interface
669  interface = context->interface;
670 
671  //Link is up
672  interface->linkState = FALSE;
673 
674  //Disable interrupts
675  interface->nicDriver->disableIrq(interface);
676  //Process link state change event
677  nicNotifyLinkChange(interface);
678  //Re-enable interrupts
679  interface->nicDriver->enableIrq(interface);
680 }
681 
682 
683 /**
684  * @brief This-Layer-Started callback function
685  * @param[in] context PPP context
686  **/
687 
689 {
690  //Debug message
691  TRACE_INFO("IPCP This-Layer-Started callback\r\n");
692 }
693 
694 
695 /**
696  * @brief This-Layer-Finished callback function
697  * @param[in] context PPP context
698  **/
699 
701 {
702  //Debug message
703  TRACE_INFO("IPCP This-Layer-Finished callback\r\n");
704 }
705 
706 
707 /**
708  * @brief Initialize-Restart-Count callback function
709  * @param[in] context PPP context
710  * @param[in] value Restart counter value
711  **/
712 
714 {
715  //Debug message
716  TRACE_INFO("IPCP Initialize-Restart-Count callback\r\n");
717 
718  //Initialize restart counter
719  context->ipcpFsm.restartCounter = value;
720 }
721 
722 
723 /**
724  * @brief Zero-Restart-Count callback function
725  * @param[in] context PPP context
726  **/
727 
729 {
730  //Debug message
731  TRACE_INFO("IPCP Zero-Restart-Count callback\r\n");
732 
733  //Zero restart counter
734  context->ipcpFsm.restartCounter = 0;
735 
736  //The receiver of a Terminate-Request should wait for the peer to
737  //disconnect, and must not disconnect until at least one Restart
738  //time has passed after sending a Terminate-Ack
739  context->ipcpFsm.timestamp = osGetSystemTime();
740 }
741 
742 
743 /**
744  * @brief Send-Configure-Request callback function
745  * @param[in] context PPP context
746  * @return Error code
747  **/
748 
750 {
751  error_t error;
752  size_t length;
753  size_t offset;
754  NetBuffer *buffer;
755  PppConfigurePacket *configureReqPacket;
756 
757  //Debug message
758  TRACE_INFO("IPCP Send-Configure-Request callback\r\n");
759 
760  //Allocate a buffer memory to hold the Configure-Request packet
761  buffer = pppAllocBuffer(PPP_MAX_CONF_REQ_SIZE, &offset);
762  //Failed to allocate memory?
763  if(buffer == NULL)
764  return ERROR_OUT_OF_MEMORY;
765 
766  //Point to the Configure-Request packet
767  configureReqPacket = netBufferAt(buffer, offset);
768 
769  //Format packet header
770  configureReqPacket->code = PPP_CODE_CONFIGURE_REQ;
771  configureReqPacket->identifier = ++context->ipcpFsm.identifier;
772  configureReqPacket->length = sizeof(PppConfigurePacket);
773 
774  //Make sure the IP-Address option has not been previously rejected
775  if(!context->localConfig.ipAddrRejected)
776  {
777  //Add option
778  pppAddOption(configureReqPacket, IPCP_OPTION_IP_ADDRESS,
779  &context->localConfig.ipAddr, sizeof(Ipv4Addr));
780  }
781 
782  //Make sure the Primary-DNS-Server-Address option has not been
783  //previously rejected
784  if(!context->localConfig.primaryDnsRejected)
785  {
786  //Add option
787  pppAddOption(configureReqPacket, IPCP_OPTION_PRIMARY_DNS,
788  &context->localConfig.primaryDns, sizeof(Ipv4Addr));
789  }
790 
791  //Make sure the Secondary-DNS-Server-Address option has not been
792  //previously rejected
793  if(!context->localConfig.secondaryDnsRejected)
794  {
795  //Add option
796  pppAddOption(configureReqPacket, IPCP_OPTION_SECONDARY_DNS,
797  &context->localConfig.secondaryDns, sizeof(Ipv4Addr));
798  }
799 
800  //Save packet length
801  length = configureReqPacket->length;
802  //Convert length field to network byte order
803  configureReqPacket->length = htons(length);
804 
805  //Adjust the length of the multi-part buffer
806  netBufferSetLength(buffer, offset + length);
807 
808  //Debug message
809  TRACE_INFO("Sending Configure-Request packet (%" PRIuSIZE " bytes)...\r\n", length);
810  //Dump packet contents for debugging purpose
811  pppDumpPacket((PppPacket *) configureReqPacket, length, PPP_PROTOCOL_IPCP);
812 
813  //Send PPP frame
814  error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_IPCP);
815 
816  //The restart counter is decremented each time a Configure-Request is sent
817  if(context->ipcpFsm.restartCounter > 0)
818  context->ipcpFsm.restartCounter--;
819 
820  //Save the time at which the packet was sent
821  context->ipcpFsm.timestamp = osGetSystemTime();
822 
823  //Free previously allocated memory block
824  netBufferFree(buffer);
825  //Return status code
826  return error;
827 }
828 
829 
830 /**
831  * @brief Send-Configure-Ack callback function
832  * @param[in] context PPP context
833  * @param[in] configureReqPacket Configure-Request packet received from the peer
834  * @return Error code
835  **/
836 
838  const PppConfigurePacket *configureReqPacket)
839 {
840  //Debug message
841  TRACE_INFO("IPCP Send-Configure-Ack callback\r\n");
842 
843  //Send Configure-Ack packet
844  return pppSendConfigureAckNak(context, configureReqPacket,
846 }
847 
848 
849 /**
850  * @brief Send-Configure-Nak callback function
851  * @param[in] context PPP context
852  * @param[in] configureReqPacket Configure-Request packet received from the peer
853  * @return Error code
854  **/
855 
857  const PppConfigurePacket *configureReqPacket)
858 {
859  //Debug message
860  TRACE_INFO("IPCP Send-Configure-Nak callback\r\n");
861 
862  //Send Configure-Nak packet
863  return pppSendConfigureAckNak(context, configureReqPacket,
865 }
866 
867 
868 /**
869  * @brief Send-Configure-Reject callback function
870  * @param[in] context PPP context
871  * @param[in] configureReqPacket Configure-Request packet received from the peer
872  * @return Error code
873  **/
874 
876  const PppConfigurePacket *configureReqPacket)
877 {
878  //Debug message
879  TRACE_INFO("IPCP Send-Configure-Reject callback\r\n");
880 
881  //Send Configure-Reject packet
882  return pppSendConfigureAckNak(context, configureReqPacket,
884 }
885 
886 
887 /**
888  * @brief Send-Terminate-Request callback function
889  * @param[in] context PPP context
890  * @return Error code
891  **/
892 
894 {
895  error_t error;
896 
897  //Debug message
898  TRACE_INFO("IPCP Send-Terminate-Request callback\r\n");
899 
900  //On transmission, the Identifier field must be changed
901  context->ipcpFsm.identifier++;
902 
903  //Send Terminate-Request packet
904  error = pppSendTerminateReq(context, context->ipcpFsm.identifier, PPP_PROTOCOL_IPCP);
905 
906  //The restart counter is decremented each time a Terminate-Request is sent
907  if(context->ipcpFsm.restartCounter > 0)
908  context->ipcpFsm.restartCounter--;
909 
910  //Save the time at which the packet was sent
911  context->ipcpFsm.timestamp = osGetSystemTime();
912 
913  //Return status code
914  return error;
915 }
916 
917 
918 /**
919  * @brief Send-Terminate-Ack callback function
920  * @param[in] context PPP context
921  * @param[in] terminateReqPacket Terminate-Request packet received from the peer
922  * @return Error code
923  **/
924 
926  const PppTerminatePacket *terminateReqPacket)
927 {
928  uint8_t identifier;
929 
930  //Debug message
931  TRACE_INFO("IPCP Send-Terminate-Ack callback\r\n");
932 
933  //Check whether this Terminate-Ack acknowledges the reception of a
934  //Terminate-Request packet
935  if(terminateReqPacket != NULL)
936  {
937  //The Identifier field of the Terminate-Request is copied into the
938  //Identifier field of the Terminate-Ack packet
939  identifier = terminateReqPacket->identifier;
940  }
941  else
942  {
943  //This Terminate-Ack packet serves to synchronize the automatons
944  identifier = ++context->ipcpFsm.identifier;
945  }
946 
947  //Send Terminate-Ack packet
949 }
950 
951 
952 /**
953  * @brief Send-Code-Reject callback function
954  * @param[in] context PPP context
955  * @param[in] packet Un-interpretable packet received from the peer
956  * @return Error code
957  **/
958 
959 error_t ipcpSendCodeRej(PppContext *context, const PppPacket *packet)
960 {
961  //Debug message
962  TRACE_INFO("IPCP Send-Code-Reject callback\r\n");
963 
964  //The Identifier field must be changed for each Code-Reject sent
965  context->ipcpFsm.identifier++;
966 
967  //Send Code-Reject packet
968  return pppSendCodeRej(context, packet, context->ipcpFsm.identifier, PPP_PROTOCOL_IPCP);
969 }
970 
971 
972 /**
973  * @brief Parse IPCP configuration option
974  * @param[in] context PPP context
975  * @param[in] option Option to be checked
976  * @param[in] inPacketLen Remaining bytes to process in the incoming packet
977  * @param[out] outPacket Pointer to the Configure-Ack, Nak or Reject packet
978  * @return Error code
979  **/
980 
982  size_t inPacketLen, PppConfigurePacket *outPacket)
983 {
984  error_t error;
985 
986  //Malformed IPCP packet?
987  if(inPacketLen < sizeof(PppOption))
988  return ERROR_INVALID_LENGTH;
989 
990  //Check option length
991  if(option->length < sizeof(PppOption))
992  return ERROR_INVALID_LENGTH;
993  if(option->length > inPacketLen)
994  return ERROR_INVALID_LENGTH;
995 
996  //Check option type
997  switch(option->type)
998  {
1000  //Check IP-Address option
1001  error = ipcpParseIpAddressOption(context, (IpcpIpAddressOption *) option, outPacket);
1002  break;
1003  default:
1004  //If some configuration options received in the Configure-Request are not
1005  //recognizable or not acceptable for negotiation, then the implementation
1006  //must transmit a Configure-Reject
1007  if(outPacket->code == PPP_CODE_CONFIGURE_REJ)
1008  {
1009  //The options field of the Configure-Reject packet is filled
1010  //with the unrecognized options from the Configure-Request
1011  pppAddOption(outPacket, option->type, option->data,
1012  option->length - sizeof(PppOption));
1013  }
1014 
1015  //The option is not acceptable for negotiation
1016  error = ERROR_INVALID_TYPE;
1017  break;
1018  }
1019 
1020  //Return status code
1021  return error;
1022 }
1023 
1024 
1025 /**
1026  * @brief Parse IP-Address option
1027  * @param[in] context PPP context
1028  * @param[in] option Option to be checked
1029  * @param[out] outPacket Pointer to the Configure-Nak or Configure-Reject packet
1030  * @return Error code
1031  **/
1032 
1034  IpcpIpAddressOption *option, PppConfigurePacket *outPacket)
1035 {
1036  error_t error;
1037 
1038  //Check length field
1039  if(option->length == sizeof(IpcpIpAddressOption))
1040  {
1041  //Check whether the option value is acceptable
1042  if(option->ipAddr != IPV4_UNSPECIFIED_ADDR)
1043  {
1044  //If every configuration option received in the Configure-Request is
1045  //recognizable and all values are acceptable, then the implementation
1046  //must transmit a Configure-Ack
1047  if(outPacket != NULL && outPacket->code == PPP_CODE_CONFIGURE_ACK)
1048  {
1049  //Save IP address
1050  context->peerConfig.ipAddr = option->ipAddr;
1051 
1052  //The options field of the Configure-Ack packet contains the
1053  //configuration options that the sender is acknowledging
1055  (void *) &option->ipAddr, option->length - sizeof(PppOption));
1056  }
1057 
1058  //The value is acceptable
1059  error = NO_ERROR;
1060  }
1061  else
1062  {
1063  //If all configuration options are recognizable, but some values are not
1064  //acceptable, then the implementation must transmit a Configure-Nak
1065  if(outPacket != NULL && outPacket->code == PPP_CODE_CONFIGURE_NAK)
1066  {
1067  //The option must be modified to a value acceptable to the
1068  //Configure-Nak sender
1070  &context->peerConfig.ipAddr, sizeof(Ipv4Addr));
1071  }
1072 
1073  //The value is not acceptable
1074  error = ERROR_INVALID_VALUE;
1075  }
1076  }
1077  else
1078  {
1079  //Invalid length field
1080  error = ERROR_INVALID_LENGTH;
1081  }
1082 
1083  //Return status code
1084  return error;
1085 }
1086 
1087 #endif
An address assigned to an interface whose use is unrestricted.
Definition: ipv4.h:184
__start_packed struct @289 PppTerminatePacket
Terminate-Request and Terminate-Ack packet.
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:232
uint32_t systime_t
Definition: compiler_port.h:44
void pppOpenEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Open event.
Definition: ppp_fsm.c:133
Terminate-Request.
Definition: ppp.h:218
void nicNotifyLinkChange(NetInterface *interface)
Process link state change event.
Definition: nic.c:298
char_t * ipv4AddrToString(Ipv4Addr ipAddr, char_t *str)
Convert a binary IPv4 address to dot-decimal notation.
Definition: ipv4.c:1785
#define PPP_MAX_CONF_REQ_SIZE
Definition: ppp.h:138
error_t ipcpProcessConfigureAck(PppContext *context, const PppConfigurePacket *configureAckPacket)
Process Configure-Ack packet.
Definition: ipcp.c:319
error_t ipcpClose(PppContext *context)
IPCP Close event.
Definition: ipcp.c:95
const PppCallbacks ipcpCallbacks
IPCP FSM callbacks.
Definition: ipcp.c:49
void pppRcvTerminateAckEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Receive-Terminate-Ack event.
Definition: ppp_fsm.c:695
systime_t osGetSystemTime(void)
Retrieve system time.
Code-Reject.
Definition: ppp.h:220
uint32_t time
Data logging functions for debugging purpose (PPP)
TCP/IP stack core.
PPP miscellaneous functions.
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:280
Debugging facilities.
error_t ipcpProcessTerminateAck(PppContext *context, const PppTerminatePacket *terminateAckPacket)
Process Terminate-Ack packet.
Definition: ipcp.c:524
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:318
__start_packed struct @290 PppCodeRejPacket
Code-Reject packet.
error_t ipcpSendTerminateReq(PppContext *context)
Send-Terminate-Request callback function.
Definition: ipcp.c:893
error_t ipcpProcessConfigureNak(PppContext *context, const PppConfigurePacket *configureNakPacket)
Process Configure-Nak packet.
Definition: ipcp.c:345
Terminate-Ack.
Definition: ppp.h:219
error_t pppSendCodeRej(PppContext *context, const PppPacket *packet, uint8_t identifier, PppProtocol protocol)
Send Code-Reject packet.
Definition: ppp_misc.c:263
#define htons(value)
Definition: cpu_endian.h:390
PPP FSM actions.
Definition: ppp_fsm.h:150
__start_packed struct @274 IpcpSecondaryDnsOption
Secondary-DNS-Server-Address option.
error_t ipcpProcessConfigureReject(PppContext *context, const PppConfigurePacket *configureRejPacket)
Process Configure-Reject packet.
Definition: ipcp.c:434
void pppRcvTerminateReqEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks, const PppTerminatePacket *terminateReqPacket)
Process Receive-Terminate-Req event.
Definition: ppp_fsm.c:646
__start_packed struct @272 IpcpPrimaryDnsOption
Primary-DNS-Server-Address option.
#define PppPacket
Definition: ppp.h:35
error_t ipcpSendConfigureNak(PppContext *context, const PppConfigurePacket *configureReqPacket)
Send-Configure-Nak callback function.
Definition: ipcp.c:856
IP Control Protocol.
Definition: ppp.h:199
error_t ipcpOpen(PppContext *context)
IPCP Open event.
Definition: ipcp.c:74
error_t ipcpParseOption(PppContext *context, PppOption *option, size_t inPacketLen, PppConfigurePacket *outPacket)
Parse IPCP configuration option.
Definition: ipcp.c:981
void ipcpThisLayerUp(PppContext *context)
This-Layer-Up callback function.
Definition: ipcp.c:614
error_t ipcpProcessConfigureReq(PppContext *context, const PppConfigurePacket *configureReqPacket)
Process Configure-Request packet.
Definition: ipcp.c:223
void ipcpZeroRestartCount(PppContext *context)
Zero-Restart-Count callback function.
Definition: ipcp.c:728
#define TRUE
Definition: os_port.h:48
__start_packed struct @294 PppOption
LCP/NCP option.
Configure-Request.
Definition: ppp.h:214
void pppUpEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Up event.
Definition: ppp_fsm.c:48
#define ntohs(value)
Definition: cpu_endian.h:396
#define IPCP_DEFAULT_SUBNET_MASK
Definition: ipcp.h:37
void ipcpInitRestartCount(PppContext *context, uint_t value)
Initialize-Restart-Count callback function.
Definition: ipcp.c:713
void ipcpThisLayerFinished(PppContext *context)
This-Layer-Finished callback function.
Definition: ipcp.c:700
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:411
error_t ipcpSendConfigureRej(PppContext *context, const PppConfigurePacket *configureReqPacket)
Send-Configure-Reject callback function.
Definition: ipcp.c:875
IPv4 (Internet Protocol Version 4)
__start_packed struct @271 IpcpIpAddressOption
IP-Address option.
void ipcpThisLayerDown(PppContext *context)
This-Layer-Down callback function.
Definition: ipcp.c:661
void ipcpProcessPacket(PppContext *context, const PppPacket *packet, size_t length)
Process an incoming IPCP packet.
Definition: ipcp.c:149
void pppRcvConfigureAckEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Receive-Configure-Ack event.
Definition: ppp_fsm.c:522
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:86
void pppDownEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Down event.
Definition: ppp_fsm.c:82
error_t pppSendTerminateAck(PppContext *context, uint8_t identifier, PppProtocol protocol)
Send Terminate-Ack packet.
Definition: ppp_misc.c:213
void pppRcvConfigureReqEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks, const PppConfigurePacket *configureReqPacket, PppCode code)
Process Receive-Configure-Request event.
Definition: ppp_fsm.c:333
uint8_t identifier[]
error_t ipcpSendCodeRej(PppContext *context, const PppPacket *packet)
Send-Code-Reject callback function.
Definition: ipcp.c:959
error_t ipcpProcessUnknownCode(PppContext *context, const PppPacket *packet)
Process packet with unknown code.
Definition: ipcp.c:594
void ipcpThisLayerStarted(PppContext *context)
This-Layer-Started callback function.
Definition: ipcp.c:688
#define PppContext
Definition: ppp.h:36
#define TRACE_INFO(...)
Definition: debug.h:86
Success.
Definition: error.h:42
error_t ipcpSendConfigureAck(PppContext *context, const PppConfigurePacket *configureReqPacket)
Send-Configure-Ack callback function.
Definition: ipcp.c:837
PPP finite state machine.
error_t ipcpSendConfigureReq(PppContext *context)
Send-Configure-Request callback function.
Definition: ipcp.c:749
Configure-Ack.
Definition: ppp.h:215
error_t ipcpProcessCodeRej(PppContext *context, const PppCodeRejPacket *codeRejPacket)
Process Code-Reject packet.
Definition: ipcp.c:547
error_t ipcpProcessTerminateReq(PppContext *context, const PppTerminatePacket *terminateReqPacket)
Process Terminate-Request packet.
Definition: ipcp.c:502
error_t
Error codes.
Definition: error.h:40
Secondary-DNS-Server-Address.
Definition: ipcp.h:56
unsigned int uint_t
Definition: compiler_port.h:43
IP-Address.
Definition: ipcp.h:53
#define PRIuSIZE
Definition: compiler_port.h:72
#define NetInterface
Definition: net.h:34
error_t pppDumpPacket(const PppPacket *packet, size_t length, PppProtocol protocol)
Dump LCP/NCP packet for debugging purpose.
Definition: ppp_debug.c:141
void pppRcvUnknownCodeEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks, const PppPacket *packet)
Process Receive-Unknown-Code event.
Definition: ppp_fsm.c:755
uint8_t value[]
Definition: dtls_misc.h:141
void pppRcvConfigureNakEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Receive-Configure-Nak event.
Definition: ppp_fsm.c:584
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:95
error_t pppSendFrame(NetInterface *interface, NetBuffer *buffer, size_t offset, uint16_t protocol)
Send a PPP frame.
Definition: ppp.c:1004
error_t ipcpSendTerminateAck(PppContext *context, const PppTerminatePacket *terminateReqPacket)
Send-Terminate-Ack callback function.
Definition: ipcp.c:925
error_t ipcpParseIpAddressOption(PppContext *context, IpcpIpAddressOption *option, PppConfigurePacket *outPacket)
Parse IP-Address option.
Definition: ipcp.c:1033
void pppTimeoutEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Timeout event.
Definition: ppp_fsm.c:255
error_t pppSendConfigureAckNak(PppContext *context, const PppConfigurePacket *configureReqPacket, PppProtocol protocol, PppCode code)
Send Configure-Ack, Nak or Reject packet.
Definition: ppp_misc.c:54
error_t pppSendTerminateReq(PppContext *context, uint8_t identifier, PppProtocol protocol)
Send Terminate-Request packet.
Definition: ppp_misc.c:164
uint8_t length
Definition: dtls_misc.h:140
Primary-DNS-Server-Address.
Definition: ipcp.h:54
void pppRcvCodeRejEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks, bool_t acceptable)
Process Receive-Code-Reject or Receive-Protocol-Reject event.
Definition: ppp_fsm.c:790
Configure-Nak.
Definition: ppp.h:216
Configure-Reject.
Definition: ppp.h:217
#define PPP_RESTART_TIMER
Definition: ppp.h:94
__start_packed struct @288 PppConfigurePacket
Configure-Request, Configure-Ack, Configure-Nak and Configure-Reject packets.
#define FALSE
Definition: os_port.h:44
IPCP (PPP Internet Protocol Control Protocol)
void ipcpTick(PppContext *context)
IPCP timer handler.
Definition: ipcp.c:119
int bool_t
Definition: compiler_port.h:47
void pppCloseEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Close event.
Definition: ppp_fsm.c:187
error_t pppAddOption(PppConfigurePacket *packet, uint8_t optionType, const void *optionValue, uint8_t optionLen)
Add an option to a Configure packet.
Definition: ppp_misc.c:446
NetBuffer * pppAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold a PPP frame.
Definition: ppp.c:1263