ppp_misc.c
Go to the documentation of this file.
1 /**
2  * @file ppp_misc.c
3  * @brief PPP miscellaneous functions
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 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.6.2
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 "ppp/ppp_misc.h"
37 #include "ppp/ppp_debug.h"
38 #include "ppp/lcp.h"
39 #include "ppp/ipcp.h"
40 #include "ppp/ipv6cp.h"
41 #include "debug.h"
42 
43 //Check TCP/IP stack configuration
44 #if (PPP_SUPPORT == ENABLED)
45 
46 
47 /**
48  * @brief Send Configure-Ack, Nak or Reject packet
49  * @param[in] context PPP context
50  * @param[in] configureReqPacket Pointer to the incoming Configure-Request
51  * @param[in] protocol Protocol field
52  * @param[in] code Code field
53  * @return Error code
54  **/
55 
57  const PppConfigurePacket *configureReqPacket, PppProtocol protocol, PppCode code)
58 {
59  error_t error;
60  size_t length;
61  size_t offset;
62  NetBuffer *buffer;
63  PppConfigurePacket *configureAckNakPacket;
64  PppOption *option;
65 
66  //Initialize status code
67  error = NO_ERROR;
68  //Retrieve the length of the Configure-Request packet
69  length = ntohs(configureReqPacket->length);
70 
71  //The Configure-Nak packet may cause a 1-byte expansion for the
72  //Authentication-Protocol option
73  buffer = pppAllocBuffer(length + 1, &offset);
74  //Failed to allocate memory?
75  if(buffer == NULL)
76  return ERROR_OUT_OF_MEMORY;
77 
78  //Point to the beginning of the packet
79  configureAckNakPacket = netBufferAt(buffer, offset, 0);
80 
81  //Format packet header
82  configureAckNakPacket->code = code;
83  configureAckNakPacket->identifier = configureReqPacket->identifier;
84  configureAckNakPacket->length = sizeof(PppConfigurePacket);
85 
86  //Retrieve the length of the option list
87  length -= sizeof(PppConfigurePacket);
88  //Point to the first option
89  option = (PppOption *) configureReqPacket->options;
90 
91  //Parse configuration options
92  while(length > 0)
93  {
94  //LCP protocol?
96  {
97  //Parse LCP option
98  lcpParseOption(context, option, length, configureAckNakPacket);
99  }
100 #if (IPV4_SUPPORT == ENABLED)
101  //IPCP protocol?
102  else if(protocol == PPP_PROTOCOL_IPCP)
103  {
104  //Parse IPCP option
105  ipcpParseOption(context, option, length, configureAckNakPacket);
106  }
107 #endif
108 #if (IPV6_SUPPORT == ENABLED)
109  //IPV6CP protocol?
110  else if(protocol == PPP_PROTOCOL_IPV6CP)
111  {
112  //Parse IPV6CP option
113  ipv6cpParseOption(context, option, length, configureAckNakPacket);
114  }
115 #endif
116 
117  //Remaining bytes to process
118  length -= option->length;
119  //Jump to the next option
120  option = (PppOption *) ((uint8_t *) option + option->length);
121  }
122 
123  //Adjust the length of the multi-part buffer
124  netBufferSetLength(buffer, offset + configureAckNakPacket->length);
125  //Convert length field to network byte order
126  configureAckNakPacket->length = htons(configureAckNakPacket->length);
127 
128  //Debug message
130  {
131  TRACE_INFO("Sending Configure-Ack packet (%" PRIuSIZE " bytes)...\r\n",
132  ntohs(configureAckNakPacket->length));
133  }
134  else if(code == PPP_CODE_CONFIGURE_NAK)
135  {
136  TRACE_INFO("Sending Configure-Nak packet (%" PRIuSIZE " bytes)...\r\n",
137  ntohs(configureAckNakPacket->length));
138  }
139  else if(code == PPP_CODE_CONFIGURE_REJ)
140  {
141  TRACE_INFO("Sending Configure-Reject packet (%" PRIuSIZE " bytes)...\r\n",
142  ntohs(configureAckNakPacket->length));
143  }
144 
145  //Dump packet contents for debugging purpose
146  pppDumpPacket((PppPacket *) configureAckNakPacket,
147  ntohs(configureAckNakPacket->length), protocol);
148 
149  //Send PPP frame
150  error = pppSendFrame(context->interface, buffer, offset, protocol);
151 
152  //Free previously allocated memory block
153  netBufferFree(buffer);
154 
155  //Return status code
156  return error;
157 }
158 
159 
160 /**
161  * @brief Send Terminate-Request packet
162  * @param[in] context PPP context
163  * @param[in] identifier Identifier field
164  * @param[in] protocol Protocol field
165  * @return Error code
166  **/
167 
170 {
171  error_t error;
172  size_t length;
173  size_t offset;
174  NetBuffer *buffer;
175  PppTerminatePacket *terminateReqPacket;
176 
177  //Length of the Terminate-Request packet
178  length = sizeof(PppTerminatePacket);
179 
180  //Allocate a memory buffer to hold the Terminate-Request packet
181  buffer = pppAllocBuffer(length, &offset);
182  //Failed to allocate memory?
183  if(buffer == NULL)
184  return ERROR_OUT_OF_MEMORY;
185 
186  //Point to the Terminate-Request packet
187  terminateReqPacket = netBufferAt(buffer, offset, 0);
188 
189  //Format packet header
190  terminateReqPacket->code = PPP_CODE_TERMINATE_REQ;
191  terminateReqPacket->identifier = identifier;
192  terminateReqPacket->length = htons(length);
193 
194  //Debug message
195  TRACE_INFO("Sending Terminate-Request packet (%" PRIuSIZE " bytes)...\r\n", length);
196  //Dump packet contents for debugging purpose
197  pppDumpPacket((PppPacket *) terminateReqPacket, length, protocol);
198 
199  //Send PPP frame
200  error = pppSendFrame(context->interface, buffer, offset, protocol);
201 
202  //Free previously allocated memory block
203  netBufferFree(buffer);
204 
205  //Return status code
206  return error;
207 }
208 
209 
210 /**
211  * @brief Send Terminate-Ack packet
212  * @param[in] context PPP context
213  * @param[in] identifier Identifier field
214  * @param[in] protocol Protocol field
215  * @return Error code
216  **/
217 
220 {
221  error_t error;
222  size_t length;
223  size_t offset;
224  NetBuffer *buffer;
225  PppTerminatePacket *terminateAckPacket;
226 
227  //Length of the Terminate-Ack packet
228  length = sizeof(PppTerminatePacket);
229 
230  //Allocate a memory buffer to hold the Terminate-Ack packet
231  buffer = pppAllocBuffer(length, &offset);
232  //Failed to allocate memory?
233  if(buffer == NULL)
234  return ERROR_OUT_OF_MEMORY;
235 
236  //Point to the Terminate-Ack packet
237  terminateAckPacket = netBufferAt(buffer, offset, 0);
238 
239  //Format packet header
240  terminateAckPacket->code = PPP_CODE_TERMINATE_ACK;
241  terminateAckPacket->identifier = identifier;
242  terminateAckPacket->length = htons(length);
243 
244  //Debug message
245  TRACE_INFO("Sending Terminate-Ack packet (%" PRIuSIZE " bytes)...\r\n", length);
246  //Dump packet contents for debugging purpose
247  pppDumpPacket((PppPacket *) terminateAckPacket, length, protocol);
248 
249  //Send PPP frame
250  error = pppSendFrame(context->interface, buffer, offset, protocol);
251 
252  //Free previously allocated memory block
253  netBufferFree(buffer);
254 
255  //Return status code
256  return error;
257 }
258 
259 
260 /**
261  * @brief Send Code-Reject packet
262  * @param[in] context PPP context
263  * @param[in] packet Un-interpretable packet received from the peer
264  * @param[in] identifier Identifier field
265  * @param[in] protocol Protocol field
266  * @return Error code
267  **/
268 
269 error_t pppSendCodeRej(PppContext *context, const PppPacket *packet,
271 {
272  error_t error;
273  size_t length;
274  size_t offset;
275  NetBuffer *buffer;
276  PppCodeRejPacket *codeRejPacket;
277 
278  //Calculate the length of the Code-Reject packet
279  length = ntohs(packet->length) + sizeof(PppCodeRejPacket);
280 
281  //The rejected packet must be truncated to comply with
282  //the peer's established MRU
283  length = MIN(length, context->peerConfig.mru);
284 
285  //Allocate a memory buffer to hold the Code-Reject packet
286  buffer = pppAllocBuffer(sizeof(PppCodeRejPacket), &offset);
287  //Failed to allocate memory?
288  if(buffer == NULL)
289  return ERROR_OUT_OF_MEMORY;
290 
291  //Point to the Code-Reject packet
292  codeRejPacket = netBufferAt(buffer, offset, 0);
293 
294  //Format packet header
295  codeRejPacket->code = PPP_CODE_CODE_REJ;
296  codeRejPacket->identifier = identifier;
297  codeRejPacket->length = htons(length);
298 
299  //The Rejected-Packet field contains a copy of the packet which is being rejected
300  error = netBufferAppend(buffer, packet, length - sizeof(PppCodeRejPacket));
301 
302  //Check status code
303  if(!error)
304  {
305  //Debug message
306  TRACE_INFO("Sending Code-Reject packet (%" PRIuSIZE " bytes)...\r\n", length);
307 
308  //Send PPP frame
309  error = pppSendFrame(context->interface, buffer, offset, protocol);
310  }
311 
312  //Free previously allocated memory block
313  netBufferFree(buffer);
314 
315  //Return status code
316  return error;
317 }
318 
319 
320 /**
321  * @brief Send Protocol-Reject packet
322  * @param[in] context PPP context
323  * @param[in] identifier Identifier field
324  * @param[in] protocol Rejected protocol
325  * @param[in] information Rejected information
326  * @param[in] length Length of the rejected information
327  * @return Error code
328  **/
329 
331  uint16_t protocol, const uint8_t *information, size_t length)
332 {
333  error_t error;
334  size_t offset;
335  NetBuffer *buffer;
336  PppProtocolRejPacket *protocolRejPacket;
337 
338  //Calculate the length of the Protocol-Reject packet
339  length += sizeof(PppProtocolRejPacket);
340 
341  //The Rejected-Information must be truncated to comply with
342  //the peer's established MRU
343  length = MIN(length, context->peerConfig.mru);
344 
345  //Allocate a memory buffer to hold the Protocol-Reject packet
346  buffer = pppAllocBuffer(sizeof(PppProtocolRejPacket), &offset);
347  //Failed to allocate memory?
348  if(buffer == NULL)
349  return ERROR_OUT_OF_MEMORY;
350 
351  //Point to the Protocol-Reject packet
352  protocolRejPacket = netBufferAt(buffer, offset, 0);
353 
354  //Format packet header
355  protocolRejPacket->code = PPP_CODE_PROTOCOL_REJ;
356  protocolRejPacket->identifier = identifier;
357  protocolRejPacket->length = htons(length);
358  protocolRejPacket->rejectedProtocol = htons(protocol);
359 
360  //The Rejected-Information field contains a copy of the
361  //packet which is being rejected
362  error = netBufferAppend(buffer, information,
363  length - sizeof(PppProtocolRejPacket));
364 
365  //Check status code
366  if(!error)
367  {
368  //Debug message
369  TRACE_INFO("Sending Protocol-Reject packet (%" PRIuSIZE " bytes)...\r\n", length);
370 
371  //Send PPP frame
372  error = pppSendFrame(context->interface, buffer, offset, PPP_PROTOCOL_LCP);
373  }
374 
375  //Free previously allocated memory block
376  netBufferFree(buffer);
377 
378  //Return status code
379  return error;
380 }
381 
382 
383 /**
384  * @brief Send Echo-Reply packet
385  * @param[in] context PPP context
386  * @param[in] echoReqPacket Echo-Request packet received from the peer
387  * @param[in] protocol Protocol field
388  * @return Error code
389  **/
390 
392  const PppEchoPacket *echoReqPacket, PppProtocol protocol)
393 {
394  error_t error;
395  size_t length;
396  size_t offset;
397  NetBuffer *buffer;
398  PppEchoPacket *echoRepPacket;
399 
400  //Retrieve the length of the Echo-Request packet
401  length = ntohs(echoReqPacket->length);
402 
403  //Make sure the length is valid
404  if(length < sizeof(PppEchoPacket))
405  return ERROR_INVALID_LENGTH;
406  if(length > context->peerConfig.mru)
407  return ERROR_INVALID_LENGTH;
408 
409  //Allocate a memory buffer to hold the Echo-Reply packet
410  buffer = pppAllocBuffer(sizeof(PppEchoPacket), &offset);
411  //Failed to allocate memory?
412  if(buffer == NULL)
413  return ERROR_OUT_OF_MEMORY;
414 
415  //Point to the Echo-Reply packet
416  echoRepPacket = netBufferAt(buffer, offset, 0);
417 
418  //Format packet header
419  echoRepPacket->code = PPP_CODE_ECHO_REP;
420  echoRepPacket->identifier = echoReqPacket->identifier;
421  echoRepPacket->length = htons(length);
422  echoRepPacket->magicNumber = context->localConfig.magicNumber;
423 
424  //The data field of the Echo-Request packet is copied into the data
425  //field of the Echo-Reply packet
426  error = netBufferAppend(buffer, echoReqPacket->data, length - sizeof(PppEchoPacket));
427 
428  //Check status code
429  if(!error)
430  {
431  //Debug message
432  TRACE_INFO("Sending Echo-Reply packet (%" PRIuSIZE " bytes)...\r\n", length);
433 
434  //Send PPP frame
435  error = pppSendFrame(context->interface, buffer, offset, protocol);
436  }
437 
438  //Free previously allocated memory block
439  netBufferFree(buffer);
440 
441  //Return status code
442  return error;
443 }
444 
445 
446 /**
447  * @brief Add an option to a Configure packet
448  * @param[in,out] packet Pointer to the Configure packet
449  * @param[in] optionType Option type
450  * @param[in] optionValue Option value
451  * @param[in] optionLen Length of the option value
452  * @return Error code
453  **/
454 
455 error_t pppAddOption(PppConfigurePacket *packet, uint8_t optionType,
456  const void *optionValue, uint8_t optionLen)
457 {
458  PppOption *option;
459 
460  //Make sure the length is valid
461  if(optionLen > (UINT8_MAX - sizeof(PppOption)))
462  return ERROR_INVALID_LENGTH;
463 
464  //Point to the end of the Configure packet
465  option = (PppOption *) ((uint8_t *) packet + packet->length);
466 
467  //Write specified option at current location
468  option->type = optionType;
469  option->length = optionLen + sizeof(PppOption);
470  //Copy option data
471  osMemcpy(option->data, optionValue, optionLen);
472 
473  //Update the length of the Configure packet
474  packet->length += optionLen + sizeof(PppOption);
475 
476  //Successful processing
477  return NO_ERROR;
478 }
479 
480 #endif
#define htons(value)
Definition: cpu_endian.h:413
Data logging functions for debugging purpose (PPP)
@ PPP_CODE_CONFIGURE_REJ
Configure-Reject.
Definition: ppp.h:219
uint8_t code
Definition: coap_common.h:179
#define PppPacket
Definition: ppp.h:37
@ PPP_CODE_CONFIGURE_ACK
Configure-Ack.
Definition: ppp.h:217
error_t ipv6cpParseOption(PppContext *context, PppOption *option, size_t inPacketLen, PppConfigurePacket *outPacket)
Parse IPV6CP configuration option.
Definition: ipv6cp.c:917
uint8_t protocol
Definition: ipv4.h:352
PppProtocol
Protocol field values.
Definition: ppp.h:198
@ PPP_CODE_PROTOCOL_REJ
Protocol-Reject.
Definition: ppp.h:223
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
IPV6CP (PPP IPv6 Control Protocol)
error_t pppSendProtocolRej(PppContext *context, uint8_t identifier, uint16_t protocol, const uint8_t *information, size_t length)
Send Protocol-Reject packet.
Definition: ppp_misc.c:330
PppConfigurePacket
Definition: ppp.h:274
@ 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:1302
#define PppContext
Definition: ppp.h:38
error_t pppSendCodeRej(PppContext *context, const PppPacket *packet, uint8_t identifier, PppProtocol protocol)
Send Code-Reject packet.
Definition: ppp_misc.c:269
PppCodeRejPacket
Definition: ppp.h:300
IPCP (PPP Internet Protocol Control Protocol)
@ PPP_CODE_CODE_REJ
Code-Reject.
Definition: ppp.h:222
LCP (PPP Link Control Protocol)
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:455
error_t lcpParseOption(PppContext *context, PppOption *option, size_t inPacketLen, PppConfigurePacket *outPacket)
Parse LCP configuration option.
Definition: lcp.c:1316
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
@ PPP_CODE_ECHO_REP
Echo-Reply.
Definition: ppp.h:225
error_t
Error codes.
Definition: error.h:43
PppCode
Code field values.
Definition: ppp.h:215
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ PPP_CODE_CONFIGURE_NAK
Configure-Nak.
Definition: ppp.h:218
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
@ PPP_PROTOCOL_IPV6CP
IPv6 Control Protocol.
Definition: ppp.h:202
#define MIN(a, b)
Definition: os_port.h:63
error_t pppSendTerminateAck(PppContext *context, uint8_t identifier, PppProtocol protocol)
Send Terminate-Ack packet.
Definition: ppp_misc.c:218
@ PPP_CODE_TERMINATE_ACK
Terminate-Ack.
Definition: ppp.h:221
#define ntohs(value)
Definition: cpu_endian.h:421
error_t pppSendEchoRep(PppContext *context, const PppEchoPacket *echoReqPacket, PppProtocol protocol)
Send Echo-Reply packet.
Definition: ppp_misc.c:391
@ PPP_PROTOCOL_LCP
Link Control Protocol.
Definition: ppp.h:203
PppEchoPacket
Definition: ppp.h:328
@ 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:1034
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
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:604
PPP miscellaneous functions.
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 identifier[]
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 pppSendTerminateReq(PppContext *context, uint8_t identifier, PppProtocol protocol)
Send Terminate-Request packet.
Definition: ppp_misc.c:168
PppOption
Definition: ppp.h:354
#define PRIuSIZE
TCP/IP stack core.
@ NO_ERROR
Success.
Definition: error.h:44
@ PPP_CODE_TERMINATE_REQ
Terminate-Request.
Definition: ppp.h:220
Debugging facilities.
PppProtocolRejPacket
Definition: ppp.h:314