Blame view

RIOT/sys/include/net/sock/ip.h 16.8 KB
a752c7ab   elopes   add first test an...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
  /*
   * Copyright (C) 2016 Alexander Aring <aar@pengutronix.de>
   *                    Freie Universität Berlin
   *                    HAW Hamburg
   *                    Kaspar Schleiser <kaspar@schleiser.de>
   *
   * This file is subject to the terms and conditions of the GNU Lesser
   * General Public License v2.1. See the file LICENSE in the top level
   * directory for more details.
   */
  
  /**
   * @defgroup    net_sock_ip     Raw IPv4/IPv6 sock API
   * @ingroup     net_sock
   * @brief       Sock submodule for raw IPv4/IPv6
   *
   * How To Use
   * ----------
   * First you need to @ref including-modules "include" a module that implements
   * this API in your application's Makefile. For example the implementation for
   * @ref net_gnrc "GNRC" is called `gnrc_sock_ip`.
   *
   * ### A Simple IPv6 Server
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
   * #include <stdio.h>
   *
   * #include "net/protnum.h"
   * #include "net/sock/ip.h"
   *
   * uint8_t buf[128];
   *
   * int main(void)
   * {
   *     sock_ip_ep_t local = SOCK_IPV6_EP_ANY;
   *     sock_ip_t sock;
   *
   *     if (sock_ip_create(&sock, &local, NULL, PROTNUM_IPV6_NONXT, 0) < 0) {
   *         puts("Error creating raw IP sock");
   *         return 1;
   *     }
   *
   *     while (1) {
   *         sock_ip_ep_t remote;
   *         ssize_t res;
   *
   *         if ((res = sock_ip_recv(&sock, buf, sizeof(buf), SOCK_NO_TIMEOUT,
   *                                 &remote)) >= 0) {
   *             puts("Received a message");
   *             if (sock_ip_send(&sock, buf, res, 0, &remote) < 0) {
   *                 puts("Error sending reply");
   *             }
   *         }
   *     }
   *
   *     return 0;
   * }
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
   * Above you see a simple IPv6 server. Don't forget to also
   * @ref including-modules "include" the IPv6 module of your networking
   * implementation (e.g. `gnrc_ipv6_default` for @ref net_gnrc "GNRC") and at
   * least one network device.
   *
   * After including header files for the @ref net_af "address families",
   * @ref net_protnum "protocol numbers" and the @ref net_sock_ip "raw `sock`s"
   * themselves, we create some buffer space `buf` to store the data received by
   * the server:
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
   * #include "net/af.h"
   * #include "net/protnum.h"
   * #include "net/sock/ip.h"
   *
   * uint8_t buf[128];
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
   * To be able to listen for incoming packets we bind the `sock` by setting a
   * local end point (even if we just state here, that we just want to bind it to
   * any IPv6 address).
   *
   * We then proceed to create the `sock`. It is bound to `local` and listens for
   * IPv6 packets with @ref ipv6_hdr_t::nh "next header field"
   * @ref PROTNUM_IPV6_NONXT. Since we don't need any further configuration we set
   * the flags to 0. In case of an error we stop the program:
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
   *     sock_ip_ep_t local = SOCK_IPV6_EP_ANY;
   *     sock_ip_t sock;
   *
   *     if (sock_ip_create(&sock, &local, NULL, PROTNUM_IPV6_NONXT, 0) < 0) {
   *         puts("Error creating raw IP sock");
   *         return 1;
   *     }
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
   * The application then waits indefinitely for an incoming message in
   * `buf` from `remote`. If we want to timeout this wait period we could
   * alternatively set the `timeout` parameter of @ref sock_ip_recv() to a
   * value `!= SOCK_NO_TIMEOUT`. If an error occurs on receive we just ignore it
   * and continue looping.
   *
   * If we receive a message we use its `remote` to reply. Note since the `proto`
   * was already set during @ref sock_ip_create() we can just leave `proto` for
   * the @ref sock_ip_send() set to 0 (it is ignored by that function in that case
   * anyway). In case of an error on send we print an according message:
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
   *     while (1) {
   *         sock_ip_ep_t remote;
   *         ssize_t res;
   *
   *         if ((res = sock_ip_recv(&sock, buf, sizeof(buf), SOCK_NO_TIMEOUT,
   *                                 &remote)) >= 0) {
   *             puts("Received a message");
   *             if (sock_ip_send(&sock, buf, res, 0, &remote) < 0) {
   *                 puts("Error sending reply");
   *             }
   *         }
   *     }
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
   * ### A Simple IPv6 Client
   * There are two kinds of clients. Those that do expect a reply and those who
   * don't. A client that does not require a reply is very simple to implement in
   * one line:
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
   * res = sock_ip_send(NULL, data, data_len, PROTNUM, &remote);
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
   * With `data` being the data sent, `data_len` the length of `data`, `PROTNUM`
   * the next header number for the sent packet and `remote` the remote end point
   * the packet that is to be sent.
   *
   * To see some other capabilities we look at a more complex example in form of
   * the counter of the echo server above:
   *
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
   * #include <stdio.h>
   *
   * #include "net/af.h"
   * #include "net/protnum.h"
   * #include "net/ipv6/addr.h"
   * #include "net/sock/ip.h"
   * #include "xtimer.h"
   *
   * uint8_t buf[7];
   *
   * int main(void)
   * {
   *     sock_ip_ep_t local = SOCK_IPV6_EP_ANY;
   *     sock_ip_t sock;
   *
   *     if (sock_ip_create(&sock, &local, NULL, PROTNUM_IPV6_NONXT, 0) < 0) {
   *         puts("Error creating raw IP sock");
   *         return 1;
   *     }
   *
   *     while (1) {
   *         sock_ip_ep_t remote = { .family = AF_INET6 };
   *         ssize_t res;
   *
   *         ipv6_addr_set_all_nodes_multicast((ipv6_addr_t *)&remote.addr.ipv6,
   *                                           IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
   *
   *         if (sock_ip_send(&sock, "Hello!", sizeof("Hello!"), 0, &remote) < 0) {
   *             puts("Error sending message");
   *             sock_ip_close(&sock);
   *             return 1;
   *         }
   *         if ((res = sock_ip_recv(&sock, buf, sizeof(buf), 1 * US_PER_SEC,
   *                                 NULL)) < 0) {
   *             if (res == -ETIMEDOUT) {
   *                 puts("Timed out");
   *             }
   *             else {
   *                 puts("Error receiving message");
   *             }
   *         }
   *         else {
   *             printf("Received message: \"");
   *             for (int i = 0; i < res; i++) {
   *                 printf("%c", buf[i]);
   *             }
   *             printf("\"\n");
   *         }
   *         xtimer_sleep(1);
   *     }
   *
   *     return 0;
   * }
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
   * Again: Don't forget to also @ref including-modules "include" the IPv6 module
   * of your networking implementation (e.g. `gnrc_ipv6_default` for
   * @ref net_gnrc "GNRC") and at least one network device.
   *
   * We first create again a `sock` with a local end point bound to any IPv6
   * address. Note that we also could specify the remote end point here and not
   * use it with @ref sock_ip_send().
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
   *     sock_ip_ep_t local = SOCK_IPV6_EP_ANY;
   *     sock_ip_t sock;
   *
   *     if (sock_ip_create(&sock, &local, NULL, PROTNUM_IPV6_NONXT, 0) < 0) {
   *         puts("Error creating raw IP sock");
   *         return 1;
   *     }
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
   * We then create a remote end point for the [link-local all nodes multicast
   * address](https://tools.ietf.org/html/rfc4291#page-16) (`ff02::1`) and send
   * a "Hello!" message to that end point.
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
   *         sock_ip_ep_t remote = { .family = AF_INET6 };
   *         ssize_t res;
   *
   *         ipv6_addr_set_all_nodes_multicast((ipv6_addr_t *)&remote.addr.ipv6,
   *                                           IPV6_ADDR_MCAST_SCP_LINK_LOCAL);
   *
   *         if (sock_ip_send(&sock, "Hello!", sizeof("Hello!"), 0, &remote) < 0) {
   *             puts("Error sending message");
   *             sock_ip_close(&sock);
   *             return 1;
   *         }
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
   * We then wait a second for a reply and print it when it is received.
   *
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
   *         if ((res = sock_ip_recv(&sock, buf, sizeof(buf), 1 * US_PER_SEC,
   *                                 NULL)) < 0) {
   *             if (res == -ETIMEDOUT) {
   *                 puts("Timed out");
   *             }
   *             else {
   *                 puts("Error receiving message");
   *             }
   *         }
   *         else {
   *             printf("Received message: \"");
   *             for (int i = 0; i < res; i++) {
   *                 printf("%c", buf[i]);
   *             }
   *             printf("\"\n");
   *         }
   * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   *
   * Finally, we wait a second before sending out the next "Hello!" with
   * `xtimer_sleep(1)`.
   *
   * @{
   *
   * @file
   * @brief   Raw IPv4/IPv6 sock definitions
   *
   * @author  Alexander Aring <aar@pengutronix.de>
   * @author  Simon Brummer <simon.brummer@haw-hamburg.de>
   * @author  Cenk Gündoğan <mail@cgundogan.de>
   * @author  Peter Kietzmann <peter.kietzmann@haw-hamburg.de>
   * @author  Martine Lenders <m.lenders@fu-berlin.de>
   * @author  Kaspar Schleiser <kaspar@schleiser.de>
   */
  #ifndef NET_SOCK_IP_H
  #define NET_SOCK_IP_H
  
  #include <assert.h>
  #include <stdint.h>
  #include <stdlib.h>
  #include <sys/types.h>
  
  #include "net/sock.h"
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  /**
   * @brief   Type for a raw IPv4/IPv6 sock object
   *
   * @note API implementors: `struct sock_ip` needs to be defined by
   *       implementation-specific `sock_types.h`.
   */
  typedef struct sock_ip sock_ip_t;
  
  /**
   * @brief   Creates a new raw IPv4/IPv6 sock object
   *
   * @pre `(sock != NULL)`
   *
   * @param[out] sock     The resulting sock object.
   * @param[in] local     Local end point for the sock object.
   *                      May be NULL. sock_ip_ep_t::netif must either be
   *                      @ref SOCK_ADDR_ANY_NETIF or equal to sock_ip_ep_t::netif
   *                      of @p remote if `remote != NULL`.
   *                      If NULL @ref sock_ip_send() may bind implicitly.
   * @param[in] remote    Remote end point for the sock object.
   *                      May be `NULL` but then the `remote` parameter of
   *                      @ref sock_ip_send() may not be `NULL` or it will always
   *                      error with return value -ENOTCONN.
   *                      sock_ip_ep_t::port may not be 0 if `remote != NULL`.
   *                      sock_ip_ep_t::netif must either be
   *                      @ref SOCK_ADDR_ANY_NETIF or equal to sock_ip_ep_t::netif
   *                      of @p local if `local != NULL`.
   * @param[in] proto     Protocol to use in the raw IPv4/IPv6 sock object
   *                      (the `protocol` header field in IPv4 and the `next_header`
   *                      field in IPv6).
   * @param[in] flags     Flags for the sock object. See also
   *                      [sock flags](net_sock_flags). May be 0.
   *
   * @return  0 on success.
   * @return  -EADDRINUSE, if `local != NULL` and @p local is already used
   *          elsewhere
   * @return  -EAFNOSUPPORT, if `local != NULL` or `remote != NULL` and
   *          sock_ip_ep_t::family of @p local or @p remote is not supported.
   * @return  -EINVAL, if sock_ip_ep_t::addr of @p remote is an invalid address.
   * @return  -EINVAL, if sock_ip_ep_t::netif of @p local or @p remote are not
   *          valid interfaces or contradict each other
   *          (i.e. `(local->netif != remote->netif) &&
   *          ((local->netif != SOCK_ADDR_ANY_NETIF) ||
   *          (remote->netif != SOCK_ADDR_ANY_NETIF))` if neither is `NULL`).
   * @return  -ENOMEM, if not enough resources can be provided for `sock` to be
   *          created.
   * @return  -EPROTONOSUPPORT, if `local != NULL` or `remote != NULL` and
   *          proto is not supported by sock_ip_ep_t::family of @p local or @p
   *          remote.
   */
  int sock_ip_create(sock_ip_t *sock, const sock_ip_ep_t *local,
                     const sock_ip_ep_t *remote, uint8_t proto, uint16_t flags);
  
  /**
   * @brief   Closes a raw IPv4/IPv6 sock object
   *
   * @pre `(sock != NULL)`
   *
   * @param[in] sock  A raw IPv4/IPv6 sock object.
   */
  void sock_ip_close(sock_ip_t *sock);
  
  /**
   * @brief   Gets the local end point of a raw IPv4/IPv6 sock object
   *
   * This gets the local end point of a raw IPv4/IPv6 sock object. Note that this
   * might not be the same end point you added in @ref sock_ip_create(), but an
   * end point more suitable for the implementation. Examples for this might be
   * that if sock_ip_ep_t::netif is given in @ref sock_ip_create(), the
   * implementation might choose to return the address on this interface the
   * @p sock is bound to in @p ep's sock_ip_ep_t::addr.
   *
   * @pre `(sock != NULL) && (ep != NULL)`
   *
   * @param[in] sock  A raw IPv4/IPv6 sock object.
   * @param[out] ep   The local end point.
   *
   * @return  0 on success.
   * @return  -EADDRNOTAVAIL, when @p sock has no end point bound to it.
   */
  int sock_ip_get_local(sock_ip_t *sock, sock_ip_ep_t *ep);
  
  /**
   * @brief   Gets the remote end point of a UDP sock object
   *
   * @pre `(sock != NULL) && (ep != NULL)`
   *
   * This gets the remote end point of a raw IPv4/IPv6 sock object. Note that this
   * might not be the same end point you added in @ref sock_ip_create(), but an
   * end point more suitable for the implementation. Examples for this might be
   * that if sock_ip_ep_t::netif is given in @ref sock_ip_create(), the
   * implementation might choose to return the address on this interface the
   * @p sock is bound to in @p ep's sock_ip_ep_t::addr.
   *
   * @param[in] sock  A UDP sock object.
   * @param[out] ep   The remote end point.
   *
   * @return  0 on success.
   * @return  -ENOTCONN, when @p sock has no remote end point bound to it.
   */
  int sock_ip_get_remote(sock_ip_t *sock, sock_ip_ep_t *ep);
  
  /**
   * @brief   Receives a message over IPv4/IPv6 from remote end point
   *
   * @pre `(sock != NULL) && (data != NULL) && (max_len > 0)`
   *
   * @param[in] sock      A raw IPv4/IPv6 sock object.
   * @param[out] data     Pointer where the received data should be stored.
   * @param[in] max_len   Maximum space available at @p data.
   * @param[in] timeout   Timeout for receive in microseconds.
   *                      If 0 and no data is available, the function returns
   *                      immediately.
   *                      May be @ref SOCK_NO_TIMEOUT for no timeout (wait until
   *                      data is available).
   * @param[out] remote   Remote end point of the received data.
   *                      May be NULL, if it is not required by the application.
   *
   * @note    Function blocks if no packet is currently waiting.
   *
   * @return  The number of bytes received on success.
   * @return  0, if no received data is available, but everything is in order.
   * @return  -EADDRNOTAVAIL, if local of @p sock is not given.
   * @return  -EAGAIN, if @p timeout is `0` and no data is available.
   * @return  -ENOBUFS, if buffer space is not large enough to store received
   *          data.
   * @return  -ENOMEM, if no memory was available to receive @p data.
   * @return  -EPROTO, if source address of received packet did not equal
   *          the remote of @p sock.
   * @return  -ETIMEDOUT, if @p timeout expired.
   */
  ssize_t sock_ip_recv(sock_ip_t *sock, void *data, size_t max_len,
                       uint32_t timeout, sock_ip_ep_t *remote);
  
  /**
   * @brief   Sends a message over IPv4/IPv6 to remote end point
   *
   * @pre `((sock != NULL || remote != NULL)) && (if (len != 0): (data != NULL))`
   *
   * @param[in] sock      A raw IPv4/IPv6 sock object. May be NULL.
   *                      A sensible local end point should be selected by the
   *                      implementation in that case.
   * @param[in] data      Pointer where the received data should be stored.
   *                      May be `NULL` if `len == 0`.
   * @param[in] len       Maximum space available at @p data.
   * @param[in] proto     Protocol to use in the packet sent, in case
   *                      `sock == NULL`. If `sock != NULL` this parameter will be
   *                      ignored.
   * @param[in] remote    Remote end point for the sent data.
   *                      May be `NULL`, if @p sock has a remote end point.
   *                      sock_ip_ep_t::family may be AF_UNSPEC, if local
   *                      end point of @p sock provides this information.
   *
   * @return  The number of bytes sent on success.
   * @return  -EAFNOSUPPORT, if `remote != NULL` and sock_ip_ep_t::family of
   *          @p remote is != AF_UNSPEC and not supported.
   * @return  -EINVAL, if sock_ip_ep_t::addr of @p remote is an invalid address.
   * @return  -EINVAL, if sock_ip_ep_t::netif of @p remote is not a
   *          valid interface or contradicts the local interface of @p sock.
   * @return  -EHOSTUNREACH, if @p remote or remote end point of @p sock is not
   *          reachable.
   * @return  -ENOMEM, if no memory was available to send @p data.
   * @return  -ENOTCONN, if `remote == NULL`, but @p sock has no remote end point.
   * @return  -EPROTOTYPE, if `sock == NULL` and @p proto is not by
   *          sock_ip_ep_t::family of @p remote.
   */
  ssize_t sock_ip_send(sock_ip_t *sock, const void *data, size_t len,
                       uint8_t proto, const sock_ip_ep_t *remote);
  
  #include "sock_types.h"
  
  #ifdef __cplusplus
  }
  #endif
  
  #endif /* NET_SOCK_IP_H */
  /** @} */