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.4
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, 0);
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 
828  //Return status code
829  return error;
830 }
831 
832 
833 /**
834  * @brief Send-Configure-Ack callback function
835  * @param[in] context PPP context
836  * @param[in] configureReqPacket Configure-Request packet received from the peer
837  * @return Error code
838  **/
839 
841  const PppConfigurePacket *configureReqPacket)
842 {
843  //Debug message
844  TRACE_INFO("IPCP Send-Configure-Ack callback\r\n");
845 
846  //Send Configure-Ack packet
847  return pppSendConfigureAckNak(context, configureReqPacket,
849 }
850 
851 
852 /**
853  * @brief Send-Configure-Nak callback function
854  * @param[in] context PPP context
855  * @param[in] configureReqPacket Configure-Request packet received from the peer
856  * @return Error code
857  **/
858 
860  const PppConfigurePacket *configureReqPacket)
861 {
862  //Debug message
863  TRACE_INFO("IPCP Send-Configure-Nak callback\r\n");
864 
865  //Send Configure-Nak packet
866  return pppSendConfigureAckNak(context, configureReqPacket,
868 }
869 
870 
871 /**
872  * @brief Send-Configure-Reject callback function
873  * @param[in] context PPP context
874  * @param[in] configureReqPacket Configure-Request packet received from the peer
875  * @return Error code
876  **/
877 
879  const PppConfigurePacket *configureReqPacket)
880 {
881  //Debug message
882  TRACE_INFO("IPCP Send-Configure-Reject callback\r\n");
883 
884  //Send Configure-Reject packet
885  return pppSendConfigureAckNak(context, configureReqPacket,
887 }
888 
889 
890 /**
891  * @brief Send-Terminate-Request callback function
892  * @param[in] context PPP context
893  * @return Error code
894  **/
895 
897 {
898  error_t error;
899 
900  //Debug message
901  TRACE_INFO("IPCP Send-Terminate-Request callback\r\n");
902 
903  //On transmission, the Identifier field must be changed
904  context->ipcpFsm.identifier++;
905 
906  //Send Terminate-Request packet
907  error = pppSendTerminateReq(context, context->ipcpFsm.identifier, PPP_PROTOCOL_IPCP);
908 
909  //The restart counter is decremented each time a Terminate-Request is sent
910  if(context->ipcpFsm.restartCounter > 0)
911  context->ipcpFsm.restartCounter--;
912 
913  //Save the time at which the packet was sent
914  context->ipcpFsm.timestamp = osGetSystemTime();
915 
916  //Return status code
917  return error;
918 }
919 
920 
921 /**
922  * @brief Send-Terminate-Ack callback function
923  * @param[in] context PPP context
924  * @param[in] terminateReqPacket Terminate-Request packet received from the peer
925  * @return Error code
926  **/
927 
929  const PppTerminatePacket *terminateReqPacket)
930 {
931  uint8_t identifier;
932 
933  //Debug message
934  TRACE_INFO("IPCP Send-Terminate-Ack callback\r\n");
935 
936  //Check whether this Terminate-Ack acknowledges the reception of a
937  //Terminate-Request packet
938  if(terminateReqPacket != NULL)
939  {
940  //The Identifier field of the Terminate-Request is copied into the
941  //Identifier field of the Terminate-Ack packet
942  identifier = terminateReqPacket->identifier;
943  }
944  else
945  {
946  //This Terminate-Ack packet serves to synchronize the automatons
947  identifier = ++context->ipcpFsm.identifier;
948  }
949 
950  //Send Terminate-Ack packet
952 }
953 
954 
955 /**
956  * @brief Send-Code-Reject callback function
957  * @param[in] context PPP context
958  * @param[in] packet Un-interpretable packet received from the peer
959  * @return Error code
960  **/
961 
962 error_t ipcpSendCodeRej(PppContext *context, const PppPacket *packet)
963 {
964  //Debug message
965  TRACE_INFO("IPCP Send-Code-Reject callback\r\n");
966 
967  //The Identifier field must be changed for each Code-Reject sent
968  context->ipcpFsm.identifier++;
969 
970  //Send Code-Reject packet
971  return pppSendCodeRej(context, packet, context->ipcpFsm.identifier, PPP_PROTOCOL_IPCP);
972 }
973 
974 
975 /**
976  * @brief Parse IPCP configuration option
977  * @param[in] context PPP context
978  * @param[in] option Option to be checked
979  * @param[in] inPacketLen Remaining bytes to process in the incoming packet
980  * @param[out] outPacket Pointer to the Configure-Ack, Nak or Reject packet
981  * @return Error code
982  **/
983 
985  size_t inPacketLen, PppConfigurePacket *outPacket)
986 {
987  error_t error;
988 
989  //Malformed IPCP packet?
990  if(inPacketLen < sizeof(PppOption))
991  return ERROR_INVALID_LENGTH;
992 
993  //Check option length
994  if(option->length < sizeof(PppOption))
995  return ERROR_INVALID_LENGTH;
996  if(option->length > inPacketLen)
997  return ERROR_INVALID_LENGTH;
998 
999  //Check option type
1000  switch(option->type)
1001  {
1003  //Check IP-Address option
1004  error = ipcpParseIpAddressOption(context, (IpcpIpAddressOption *) option, outPacket);
1005  break;
1006  default:
1007  //If some configuration options received in the Configure-Request are not
1008  //recognizable or not acceptable for negotiation, then the implementation
1009  //must transmit a Configure-Reject
1010  if(outPacket != NULL && outPacket->code == PPP_CODE_CONFIGURE_REJ)
1011  {
1012  //The options field of the Configure-Reject packet is filled
1013  //with the unrecognized options from the Configure-Request
1014  pppAddOption(outPacket, option->type, option->data,
1015  option->length - sizeof(PppOption));
1016  }
1017 
1018  //The option is not acceptable for negotiation
1019  error = ERROR_INVALID_TYPE;
1020  break;
1021  }
1022 
1023  //Return status code
1024  return error;
1025 }
1026 
1027 
1028 /**
1029  * @brief Parse IP-Address option
1030  * @param[in] context PPP context
1031  * @param[in] option Option to be checked
1032  * @param[out] outPacket Pointer to the Configure-Nak or Configure-Reject packet
1033  * @return Error code
1034  **/
1035 
1037  IpcpIpAddressOption *option, PppConfigurePacket *outPacket)
1038 {
1039  error_t error;
1040 
1041  //Check length field
1042  if(option->length == sizeof(IpcpIpAddressOption))
1043  {
1044  //Check whether the option value is acceptable
1045  if(option->ipAddr != IPV4_UNSPECIFIED_ADDR)
1046  {
1047  //If every configuration option received in the Configure-Request is
1048  //recognizable and all values are acceptable, then the implementation
1049  //must transmit a Configure-Ack
1050  if(outPacket != NULL && outPacket->code == PPP_CODE_CONFIGURE_ACK)
1051  {
1052  //Save IP address
1053  context->peerConfig.ipAddr = option->ipAddr;
1054 
1055  //The options field of the Configure-Ack packet contains the
1056  //configuration options that the sender is acknowledging
1058  (void *) &option->ipAddr, option->length - sizeof(PppOption));
1059  }
1060 
1061  //The value is acceptable
1062  error = NO_ERROR;
1063  }
1064  else
1065  {
1066  //If all configuration options are recognizable, but some values are not
1067  //acceptable, then the implementation must transmit a Configure-Nak
1068  if(outPacket != NULL && outPacket->code == PPP_CODE_CONFIGURE_NAK)
1069  {
1070  //The option must be modified to a value acceptable to the
1071  //Configure-Nak sender
1073  &context->peerConfig.ipAddr, sizeof(Ipv4Addr));
1074  }
1075 
1076  //The value is not acceptable
1077  error = ERROR_INVALID_VALUE;
1078  }
1079  }
1080  else
1081  {
1082  //Invalid length field
1083  error = ERROR_INVALID_LENGTH;
1084  }
1085 
1086  //Return status code
1087  return error;
1088 }
1089 
1090 #endif
void ipcpThisLayerStarted(PppContext *context)
This-Layer-Started callback function.
Definition: ipcp.c:690
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:559
#define htons(value)
Definition: cpu_endian.h:413
error_t ipcpSendConfigureNak(PppContext *context, const PppConfigurePacket *configureReqPacket)
Send-Configure-Nak callback function.
Definition: ipcp.c:859
Data logging functions for debugging purpose (PPP)
@ PPP_CODE_CONFIGURE_REJ
Configure-Reject.
Definition: ppp.h:219
int bool_t
Definition: compiler_port.h:53
#define PppPacket
Definition: ppp.h:37
void pppRcvConfigureNakEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Receive-Configure-Nak event.
Definition: ppp_fsm.c:586
@ PPP_CODE_CONFIGURE_ACK
Configure-Ack.
Definition: ppp.h:217
void pppRcvUnknownCodeEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks, const PppPacket *packet)
Process Receive-Unknown-Code event.
Definition: ppp_fsm.c:757
IpcpSecondaryDnsOption
Definition: ipcp.h:142
void ipcpThisLayerUp(PppContext *context)
This-Layer-Up callback function.
Definition: ipcp.c:616
void ipcpZeroRestartCount(PppContext *context)
Zero-Restart-Count callback function.
Definition: ipcp.c:730
void pppUpEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Up event.
Definition: ppp_fsm.c:50
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
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
PPP finite state machine.
error_t ipcpSendTerminateAck(PppContext *context, const PppTerminatePacket *terminateReqPacket)
Send-Terminate-Ack callback function.
Definition: ipcp.c:928
#define TRUE
Definition: os_port.h:50
@ IPCP_OPTION_PRIMARY_DNS
Primary-DNS-Server-Address.
Definition: ipcp.h:56
error_t ipcpProcessConfigureReq(PppContext *context, const PppConfigurePacket *configureReqPacket)
Process Configure-Request packet.
Definition: ipcp.c:225
#define IPCP_DEFAULT_SUBNET_MASK
Definition: ipcp.h:39
PppConfigurePacket
Definition: ppp.h:274
void ipcpInitRestartCount(PppContext *context, uint_t value)
Initialize-Restart-Count callback function.
Definition: ipcp.c:715
error_t ipcpSendConfigureRej(PppContext *context, const PppConfigurePacket *configureReqPacket)
Send-Configure-Reject callback function.
Definition: ipcp.c:878
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
NetBuffer * pppAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold a PPP frame.
Definition: ppp.c:1305
void pppCloseEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Close event.
Definition: ppp_fsm.c:189
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:297
error_t ipcpSendConfigureReq(PppContext *context)
Send-Configure-Request callback function.
Definition: ipcp.c:751
#define PppContext
Definition: ppp.h:38
void pppOpenEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Open event.
Definition: ppp_fsm.c:135
error_t pppSendCodeRej(PppContext *context, const PppPacket *packet, uint8_t identifier, PppProtocol protocol)
Send Code-Reject packet.
Definition: ppp_misc.c:268
PPP FSM actions.
Definition: ppp_fsm.h:153
PppCodeRejPacket
Definition: ppp.h:300
IPCP (PPP Internet Protocol Control Protocol)
@ PPP_CODE_CODE_REJ
Code-Reject.
Definition: ppp.h:222
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:454
@ PPP_CODE_CONFIGURE_REQ
Configure-Request.
Definition: ppp.h:216
#define FALSE
Definition: os_port.h:46
error_t ipcpProcessConfigureAck(PppContext *context, const PppConfigurePacket *configureAckPacket)
Process Configure-Ack packet.
Definition: ipcp.c:321
const PppCallbacks ipcpCallbacks
IPCP FSM callbacks.
Definition: ipcp.c:51
error_t
Error codes.
Definition: error.h:43
error_t ipcpProcessCodeRej(PppContext *context, const PppCodeRejPacket *codeRejPacket)
Process Code-Reject packet.
Definition: ipcp.c:549
void pppRcvConfigureAckEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Receive-Configure-Ack event.
Definition: ppp_fsm.c:524
error_t ipcpProcessConfigureReject(PppContext *context, const PppConfigurePacket *configureRejPacket)
Process Configure-Reject packet.
Definition: ipcp.c:436
#define NetInterface
Definition: net.h:36
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
@ ERROR_INVALID_LENGTH
Definition: error.h:111
#define PPP_RESTART_TIMER
Definition: ppp.h:96
@ PPP_CODE_CONFIGURE_NAK
Configure-Nak.
Definition: ppp.h:218
@ ERROR_INVALID_TYPE
Definition: error.h:115
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t length
Definition: tcp.h:368
IpcpPrimaryDnsOption
Definition: ipcp.h:118
void pppRcvTerminateReqEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks, const PppTerminatePacket *terminateReqPacket)
Process Receive-Terminate-Req event.
Definition: ppp_fsm.c:648
error_t ipcpParseIpAddressOption(PppContext *context, IpcpIpAddressOption *option, PppConfigurePacket *outPacket)
Parse IP-Address option.
Definition: ipcp.c:1036
error_t ipcpOpen(PppContext *context)
IPCP Open event.
Definition: ipcp.c:76
error_t pppSendTerminateAck(PppContext *context, uint8_t identifier, PppProtocol protocol)
Send Terminate-Ack packet.
Definition: ppp_misc.c:217
@ PPP_STATE_8_ACK_SENT
Definition: ppp.h:188
@ PPP_CODE_TERMINATE_ACK
Terminate-Ack.
Definition: ppp.h:221
IpcpIpAddressOption
Definition: ipcp.h:106
uint32_t systime_t
System time.
#define ntohs(value)
Definition: cpu_endian.h:421
uint32_t time
@ PPP_PROTOCOL_IPCP
IP Control Protocol.
Definition: ppp.h:201
error_t pppSendFrame(NetInterface *interface, NetBuffer *buffer, size_t offset, uint16_t protocol)
Send a PPP frame.
Definition: ppp.c:1035
void pppRcvConfigureReqEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks, const PppConfigurePacket *configureReqPacket, PppCode code)
Process Receive-Configure-Request event.
Definition: ppp_fsm.c:335
@ ERROR_INVALID_VALUE
Definition: error.h:116
void ipcpTick(PppContext *context)
IPCP timer handler.
Definition: ipcp.c:121
error_t ipcpParseOption(PppContext *context, PppOption *option, size_t inPacketLen, PppConfigurePacket *outPacket)
Parse IPCP configuration option.
Definition: ipcp.c:984
error_t pppDumpPacket(const PppPacket *packet, size_t length, PppProtocol protocol)
Dump LCP/NCP packet for debugging purpose.
Definition: ppp_debug.c:143
PPP miscellaneous functions.
void ipcpThisLayerFinished(PppContext *context)
This-Layer-Finished callback function.
Definition: ipcp.c:702
error_t pppSendConfigureAckNak(PppContext *context, const PppConfigurePacket *configureReqPacket, PppProtocol protocol, PppCode code)
Send Configure-Ack, Nak or Reject packet.
Definition: ppp_misc.c:56
PppTerminatePacket
Definition: ppp.h:287
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:322
uint8_t value[]
Definition: tcp.h:369
error_t ipcpClose(PppContext *context)
IPCP Close event.
Definition: ipcp.c:97
@ ERROR_WRONG_IDENTIFIER
Definition: error.h:89
uint8_t identifier[]
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 * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
error_t ipcpProcessTerminateReq(PppContext *context, const PppTerminatePacket *terminateReqPacket)
Process Terminate-Request packet.
Definition: ipcp.c:504
error_t pppSendTerminateReq(PppContext *context, uint8_t identifier, PppProtocol protocol)
Send Terminate-Request packet.
Definition: ppp_misc.c:167
@ IPV4_ADDR_STATE_VALID
An address assigned to an interface whose use is unrestricted.
Definition: ipv4.h:204
@ IPCP_OPTION_SECONDARY_DNS
Secondary-DNS-Server-Address.
Definition: ipcp.h:58
IPv4 (Internet Protocol Version 4)
PppOption
Definition: ppp.h:354
@ PPP_STATE_4_CLOSING
Definition: ppp.h:184
void pppDownEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Down event.
Definition: ppp_fsm.c:84
#define PRIuSIZE
void pppRcvTerminateAckEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Receive-Terminate-Ack event.
Definition: ppp_fsm.c:697
unsigned int uint_t
Definition: compiler_port.h:50
error_t ipcpSendCodeRej(PppContext *context, const PppPacket *packet)
Send-Code-Reject callback function.
Definition: ipcp.c:962
@ IPCP_OPTION_IP_ADDRESS
IP-Address.
Definition: ipcp.h:55
TCP/IP stack core.
char_t * ipv4AddrToString(Ipv4Addr ipAddr, char_t *str)
Convert a binary IPv4 address to dot-decimal notation.
Definition: ipv4.c:1457
#define PPP_MAX_CONF_REQ_SIZE
Definition: ppp.h:140
error_t ipcpProcessConfigureNak(PppContext *context, const PppConfigurePacket *configureNakPacket)
Process Configure-Nak packet.
Definition: ipcp.c:347
error_t ipcpSendConfigureAck(PppContext *context, const PppConfigurePacket *configureReqPacket)
Send-Configure-Ack callback function.
Definition: ipcp.c:840
@ NO_ERROR
Success.
Definition: error.h:44
@ PPP_CODE_TERMINATE_REQ
Terminate-Request.
Definition: ppp.h:220
error_t ipcpSendTerminateReq(PppContext *context)
Send-Terminate-Request callback function.
Definition: ipcp.c:896
Debugging facilities.
void pppTimeoutEvent(PppContext *context, PppFsm *fsm, const PppCallbacks *callbacks)
Process Timeout event.
Definition: ppp_fsm.c:257
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:117
error_t ipcpProcessTerminateAck(PppContext *context, const PppTerminatePacket *terminateAckPacket)
Process Terminate-Ack packet.
Definition: ipcp.c:526
systime_t osGetSystemTime(void)
Retrieve system time.
error_t ipcpProcessUnknownCode(PppContext *context, const PppPacket *packet)
Process packet with unknown code.
Definition: ipcp.c:596