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