[489740f] | 1 | .. comment SPDX-License-Identifier: CC-BY-SA-4.0 |
---|
| 2 | |
---|
[b412038] | 3 | .. COMMENT: Written by Eric Norum |
---|
| 4 | .. COMMENT: COPYRIGHT (c) 1988-2002. |
---|
| 5 | .. COMMENT: On-Line Applications Research Corporation (OAR). |
---|
| 6 | .. COMMENT: All rights reserved. |
---|
| 7 | |
---|
[ca49bfd] | 8 | Using Networking in an RTEMS Application |
---|
| 9 | ######################################## |
---|
| 10 | |
---|
| 11 | Makefile changes |
---|
| 12 | ================ |
---|
| 13 | |
---|
| 14 | Including the required managers |
---|
| 15 | ------------------------------- |
---|
| 16 | |
---|
[b412038] | 17 | The FreeBSD networking code requires several RTEMS managers in the application: |
---|
| 18 | |
---|
| 19 | .. code-block:: c |
---|
[ca49bfd] | 20 | |
---|
| 21 | MANAGERS = io event semaphore |
---|
| 22 | |
---|
| 23 | Increasing the size of the heap |
---|
| 24 | ------------------------------- |
---|
| 25 | |
---|
[b412038] | 26 | The networking tasks allocate a lot of memory. For most applications the heap |
---|
| 27 | should be at least 256 kbytes. The amount of memory set aside for the heap can |
---|
| 28 | be adjusted by setting the ``CFLAGS_LD`` definition as shown below: |
---|
| 29 | |
---|
| 30 | .. code-block:: c |
---|
[ca49bfd] | 31 | |
---|
| 32 | CFLAGS_LD += -Wl,--defsym -Wl,HeapSize=0x80000 |
---|
| 33 | |
---|
| 34 | This sets aside 512 kbytes of memory for the heap. |
---|
| 35 | |
---|
| 36 | System Configuration |
---|
| 37 | ==================== |
---|
| 38 | |
---|
[b412038] | 39 | The networking tasks allocate some RTEMS objects. These must be accounted for |
---|
| 40 | in the application configuration table. The following lists the requirements. |
---|
[ca49bfd] | 41 | |
---|
| 42 | *TASKS* |
---|
| 43 | One network task plus a receive and transmit task for each device. |
---|
| 44 | |
---|
| 45 | *SEMAPHORES* |
---|
[b412038] | 46 | One network semaphore plus one syslog mutex semaphore if the application |
---|
| 47 | uses openlog/syslog. |
---|
[ca49bfd] | 48 | |
---|
| 49 | *EVENTS* |
---|
[b412038] | 50 | The network stack uses ``RTEMS_EVENT_24`` and ``RTEMS_EVENT_25``. This has |
---|
| 51 | no effect on the application configuration, but application tasks which |
---|
| 52 | call the network functions should not use these events for other purposes. |
---|
[ca49bfd] | 53 | |
---|
| 54 | Initialization |
---|
| 55 | ============== |
---|
| 56 | |
---|
| 57 | Additional include files |
---|
| 58 | ------------------------ |
---|
| 59 | |
---|
[b412038] | 60 | The source file which declares the network configuration structures and calls |
---|
| 61 | the network initialization function must include |
---|
| 62 | |
---|
| 63 | .. code-block:: c |
---|
[ca49bfd] | 64 | |
---|
| 65 | #include <rtems/rtems_bsdnet.h> |
---|
| 66 | |
---|
| 67 | Network Configuration |
---|
| 68 | --------------------- |
---|
| 69 | |
---|
[b412038] | 70 | The network configuration is specified by declaring and initializing the |
---|
| 71 | ``rtems_bsdnet_config`` structure. |
---|
| 72 | |
---|
| 73 | .. code-block:: c |
---|
[ca49bfd] | 74 | |
---|
| 75 | struct rtems_bsdnet_config { |
---|
[b412038] | 76 | /* |
---|
| 77 | * This entry points to the head of the ifconfig chain. |
---|
| 78 | */ |
---|
| 79 | struct rtems_bsdnet_ifconfig *ifconfig; |
---|
| 80 | /* |
---|
| 81 | * This entry should be rtems_bsdnet_do_bootp if BOOTP |
---|
| 82 | * is being used to configure the network, and NULL |
---|
| 83 | * if BOOTP is not being used. |
---|
| 84 | */ |
---|
| 85 | void (*bootp)(void); |
---|
| 86 | /* |
---|
| 87 | * The remaining items can be initialized to 0, in |
---|
| 88 | * which case the default value will be used. |
---|
| 89 | */ |
---|
| 90 | rtems_task_priority network_task_priority; /* 100 */ |
---|
| 91 | unsigned long mbuf_bytecount; /* 64 kbytes */ |
---|
| 92 | unsigned long mbuf_cluster_bytecount; /* 128 kbytes */ |
---|
| 93 | char *hostname; /* BOOTP */ |
---|
| 94 | char *domainname; /* BOOTP */ |
---|
| 95 | char *gateway; /* BOOTP */ |
---|
| 96 | char *log_host; /* BOOTP */ |
---|
| 97 | char *name_server[3]; /* BOOTP */ |
---|
| 98 | char *ntp_server[3]; /* BOOTP */ |
---|
| 99 | unsigned long sb_efficiency; /* 2 */ |
---|
| 100 | /* UDP TX: 9216 bytes */ |
---|
| 101 | unsigned long udp_tx_buf_size; |
---|
| 102 | /* UDP RX: 40 * (1024 + sizeof(struct sockaddr_in)) */ |
---|
| 103 | unsigned long udp_rx_buf_size; |
---|
| 104 | /* TCP TX: 16 * 1024 bytes */ |
---|
| 105 | unsigned long tcp_tx_buf_size; |
---|
| 106 | /* TCP TX: 16 * 1024 bytes */ |
---|
| 107 | unsigned long tcp_rx_buf_size; |
---|
| 108 | /* Default Network Tasks CPU Affinity */ |
---|
| 109 | #ifdef RTEMS_SMP |
---|
| 110 | const cpu_set_t *network_task_cpuset; |
---|
| 111 | size_t network_task_cpuset_size; |
---|
| 112 | #endif |
---|
[ca49bfd] | 113 | }; |
---|
| 114 | |
---|
[b412038] | 115 | The structure entries are described in the following table. If your |
---|
| 116 | application uses BOOTP/DHCP to obtain network configuration information and if |
---|
| 117 | you are happy with the default values described below, you need to provide only |
---|
| 118 | the first two entries in this structure. |
---|
| 119 | |
---|
| 120 | ``struct rtems_bsdnet_ifconfig *ifconfig`` |
---|
| 121 | A pointer to the first configuration structure of the first network device. |
---|
| 122 | This structure is described in the following section. You must provide a |
---|
| 123 | value for this entry since there is no default value for it. |
---|
| 124 | |
---|
| 125 | ``void (*bootp)(void)`` |
---|
| 126 | This entry should be set to ``rtems_bsdnet_do_bootp`` if your application |
---|
| 127 | by default uses the BOOTP/DHCP client protocol to obtain network |
---|
| 128 | configuration information. It should be set to ``NULL`` if your |
---|
| 129 | application does not use BOOTP/DHCP. You can also use |
---|
| 130 | ``rtems_bsdnet_do_bootp_rootfs`` to have a set of standard files created |
---|
| 131 | with the information return by the BOOTP/DHCP protocol. The IP address is |
---|
| 132 | added to :file:`/etc/hosts` with the host name and domain returned. If no |
---|
| 133 | host name or domain is returned ``me.mydomain`` is used. The BOOTP/DHCP |
---|
| 134 | server's address is also added to :file:`/etc/hosts`. The domain name |
---|
| 135 | server listed in the BOOTP/DHCP information are added to |
---|
| 136 | :file:`/etc/resolv.conf`. A``search`` record is also added if a domain is |
---|
| 137 | returned. The files are created if they do not exist. The default |
---|
| 138 | ``rtems_bsdnet_do_bootp`` and ``rtems_bsdnet_do_bootp_rootfs`` handlers |
---|
| 139 | will loop for-ever waiting for a BOOTP/DHCP server to respond. If an error |
---|
| 140 | is detected such as not valid interface or valid hardware address the |
---|
| 141 | target will reboot allowing any hardware reset to correct itself. You can |
---|
| 142 | provide your own custom handler which allows you to perform an |
---|
| 143 | initialization that meets your specific system requirements. For example |
---|
| 144 | you could try BOOTP/DHCP then enter a configuration tool if no server is |
---|
| 145 | found allowing the user to switch to a static configuration. |
---|
[ca49bfd] | 146 | |
---|
| 147 | ``int network_task_priority`` |
---|
| 148 | The priority at which the network task and network device |
---|
| 149 | receive and transmit tasks will run. |
---|
| 150 | If a value of 0 is specified the tasks will run at priority 100. |
---|
| 151 | |
---|
| 152 | ``unsigned long mbuf_bytecount`` |
---|
| 153 | The number of bytes to allocate from the heap for use as mbufs. |
---|
| 154 | If a value of 0 is specified, 64 kbytes will be allocated. |
---|
| 155 | |
---|
| 156 | ``unsigned long mbuf_cluster_bytecount`` |
---|
| 157 | The number of bytes to allocate from the heap for use as mbuf clusters. |
---|
| 158 | If a value of 0 is specified, 128 kbytes will be allocated. |
---|
| 159 | |
---|
[b412038] | 160 | ``char *hostname`` |
---|
[ca49bfd] | 161 | The host name of the system. |
---|
| 162 | If this, or any of the following, entries are ``NULL`` the value |
---|
| 163 | may be obtained from a BOOTP/DHCP server. |
---|
| 164 | |
---|
[b412038] | 165 | ``char *domainname`` |
---|
[ca49bfd] | 166 | The name of the Internet domain to which the system belongs. |
---|
| 167 | |
---|
[b412038] | 168 | ``char *gateway`` |
---|
| 169 | The Internet host number of the network gateway machine, specified in |
---|
| 170 | 'dotted decimal' (``129.128.4.1``) form. |
---|
[ca49bfd] | 171 | |
---|
[b412038] | 172 | ``char *log_host`` |
---|
| 173 | The Internet host number of the machine to which ``syslog`` messages will |
---|
| 174 | be sent. |
---|
[ca49bfd] | 175 | |
---|
[b412038] | 176 | ``char *name_server[3]`` |
---|
| 177 | The Internet host numbers of up to three machines to be used as Internet |
---|
| 178 | Domain Name Servers. |
---|
[ca49bfd] | 179 | |
---|
[b412038] | 180 | ``char *ntp_server[3]`` |
---|
[ca49bfd] | 181 | The Internet host numbers of up to three machines to be used as |
---|
| 182 | Network Time Protocol (NTP) Servers. |
---|
| 183 | |
---|
| 184 | ``unsigned long sb_efficiency`` |
---|
[b412038] | 185 | This is the first of five configuration parameters related to the amount of |
---|
| 186 | memory each socket may consume for buffers. The TCP/IP stack reserves |
---|
| 187 | buffers (e.g. mbufs) for each open socket. The TCP/IP stack has different |
---|
| 188 | limits for the transmit and receive buffers associated with each TCP and |
---|
| 189 | UDP socket. By tuning these parameters, the application developer can make |
---|
| 190 | trade-offs between memory consumption and performance. The default |
---|
| 191 | parameters favor performance over memory consumption. See |
---|
| 192 | http://www.rtems.org/ml/rtems-users/2004/february/msg00200.html for more |
---|
| 193 | details but note that after the RTEMS 4.8 release series, the |
---|
| 194 | ``sb_efficiency`` default was changed from ``8`` to ``2``. The user should |
---|
| 195 | also be aware of the ``SO_SNDBUF`` and ``SO_RCVBUF`` IO control operations. |
---|
| 196 | These can be used to specify the send and receive buffer sizes for a |
---|
| 197 | specific socket. There is no standard IO control to change the |
---|
| 198 | ``sb_efficiency`` factor. The ``sb_efficiency`` parameter is a buffering |
---|
| 199 | factor used in the implementation of the TCP/IP stack. The default is |
---|
| 200 | ``2`` which indicates double buffering. When allocating memory for each |
---|
[ca49bfd] | 201 | socket, this number is multiplied by the buffer sizes for that socket. |
---|
| 202 | |
---|
| 203 | ``unsigned long udp_tx_buf_size`` |
---|
[b412038] | 204 | This configuration parameter specifies the maximum amount of buffer memory |
---|
| 205 | which may be used for UDP sockets to transmit with. The default size is |
---|
| 206 | 9216 bytes which corresponds to the maximum datagram size. |
---|
[ca49bfd] | 207 | |
---|
| 208 | ``unsigned long udp_rx_buf_size`` |
---|
[b412038] | 209 | This configuration parameter specifies the maximum amount of buffer memory |
---|
| 210 | which may be used for UDP sockets to receive into. The default size is the |
---|
| 211 | following length in bytes: |
---|
[ca49bfd] | 212 | |
---|
[b412038] | 213 | .. code-block:: c |
---|
[ca49bfd] | 214 | |
---|
| 215 | 40 * (1024 + sizeof(struct sockaddr_in) |
---|
| 216 | |
---|
| 217 | ``unsigned long tcp_tx_buf_size`` |
---|
[b412038] | 218 | This configuration parameter specifies the maximum amount of buffer memory |
---|
| 219 | which may be used for TCP sockets to transmit with. The default size is |
---|
| 220 | sixteen kilobytes. |
---|
[ca49bfd] | 221 | |
---|
| 222 | ``unsigned long tcp_rx_buf_size`` |
---|
[b412038] | 223 | This configuration parameter specifies the maximum amount of buffer memory |
---|
| 224 | which may be used for TCP sockets to receive into. The default size is |
---|
| 225 | sixteen kilobytes. |
---|
[ca49bfd] | 226 | |
---|
[b412038] | 227 | ``const cpu_set_t *network_task_cpuset`` |
---|
| 228 | This configuration parameter specifies the CPU affinity of the network |
---|
| 229 | task. If set to ``0`` the network task can be scheduled on any CPU. Only |
---|
| 230 | available in SMP configurations. |
---|
[ca49bfd] | 231 | |
---|
| 232 | ``size_t network_task_cpuset_size`` |
---|
[b412038] | 233 | This configuration parameter specifies the size of the |
---|
| 234 | ``network_task_cpuset`` used. Only available in SMP configurations. |
---|
[ca49bfd] | 235 | |
---|
[b412038] | 236 | In addition, the following fields in the ``rtems_bsdnet_ifconfig`` are of |
---|
| 237 | interest. |
---|
[ca49bfd] | 238 | |
---|
| 239 | *int port* |
---|
[b412038] | 240 | The I/O port number (ex: 0x240) on which the external Ethernet can be |
---|
| 241 | accessed. |
---|
[ca49bfd] | 242 | |
---|
| 243 | *int irno* |
---|
| 244 | The interrupt number of the external Ethernet controller. |
---|
| 245 | |
---|
| 246 | *int bpar* |
---|
| 247 | The address of the shared memory on the external Ethernet controller. |
---|
| 248 | |
---|
| 249 | Network device configuration |
---|
| 250 | ---------------------------- |
---|
| 251 | |
---|
[b412038] | 252 | Network devices are specified and configured by declaring and initializing a |
---|
| 253 | ``struct rtems_bsdnet_ifconfig`` structure for each network device. |
---|
[ca49bfd] | 254 | |
---|
| 255 | The structure entries are described in the following table. An application |
---|
| 256 | which uses a single network interface, gets network configuration information |
---|
[b412038] | 257 | from a BOOTP/DHCP server, and uses the default values for all driver parameters |
---|
| 258 | needs to initialize only the first two entries in the structure. |
---|
| 259 | |
---|
| 260 | ``char *name`` |
---|
| 261 | The full name of the network device. This name consists of the driver name |
---|
| 262 | and the unit number (e.g. ``"scc1"``). The ``bsp.h`` include file usually |
---|
| 263 | defines ``RTEMS_BSP_NETWORK_DRIVER_NAME`` as the name of the primary (or |
---|
| 264 | only) network driver. |
---|
| 265 | |
---|
| 266 | ``int (*attach)(struct rtems_bsdnet_ifconfig *conf)`` |
---|
| 267 | |
---|
| 268 | The address of the driver ``attach`` function. The network initialization |
---|
| 269 | function calls this function to configure the driver and attach it to the |
---|
| 270 | network stack. The ``bsp.h`` include file usually defines |
---|
| 271 | ``RTEMS_BSP_NETWORK_DRIVER_ATTACH`` as the name of the attach function of |
---|
| 272 | the primary (or only) network driver. |
---|
| 273 | |
---|
| 274 | ``struct rtems_bsdnet_ifconfig *next`` |
---|
| 275 | A pointer to the network device configuration structure for the next |
---|
| 276 | network interface, or ``NULL`` if this is the configuration structure of |
---|
| 277 | the last network interface. |
---|
| 278 | |
---|
| 279 | ``char *ip_address`` |
---|
| 280 | The Internet address of the device, specified in 'dotted decimal' |
---|
| 281 | (``129.128.4.2``) form, or ``NULL`` if the device configuration information |
---|
| 282 | is being obtained from a BOOTP/DHCP server. |
---|
| 283 | |
---|
| 284 | ``char *ip_netmask`` |
---|
| 285 | The Internet inetwork mask of the device, specified in 'dotted decimal' |
---|
| 286 | (``255.255.255.0``) form, or ``NULL`` if the device configuration |
---|
| 287 | information is being obtained from a BOOTP/DHCP server. |
---|
| 288 | |
---|
| 289 | ``void *hardware_address`` |
---|
| 290 | The hardware address of the device, or ``NULL`` if the driver is to obtain |
---|
| 291 | the hardware address in some other way (usually by reading it from the |
---|
| 292 | device or from the bootstrap ROM). |
---|
[ca49bfd] | 293 | |
---|
| 294 | ``int ignore_broadcast`` |
---|
| 295 | Zero if the device is to accept broadcast packets, non-zero if the device |
---|
| 296 | is to ignore broadcast packets. |
---|
| 297 | |
---|
| 298 | ``int mtu`` |
---|
[b412038] | 299 | The maximum transmission unit of the device, or zero if the driver is to |
---|
| 300 | choose a default value (typically 1500 for Ethernet devices). |
---|
[ca49bfd] | 301 | |
---|
| 302 | ``int rbuf_count`` |
---|
[b412038] | 303 | The number of receive buffers to use, or zero if the driver is to choose a |
---|
| 304 | default value |
---|
[ca49bfd] | 305 | |
---|
| 306 | ``int xbuf_count`` |
---|
[b412038] | 307 | The number of transmit buffers to use, or zero if the driver is to choose a |
---|
| 308 | default value Keep in mind that some network devices may use 4 or more |
---|
[ca49bfd] | 309 | transmit descriptors for a single transmit buffer. |
---|
| 310 | |
---|
| 311 | A complete network configuration specification can be as simple as the one |
---|
[b412038] | 312 | shown in the following example. This configuration uses a single network |
---|
| 313 | interface, gets network configuration information from a BOOTP/DHCP server, and |
---|
| 314 | uses the default values for all driver parameters. |
---|
| 315 | |
---|
| 316 | .. code-block:: c |
---|
[ca49bfd] | 317 | |
---|
| 318 | static struct rtems_bsdnet_ifconfig netdriver_config = { |
---|
[b412038] | 319 | RTEMS_BSP_NETWORK_DRIVER_NAME, |
---|
| 320 | RTEMS_BSP_NETWORK_DRIVER_ATTACH |
---|
[ca49bfd] | 321 | }; |
---|
| 322 | struct rtems_bsdnet_config rtems_bsdnet_config = { |
---|
[b412038] | 323 | &netdriver_config, |
---|
| 324 | rtems_bsdnet_do_bootp, |
---|
[ca49bfd] | 325 | }; |
---|
| 326 | |
---|
| 327 | Network initialization |
---|
| 328 | ---------------------- |
---|
| 329 | |
---|
[b412038] | 330 | The networking tasks must be started before any network I/O operations can be |
---|
| 331 | performed. This is done by calling: |
---|
[ca49bfd] | 332 | |
---|
[b412038] | 333 | .. code-block:: c |
---|
[ca49bfd] | 334 | |
---|
| 335 | rtems_bsdnet_initialize_network (); |
---|
| 336 | |
---|
[b412038] | 337 | This function is declared in ``rtems/rtems_bsdnet.h``. t returns 0 on success |
---|
| 338 | and -1 on failure with an error code in ``errno``. It is not possible to undo |
---|
| 339 | the effects of a partial initialization, though, so the function can be called |
---|
| 340 | only once irregardless of the return code. Consequently, if the condition for |
---|
| 341 | the failure can be corrected, the system must be reset to permit another |
---|
| 342 | network initialization attempt. |
---|
[ca49bfd] | 343 | |
---|
| 344 | Application Programming Interface |
---|
| 345 | ================================= |
---|
| 346 | |
---|
| 347 | The RTEMS network package provides almost a complete set of BSD network |
---|
[b412038] | 348 | services. The network functions work like their BSD counterparts with the |
---|
| 349 | following exceptions: |
---|
[ca49bfd] | 350 | |
---|
| 351 | - A given socket can be read or written by only one task at a time. |
---|
| 352 | |
---|
[b412038] | 353 | - The ``select`` function only works for file descriptors associated with |
---|
| 354 | sockets. |
---|
[ca49bfd] | 355 | |
---|
| 356 | - You must call ``openlog`` before calling any of the ``syslog`` functions. |
---|
| 357 | |
---|
[b412038] | 358 | - *Some of the network functions are not thread-safe.* For example the |
---|
| 359 | following functions return a pointer to a static buffer which remains valid |
---|
| 360 | only until the next call: |
---|
[ca49bfd] | 361 | |
---|
| 362 | ``gethostbyaddr`` |
---|
| 363 | ``gethostbyname`` |
---|
[bc37517] | 364 | ``inet_ntoa`` (``inet_ntop`` is thread-safe, though). |
---|
[ca49bfd] | 365 | |
---|
| 366 | - The RTEMS network package gathers statistics. |
---|
| 367 | |
---|
[b412038] | 368 | - Addition of a mechanism to "tap onto" an interface and monitor every packet |
---|
| 369 | received and transmitted. |
---|
[ca49bfd] | 370 | |
---|
| 371 | - Addition of ``SO_SNDWAKEUP`` and ``SO_RCVWAKEUP`` socket options. |
---|
| 372 | |
---|
| 373 | Some of the new features are discussed in more detail in the following |
---|
| 374 | sections. |
---|
| 375 | |
---|
| 376 | Network Statistics |
---|
| 377 | ------------------ |
---|
| 378 | |
---|
[b412038] | 379 | There are a number of functions to print statistics gathered by the network |
---|
| 380 | stack. These function are declared in ``rtems/rtems_bsdnet.h``. |
---|
[ca49bfd] | 381 | |
---|
| 382 | ``rtems_bsdnet_show_if_stats`` |
---|
| 383 | Display statistics gathered by network interfaces. |
---|
| 384 | |
---|
| 385 | ``rtems_bsdnet_show_ip_stats`` |
---|
| 386 | Display IP packet statistics. |
---|
| 387 | |
---|
| 388 | ``rtems_bsdnet_show_icmp_stats`` |
---|
| 389 | Display ICMP packet statistics. |
---|
| 390 | |
---|
| 391 | ``rtems_bsdnet_show_tcp_stats`` |
---|
| 392 | Display TCP packet statistics. |
---|
| 393 | |
---|
| 394 | ``rtems_bsdnet_show_udp_stats`` |
---|
| 395 | Display UDP packet statistics. |
---|
| 396 | |
---|
| 397 | ``rtems_bsdnet_show_mbuf_stats`` |
---|
| 398 | Display mbuf statistics. |
---|
| 399 | |
---|
| 400 | ``rtems_bsdnet_show_inet_routes`` |
---|
| 401 | Display the routing table. |
---|
| 402 | |
---|
| 403 | Tapping Into an Interface |
---|
| 404 | ------------------------- |
---|
| 405 | |
---|
[b412038] | 406 | RTEMS add two new ioctls to the BSD networking code, ``SIOCSIFTAP`` and |
---|
| 407 | ``SIOCGIFTAP``. These may be used to set and get a *tap function*. The tap |
---|
| 408 | function will be called for every Ethernet packet received by the interface. |
---|
[ca49bfd] | 409 | |
---|
[b412038] | 410 | These are called like other interface ioctls, such as ``SIOCSIFADDR``. When |
---|
| 411 | setting the tap function with ``SIOCSIFTAP``, set the ifr_tap field of the |
---|
| 412 | ifreq struct to the tap function. When retrieving the tap function with |
---|
| 413 | ``SIOCGIFTAP``, the current tap function will be returned in the ifr_tap field. |
---|
| 414 | To stop tapping packets, call ``SIOCSIFTAP`` with a ``ifr_tap`` field of ``0``. |
---|
[ca49bfd] | 415 | |
---|
| 416 | The tap function is called like this: |
---|
| 417 | |
---|
[b412038] | 418 | .. code-block:: c |
---|
[ca49bfd] | 419 | |
---|
[b412038] | 420 | int tap (struct ifnet *, struct ether_header *, struct mbuf *) |
---|
[ca49bfd] | 421 | |
---|
[b412038] | 422 | The tap function should return ``1`` if the packet was fully handled, in which |
---|
| 423 | case the caller will simply discard the mbuf. The tap function should return |
---|
| 424 | ``0`` if the packet should be passed up to the higher networking layers. |
---|
| 425 | |
---|
| 426 | The tap function is called with the network semaphore locked. It must not make |
---|
| 427 | any calls on the application levels of the networking level itself. It is safe |
---|
| 428 | to call other non-networking RTEMS functions. |
---|
[ca49bfd] | 429 | |
---|
| 430 | Socket Options |
---|
| 431 | -------------- |
---|
| 432 | |
---|
[b412038] | 433 | RTEMS adds two new ``SOL_SOCKET`` level options for ``setsockopt`` and |
---|
| 434 | ``getsockopt``: ``SO_SNDWAKEUP`` and ``SO_RCVWAKEUP``. For both, the option |
---|
| 435 | value should point to a sockwakeup structure. The sockwakeup structure has the |
---|
| 436 | following fields: |
---|
| 437 | |
---|
| 438 | .. code-block:: c |
---|
[ca49bfd] | 439 | |
---|
[b412038] | 440 | void (*sw_pfn) (struct socket *, caddr_t); |
---|
[ca49bfd] | 441 | caddr_t sw_arg; |
---|
| 442 | |
---|
| 443 | These options are used to set a callback function to be called when, for |
---|
[b412038] | 444 | example, there is data available from the socket (``SO_RCVWAKEUP``) and when |
---|
| 445 | there is space available to accept data written to the socket |
---|
| 446 | (``SO_SNDWAKEUP``). |
---|
| 447 | |
---|
| 448 | If ``setsockopt`` is called with the ``SO_RCVWAKEUP`` option, and the |
---|
| 449 | ``sw_pfn`` field is not zero, then when there is data available to be read from |
---|
| 450 | the socket, the function pointed to by the ``sw_pfn`` field will be called. A |
---|
| 451 | pointer to the socket structure will be passed as the first argument to the |
---|
| 452 | function. The ``sw_arg`` field set by the ``SO_RCVWAKEUP`` call will be passed |
---|
| 453 | as the second argument to the function. |
---|
| 454 | |
---|
| 455 | If ``setsockopt`` is called with the ``SO_SNDWAKEUP`` function, and the |
---|
| 456 | ``sw_pfn`` field is not zero, then when there is space available to accept data |
---|
| 457 | written to the socket, the function pointed to by the ``sw_pfn`` field will be |
---|
| 458 | called. The arguments passed to the function will be as with ``SO_SNDWAKEUP``. |
---|
| 459 | |
---|
| 460 | When the function is called, the network semaphore will be locked and the |
---|
| 461 | callback function runs in the context of the networking task. The function |
---|
| 462 | must be careful not to call any networking functions. It is OK to call an |
---|
| 463 | RTEMS function; for example, it is OK to send an RTEMS event. |
---|
[ca49bfd] | 464 | |
---|
| 465 | The purpose of these callback functions is to permit a more efficient |
---|
[b412038] | 466 | alternative to the select call when dealing with a large number of sockets. |
---|
| 467 | |
---|
| 468 | The callbacks are called by the same criteria that the select function uses for |
---|
| 469 | indicating "ready" sockets. In Stevens *Unix Network Programming* on page |
---|
| 470 | 153-154 in the section "Under what Conditions Is a Descriptor Ready?" you will |
---|
| 471 | find the definitive list of conditions for readable and writable that also |
---|
| 472 | determine when the functions are called. |
---|
| 473 | |
---|
| 474 | When the number of received bytes equals or exceeds the socket receive buffer |
---|
| 475 | "low water mark" (default 1 byte) you get a readable callback. If there are 100 |
---|
| 476 | bytes in the receive buffer and you only read 1, you will not immediately get |
---|
| 477 | another callback. However, you will get another callback after you read the |
---|
| 478 | remaining 99 bytes and at least 1 more byte arrives. Using a non-blocking |
---|
| 479 | socket you should probably read until it produces error ``EWOULDBLOCK`` and |
---|
| 480 | then allow the readable callback to tell you when more data has arrived. |
---|
| 481 | (Condition 1.a.) |
---|
| 482 | |
---|
| 483 | For sending, when the socket is connected and the free space becomes at or |
---|
| 484 | above the "low water mark" for the send buffer (default 4096 bytes) you will |
---|
| 485 | receive a writable callback. You don't get continuous callbacks if you don't |
---|
| 486 | write anything. Using a non-blocking write socket, you can then call write |
---|
| 487 | until it returns a value less than the amount of data requested to be sent or |
---|
| 488 | it produces error ``EWOULDBLOCK`` (indicating buffer full and no longer |
---|
| 489 | writable). When this happens you can try the write again, but it is often |
---|
| 490 | better to go do other things and let the writable callback tell you when space |
---|
| 491 | is available to send again. You only get a writable callback when the free |
---|
| 492 | space transitions to above the "low water mark" and not every time you write to |
---|
| 493 | a non-full send buffer. (Condition 2.a.) |
---|
| 494 | |
---|
| 495 | The remaining conditions enumerated by Stevens handle the fact that sockets |
---|
| 496 | become readable and/or writable when connects, disconnects and errors occur, |
---|
| 497 | not just when data is received or sent. For example, when a server "listening" |
---|
| 498 | socket becomes readable it indicates that a client has connected and accept can |
---|
| 499 | be called without blocking, not that network data was received (Condition 1.c). |
---|
[ca49bfd] | 500 | |
---|
| 501 | Adding an IP Alias |
---|
| 502 | ------------------ |
---|
| 503 | |
---|
| 504 | The following code snippet adds an IP alias: |
---|
| 505 | |
---|
[b412038] | 506 | .. code-block:: c |
---|
| 507 | |
---|
| 508 | void addAlias(const char *pName, const char *pAddr, const char *pMask) |
---|
[ca49bfd] | 509 | { |
---|
[b412038] | 510 | struct ifaliasreq aliasreq; |
---|
| 511 | struct sockaddr_in *in; |
---|
| 512 | |
---|
| 513 | /* initialize alias request */ |
---|
| 514 | memset(&aliasreq, 0, sizeof(aliasreq)); |
---|
| 515 | sprintf(aliasreq.ifra_name, pName); |
---|
| 516 | |
---|
| 517 | /* initialize alias address */ |
---|
| 518 | in = (struct sockaddr_in *)&aliasreq.ifra_addr; |
---|
| 519 | in->sin_family = AF_INET; |
---|
| 520 | in->sin_len = sizeof(aliasreq.ifra_addr); |
---|
| 521 | in->sin_addr.s_addr = inet_addr(pAddr); |
---|
| 522 | |
---|
| 523 | /* initialize alias mask */ |
---|
| 524 | in = (struct sockaddr_in *)&aliasreq.ifra_mask; |
---|
| 525 | in->sin_family = AF_INET; |
---|
| 526 | in->sin_len = sizeof(aliasreq.ifra_mask); |
---|
| 527 | in->sin_addr.s_addr = inet_addr(pMask); |
---|
| 528 | |
---|
| 529 | /* call to setup the alias */ |
---|
| 530 | rtems_bsdnet_ifconfig(pName, SIOCAIFADDR, &aliasreq); |
---|
[ca49bfd] | 531 | } |
---|
| 532 | |
---|
[b412038] | 533 | Thanks to Mike Seirs <mailto:mikes@poliac.com> for this example code. |
---|
[ca49bfd] | 534 | |
---|
| 535 | Adding a Default Route |
---|
| 536 | ---------------------- |
---|
| 537 | |
---|
[b412038] | 538 | The function provided in this section is functionally equivalent to the command |
---|
| 539 | ``route add default gw yyy.yyy.yyy.yyy``: |
---|
[ca49bfd] | 540 | |
---|
[b412038] | 541 | .. code-block:: c |
---|
| 542 | |
---|
| 543 | void mon_ifconfig(int argc, char *argv[], unsigned32 command_arg, bool verbose) |
---|
[ca49bfd] | 544 | { |
---|
[b412038] | 545 | struct sockaddr_in ipaddr; |
---|
| 546 | struct sockaddr_in dstaddr; |
---|
| 547 | struct sockaddr_in netmask; |
---|
| 548 | struct sockaddr_in broadcast; |
---|
| 549 | char *iface; |
---|
| 550 | int f_ip = 0; |
---|
| 551 | int f_ptp = 0; |
---|
| 552 | int f_netmask = 0; |
---|
| 553 | int f_up = 0; |
---|
| 554 | int f_down = 0; |
---|
| 555 | int f_bcast = 0; |
---|
| 556 | int cur_idx; |
---|
| 557 | int rc; |
---|
| 558 | int flags; |
---|
| 559 | |
---|
| 560 | bzero((void*) &ipaddr, sizeof(ipaddr)); |
---|
| 561 | bzero((void*) &dstaddr, sizeof(dstaddr)); |
---|
| 562 | bzero((void*) &netmask, sizeof(netmask)); |
---|
| 563 | bzero((void*) &broadcast, sizeof(broadcast)); |
---|
| 564 | ipaddr.sin_len = sizeof(ipaddr); |
---|
| 565 | ipaddr.sin_family = AF_INET; |
---|
| 566 | dstaddr.sin_len = sizeof(dstaddr); |
---|
| 567 | dstaddr.sin_family = AF_INET; |
---|
| 568 | netmask.sin_len = sizeof(netmask); |
---|
| 569 | netmask.sin_family = AF_INET; |
---|
| 570 | broadcast.sin_len = sizeof(broadcast); |
---|
| 571 | broadcast.sin_family = AF_INET; |
---|
| 572 | cur_idx = 0; |
---|
| 573 | |
---|
| 574 | if (argc <= 1) { |
---|
| 575 | /* display all interfaces */ |
---|
| 576 | iface = NULL; |
---|
| 577 | cur_idx += 1; |
---|
| 578 | } else { |
---|
| 579 | iface = argv[1]; |
---|
| 580 | if (isdigit(*argv[2])) { |
---|
| 581 | if (inet_pton(AF_INET, argv[2], &ipaddr.sin_addr) < 0) { |
---|
| 582 | printf("bad ip address: %s\n", argv[2]); |
---|
| 583 | return; |
---|
| 584 | } |
---|
| 585 | f_ip = 1; |
---|
| 586 | cur_idx += 3; |
---|
| 587 | } else { |
---|
| 588 | cur_idx += 2; |
---|
| 589 | } |
---|
| 590 | } |
---|
| 591 | |
---|
| 592 | if ((f_down !=0) && (f_ip != 0)) { |
---|
| 593 | f_up = 1; |
---|
| 594 | } |
---|
| 595 | |
---|
| 596 | while(argc > cur_idx) { |
---|
| 597 | if (strcmp(argv[cur_idx], "up") == 0) { |
---|
| 598 | f_up = 1; |
---|
| 599 | if (f_down != 0) { |
---|
| 600 | printf("Can't make interface up and down\n"); |
---|
| 601 | } |
---|
| 602 | } else if(strcmp(argv[cur_idx], "down") == 0) { |
---|
| 603 | f_down = 1; |
---|
| 604 | if (f_up != 0) { |
---|
| 605 | printf("Can't make interface up and down\n"); |
---|
| 606 | } |
---|
| 607 | } else if(strcmp(argv[cur_idx], "netmask") == 0) { |
---|
| 608 | if ((cur_idx + 1) >= argc) { |
---|
| 609 | printf("No netmask address\n"); |
---|
| 610 | return; |
---|
| 611 | } |
---|
| 612 | if (inet_pton(AF_INET, argv[cur_idx+1], &netmask.sin_addr) < 0) { |
---|
| 613 | printf("bad netmask: %s\n", argv[cur_idx]); |
---|
| 614 | return; |
---|
| 615 | } |
---|
| 616 | f_netmask = 1; |
---|
| 617 | cur_idx += 1; |
---|
| 618 | } else if(strcmp(argv[cur_idx], "broadcast") == 0) { |
---|
| 619 | if ((cur_idx + 1) >= argc) { |
---|
| 620 | printf("No broadcast address\n"); |
---|
| 621 | return; |
---|
| 622 | } |
---|
| 623 | if (inet_pton(AF_INET, argv[cur_idx+1], &broadcast.sin_addr) < 0) { |
---|
| 624 | printf("bad broadcast: %s\n", argv[cur_idx]); |
---|
| 625 | return; |
---|
| 626 | } |
---|
| 627 | f_bcast = 1; |
---|
| 628 | cur_idx += 1; |
---|
| 629 | } else if(strcmp(argv[cur_idx], "pointopoint") == 0) { |
---|
| 630 | if ((cur_idx + 1) >= argc) { |
---|
| 631 | printf("No pointopoint address\n"); |
---|
| 632 | return; |
---|
| 633 | } |
---|
| 634 | if (inet_pton(AF_INET, argv[cur_idx+1], &dstaddr.sin_addr) < 0) { |
---|
| 635 | printf("bad pointopoint: %s\n", argv[cur_idx]); |
---|
| 636 | return; |
---|
| 637 | } |
---|
| 638 | f_ptp = 1; |
---|
| 639 | cur_idx += 1; |
---|
| 640 | } else { |
---|
| 641 | printf("Bad parameter: %s\n", argv[cur_idx]); |
---|
| 642 | return; |
---|
| 643 | } |
---|
| 644 | cur_idx += 1; |
---|
| 645 | } |
---|
| 646 | |
---|
| 647 | printf("ifconfig "); |
---|
| 648 | |
---|
| 649 | if (iface != NULL) { |
---|
| 650 | printf("%s ", iface); |
---|
| 651 | if (f_ip != 0) { |
---|
| 652 | char str[256]; |
---|
| 653 | inet_ntop(AF_INET, &ipaddr.sin_addr, str, 256); |
---|
| 654 | printf("%s ", str); |
---|
| 655 | } |
---|
| 656 | if (f_netmask != 0) { |
---|
| 657 | char str[256]; |
---|
| 658 | inet_ntop(AF_INET, &netmask.sin_addr, str, 256); |
---|
| 659 | printf("netmask %s ", str); |
---|
| 660 | } |
---|
| 661 | if (f_bcast != 0) { |
---|
| 662 | char str[256]; |
---|
| 663 | inet_ntop(AF_INET, &broadcast.sin_addr, str, 256); |
---|
| 664 | printf("broadcast %s ", str); |
---|
| 665 | } |
---|
| 666 | if (f_ptp != 0) { |
---|
| 667 | char str[256]; |
---|
| 668 | inet_ntop(AF_INET, &dstaddr.sin_addr, str, 256); |
---|
| 669 | printf("pointopoint %s ", str); |
---|
| 670 | } |
---|
| 671 | if (f_up != 0) { |
---|
| 672 | printf("up\n"); |
---|
| 673 | } else if (f_down != 0) { |
---|
| 674 | printf("down\n"); |
---|
| 675 | } else { |
---|
| 676 | printf("\n"); |
---|
| 677 | } |
---|
| 678 | } |
---|
| 679 | |
---|
| 680 | if ((iface == NULL) || ((f_ip == 0) && (f_down == 0) && (f_up == 0))) { |
---|
| 681 | rtems_bsdnet_show_if_stats(); |
---|
| 682 | return; |
---|
| 683 | } |
---|
| 684 | |
---|
| 685 | flags = 0; |
---|
| 686 | if (f_netmask) { |
---|
| 687 | rc = rtems_bsdnet_ifconfig(iface, SIOCSIFNETMASK, &netmask); |
---|
| 688 | if (rc < 0) { |
---|
| 689 | printf("Could not set netmask: %s\n", strerror(errno)); |
---|
| 690 | return; |
---|
| 691 | } |
---|
| 692 | } |
---|
| 693 | if (f_bcast) { |
---|
| 694 | rc = rtems_bsdnet_ifconfig(iface, SIOCSIFBRDADDR, &broadcast); |
---|
| 695 | if (rc < 0) { |
---|
| 696 | printf("Could not set broadcast: %s\n", strerror(errno)); |
---|
| 697 | return; |
---|
| 698 | } |
---|
| 699 | } |
---|
| 700 | if (f_ptp) { |
---|
| 701 | rc = rtems_bsdnet_ifconfig(iface, SIOCSIFDSTADDR, &dstaddr); |
---|
| 702 | if (rc < 0) { |
---|
| 703 | printf("Could not set destination address: %s\n", strerror(errno)); |
---|
| 704 | return; |
---|
| 705 | } |
---|
| 706 | flags |= IFF_POINTOPOINT; |
---|
| 707 | } |
---|
| 708 | |
---|
| 709 | /* This must come _after_ setting the netmask, broadcast addresses */ |
---|
| 710 | if (f_ip) { |
---|
| 711 | rc = rtems_bsdnet_ifconfig(iface, SIOCSIFADDR, &ipaddr); |
---|
| 712 | if (rc < 0) { |
---|
| 713 | printf("Could not set IP address: %s\n", strerror(errno)); |
---|
| 714 | return; |
---|
| 715 | } |
---|
| 716 | } |
---|
| 717 | if (f_up != 0) { |
---|
| 718 | flags |= IFF_UP; |
---|
| 719 | } |
---|
| 720 | if (f_down != 0) { |
---|
| 721 | printf("Warning: taking interfaces down is not supported\n"); |
---|
| 722 | } |
---|
| 723 | |
---|
| 724 | rc = rtems_bsdnet_ifconfig(iface, SIOCSIFFLAGS, &flags); |
---|
| 725 | if (rc < 0) { |
---|
| 726 | printf("Could not set interface flags: %s\n", strerror(errno)); |
---|
| 727 | return; |
---|
| 728 | } |
---|
| 729 | } |
---|
| 730 | |
---|
| 731 | void mon_route(int argc, char *argv[], unsigned32 command_arg, bool verbose) |
---|
[ca49bfd] | 732 | { |
---|
[b412038] | 733 | int cmd; |
---|
| 734 | struct sockaddr_in dst; |
---|
| 735 | struct sockaddr_in gw; |
---|
| 736 | struct sockaddr_in netmask; |
---|
| 737 | int f_host; |
---|
| 738 | int f_gw = 0; |
---|
| 739 | int cur_idx; |
---|
| 740 | int flags; |
---|
| 741 | int rc; |
---|
| 742 | |
---|
| 743 | memset(&dst, 0, sizeof(dst)); |
---|
| 744 | memset(&gw, 0, sizeof(gw)); |
---|
| 745 | memset(&netmask, 0, sizeof(netmask)); |
---|
| 746 | dst.sin_len = sizeof(dst); |
---|
| 747 | dst.sin_family = AF_INET; |
---|
| 748 | dst.sin_addr.s_addr = inet_addr("0.0.0.0"); |
---|
| 749 | gw.sin_len = sizeof(gw); |
---|
| 750 | gw.sin_family = AF_INET; |
---|
| 751 | gw.sin_addr.s_addr = inet_addr("0.0.0.0"); |
---|
| 752 | netmask.sin_len = sizeof(netmask); |
---|
| 753 | netmask.sin_family = AF_INET; |
---|
| 754 | netmask.sin_addr.s_addr = inet_addr("255.255.255.0"); |
---|
| 755 | |
---|
| 756 | if (argc < 2) { |
---|
| 757 | rtems_bsdnet_show_inet_routes(); |
---|
| 758 | return; |
---|
| 759 | } |
---|
| 760 | |
---|
| 761 | if (strcmp(argv[1], "add") == 0) { |
---|
| 762 | cmd = RTM_ADD; |
---|
| 763 | } else if (strcmp(argv[1], "del") == 0) { |
---|
| 764 | cmd = RTM_DELETE; |
---|
| 765 | } else { |
---|
| 766 | printf("invalid command: %s\n", argv[1]); |
---|
| 767 | printf("\tit should be 'add' or 'del'\n"); |
---|
| 768 | return; |
---|
| 769 | } |
---|
| 770 | |
---|
| 771 | if (argc < 3) { |
---|
| 772 | printf("not enough arguments\n"); |
---|
| 773 | return; |
---|
| 774 | } |
---|
| 775 | |
---|
| 776 | if (strcmp(argv[2], "-host") == 0) { |
---|
| 777 | f_host = 1; |
---|
| 778 | } else if (strcmp(argv[2], "-net") == 0) { |
---|
| 779 | f_host = 0; |
---|
| 780 | } else { |
---|
| 781 | printf("Invalid type: %s\n", argv[1]); |
---|
| 782 | printf("\tit should be '-host' or '-net'\n"); |
---|
| 783 | return; |
---|
| 784 | } |
---|
| 785 | |
---|
| 786 | if (argc < 4) { |
---|
| 787 | printf("not enough arguments\n"); |
---|
| 788 | return; |
---|
| 789 | } |
---|
| 790 | |
---|
| 791 | inet_pton(AF_INET, argv[3], &dst.sin_addr); |
---|
| 792 | |
---|
| 793 | cur_idx = 4; |
---|
| 794 | while(cur_idx < argc) { |
---|
| 795 | if (strcmp(argv[cur_idx], "gw") == 0) { |
---|
| 796 | if ((cur_idx +1) >= argc) { |
---|
| 797 | printf("no gateway address\n"); |
---|
| 798 | return; |
---|
| 799 | } |
---|
| 800 | f_gw = 1; |
---|
| 801 | inet_pton(AF_INET, argv[cur_idx + 1], &gw.sin_addr); |
---|
| 802 | cur_idx += 1; |
---|
| 803 | } else if(strcmp(argv[cur_idx], "netmask") == 0) { |
---|
| 804 | if ((cur_idx +1) >= argc) { |
---|
| 805 | printf("no netmask address\n"); |
---|
| 806 | return; |
---|
| 807 | } |
---|
| 808 | f_gw = 1; |
---|
| 809 | inet_pton(AF_INET, argv[cur_idx + 1], &netmask.sin_addr); |
---|
| 810 | cur_idx += 1; |
---|
| 811 | } else { |
---|
| 812 | printf("Unknown argument\n"); |
---|
| 813 | return; |
---|
| 814 | } |
---|
| 815 | cur_idx += 1; |
---|
| 816 | } |
---|
| 817 | |
---|
| 818 | flags = RTF_STATIC; |
---|
| 819 | if (f_gw != 0) { |
---|
| 820 | flags |= RTF_GATEWAY; |
---|
| 821 | } |
---|
| 822 | if (f_host != 0) { |
---|
| 823 | flags |= RTF_HOST; |
---|
| 824 | } |
---|
| 825 | |
---|
| 826 | rc = rtems_bsdnet_rtrequest(cmd, &dst, &gw, &netmask, flags, NULL); |
---|
| 827 | if (rc < 0) { |
---|
| 828 | printf("Error adding route\n"); |
---|
| 829 | } |
---|
| 830 | } |
---|
| 831 | |
---|
| 832 | Thanks to Jay Monkman <mailto:jtm@smoothmsmoothie.com> for this example |
---|
[ca49bfd] | 833 | code. |
---|
| 834 | |
---|
| 835 | Time Synchronization Using NTP |
---|
| 836 | ------------------------------ |
---|
| 837 | |
---|
[b412038] | 838 | .. code-block:: c |
---|
[ca49bfd] | 839 | |
---|
| 840 | int rtems_bsdnet_synchronize_ntp (int interval, rtems_task_priority priority); |
---|
| 841 | |
---|
[b412038] | 842 | If the interval argument is ``0`` the routine synchronizes the RTEMS |
---|
| 843 | time-of-day clock with the first NTP server in the ``rtems_bsdnet_ntpserve`` |
---|
| 844 | array and returns. The priority argument is ignored. |
---|
[ca49bfd] | 845 | |
---|
[b412038] | 846 | If the interval argument is greater than 0, the routine also starts an RTEMS |
---|
| 847 | task at the specified priority and polls the NTP server every 'interval' |
---|
| 848 | seconds. NOTE: This mode of operation has not yet been implemented. |
---|
[ca49bfd] | 849 | |
---|
| 850 | On successful synchronization of the RTEMS time-of-day clock the routine |
---|
[b412038] | 851 | returns ``0``. If an error occurs a message is printed and the routine returns |
---|
| 852 | ``-1`` with an error code in errno. There is no timeout - if there is no |
---|
| 853 | response from an NTP server the routine will wait forever. |
---|