1#include "utils.h"
2#include <pico_ipv4.h>
3#include <pico_socket.h>
4
5extern void app_udpecho(char *arg);
6
7/*** START Multicast RECEIVE + ECHO ***/
8/*
9 * multicast receive expects the following format: mcastreceive:link_addr:mcast_addr:listen_port:sendto_port
10 * link_addr: mcastreceive picoapp IP address
11 * mcast_addr: multicast IP address to receive
12 * listen_port: port number on which the mcastreceive listens
13 * sendto_port: port number to echo multicast traffic to (echo to originating IP address)
14 *
15 * f.e.: ./build/test/picoapp.elf --vde pic1:/tmp/pic0.ctl:10.40.0.3:255.255.0.0: -a mcastreceive:10.40.0.3:224.7.7.7:6667:6667
16 */
17extern struct udpclient_pas *udpclient_pas;
18extern struct udpecho_pas *udpecho_pas;
19#ifdef PICO_SUPPORT_MCAST
20void app_mcastreceive(char *arg)
21{
22    char *new_arg = NULL, *p = NULL, *nxt = arg;
23    char *laddr = NULL, *maddr = NULL, *lport = NULL, *sport = NULL;
24    uint16_t listen_port = 0;
25    union pico_address inaddr_link = {
26        0
27    }, inaddr_mcast = {
28        0
29    };
30    struct pico_ip_mreq mreq = ZERO_MREQ;
31    struct pico_ip_mreq_source mreq_source = ZERO_MREQ_SRC;
32
33    /* start of parameter parsing */
34    if (nxt) {
35        nxt = cpy_arg(&laddr, nxt);
36        if (laddr) {
37            pico_string_to_ipv4(laddr, &inaddr_link.ip4.addr);
38        } else {
39            goto out;
40        }
41    } else {
42        /* no arguments */
43        goto out;
44    }
45
46    if (nxt) {
47        nxt = cpy_arg(&maddr, nxt);
48        if (maddr) {
49            pico_string_to_ipv4(maddr, &inaddr_mcast.ip4.addr);
50        } else {
51            goto out;
52        }
53    } else {
54        /* missing multicast address */
55        goto out;
56    }
57
58    if (nxt) {
59        nxt = cpy_arg(&lport, nxt);
60        if (lport && atoi(lport)) {
61            listen_port = short_be(atoi(lport));
62        } else {
63            /* incorrect listen_port */
64            goto out;
65        }
66    } else {
67        /* missing listen_port */
68        goto out;
69    }
70
71    if (nxt) {
72        nxt = cpy_arg(&sport, nxt);
73        if (sport && atoi(sport)) {
74            /* unused at this moment */
75            /* send_port = short_be(atoi(sport)); */
76        } else {
77            /* incorrect send_port */
78            goto out;
79        }
80    } else {
81        /* missing send_port */
82        goto out;
83    }
84
85    /* end of parameter parsing */
86
87    printf("\n%s: multicast receive started. Receiving packets on %s:%d\n\n", __FUNCTION__, maddr, short_be(listen_port));
88
89    /* udpecho:bind_addr:listen_port[:sendto_port:datasize] */
90    new_arg = calloc(1, strlen(laddr) + 1 + strlen(lport) + 1 + strlen(sport) + strlen(":64:") + 1);
91    p = strcat(new_arg, laddr);
92    p = strcat(p + strlen(laddr), ":");
93    p = strcat(p + 1, lport);
94    p = strcat(p + strlen(lport), ":");
95    p = strcat(p + 1, sport);
96    p = strcat(p + strlen(sport), ":64:");
97
98    app_udpecho(new_arg);
99
100    mreq.mcast_group_addr = mreq_source.mcast_group_addr = inaddr_mcast;
101    mreq.mcast_link_addr = mreq_source.mcast_link_addr = inaddr_link;
102    mreq_source.mcast_source_addr.ip4.addr = long_be(0XAC100101);
103    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) {
104        printf("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
105    }
106
107    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) {
108        printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
109    }
110
111    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_MEMBERSHIP, &mreq) < 0) {
112        printf("%s: socket_setoption PICO_IP_ADD_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
113    }
114
115    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_BLOCK_SOURCE, &mreq_source) < 0) {
116        printf("%s: socket_setoption PICO_IP_BLOCK_SOURCE failed: %s\n", __FUNCTION__, strerror(pico_err));
117    }
118
119    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_UNBLOCK_SOURCE, &mreq_source) < 0) {
120        printf("%s: socket_setoption PICO_IP_UNBLOCK_SOURCE failed: %s\n", __FUNCTION__, strerror(pico_err));
121    }
122
123    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) {
124        printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
125    }
126
127    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
128        printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
129    }
130
131    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
132        printf("%s: socket_setoption PICO_IP_DROP_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
133    }
134
135    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
136        printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
137    }
138
139    mreq_source.mcast_source_addr.ip4.addr = long_be(0XAC10010A);
140    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
141        printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
142    }
143
144    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_DROP_MEMBERSHIP, &mreq) < 0) {
145        printf("%s: socket_setoption PICO_IP_DROP_MEMBERSHIP failed: %s\n", __FUNCTION__, strerror(pico_err));
146    }
147
148    mreq_source.mcast_source_addr.ip4.addr = long_be(0XAC100101);
149    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
150        printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
151    }
152
153    mreq_source.mcast_group_addr.ip4.addr = long_be(0XE0010101);
154    if(pico_socket_setoption(udpecho_pas->s, PICO_IP_ADD_SOURCE_MEMBERSHIP, &mreq_source) < 0) {
155        printf("%s: socket_setoption PICO_IP_ADD_SOURCE_MEMBERSHIP: %s\n", __FUNCTION__, strerror(pico_err));
156    }
157
158    return;
159
160out:
161    fprintf(stderr, "mcastreceive expects the following format: mcastreceive:link_addr:mcast_addr:listen_port[:send_port]\n");
162    exit(255);
163}
164#else
165void app_mcastreceive(char *arg)
166{
167    printf("ERROR: PICO_SUPPORT_MCAST disabled\n");
168    return;
169}
170#endif
171/*** END Multicast RECEIVE + ECHO ***/
172