]> granicus.if.org Git - esp-idf/blob - components/mdns/mdns_networking.c
Merge branch 'bugfix/esp-tls-doc' into 'master'
[esp-idf] / components / mdns / mdns_networking.c
1
2 /*
3  * MDNS Server Networking
4  * 
5  */
6 #include <string.h>
7 #include "mdns_networking.h"
8
9
10 extern mdns_server_t * _mdns_server;
11
12 /*
13  * MDNS Server Networking
14  *
15  */
16
17 static struct udp_pcb * _pcb_main = NULL;
18
19 static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport);
20
21 /**
22  * @brief  Low level UDP PCB Initialize
23  */
24 static esp_err_t _udp_pcb_main_init()
25 {
26     if(_pcb_main) {
27         return ESP_OK;
28     }
29     _pcb_main = udp_new();
30     if (!_pcb_main) {
31         return ESP_ERR_NO_MEM;
32     }
33     if (udp_bind(_pcb_main, IP_ANY_TYPE, MDNS_SERVICE_PORT) != 0) {
34         udp_remove(_pcb_main);
35         _pcb_main = NULL;
36         return ESP_ERR_INVALID_STATE;
37     }
38     _pcb_main->mcast_ttl = 1;
39     _pcb_main->remote_port = MDNS_SERVICE_PORT;
40     ip_addr_copy(_pcb_main->remote_ip, ip_addr_any_type);
41     udp_recv(_pcb_main, &_udp_recv, _mdns_server);
42     return ESP_OK;
43 }
44
45 /**
46  * @brief  Low level UDP PCB Free
47  */
48 static void _udp_pcb_main_deinit()
49 {
50     if(_pcb_main){
51         udp_recv(_pcb_main, NULL, NULL);
52         udp_disconnect(_pcb_main);
53         udp_remove(_pcb_main);
54         _pcb_main = NULL;
55     }
56 }
57
58 /**
59  * @brief  Low level UDP Multicast membership control
60  */
61 static esp_err_t _udp_join_group(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, bool join)
62 {
63     struct netif * netif = NULL;
64     void * nif = NULL;
65
66     if (!tcpip_adapter_is_netif_up(tcpip_if)) {
67         // Network interface went down before event propagated, skipping IGMP config
68         return ESP_ERR_INVALID_STATE;
69     }
70
71     esp_err_t err = tcpip_adapter_get_netif(tcpip_if, &nif);
72     if (err) {
73         return ESP_ERR_INVALID_ARG;
74     }
75     netif = (struct netif *)nif;
76
77     if (ip_protocol == MDNS_IP_PROTOCOL_V4) {
78         ip_addr_t multicast_addr;
79         IP_ADDR4(&multicast_addr, 224, 0, 0, 251);
80
81         if(join){
82             if (igmp_joingroup_netif(netif, (const struct ip4_addr *)&multicast_addr.u_addr.ip4)) {
83                 return ESP_ERR_INVALID_STATE;
84             }
85         } else {
86             if (igmp_leavegroup_netif(netif, (const struct ip4_addr *)&multicast_addr.u_addr.ip4)) {
87                 return ESP_ERR_INVALID_STATE;
88             }
89         }
90     } else {
91         ip_addr_t multicast_addr = IPADDR6_INIT(0x000002ff, 0, 0, 0xfb000000);
92
93         if(join){
94             if (mld6_joingroup_netif(netif, &(multicast_addr.u_addr.ip6))) {
95                 return ESP_ERR_INVALID_STATE;
96             }
97         } else {
98             if (mld6_leavegroup_netif(netif, &(multicast_addr.u_addr.ip6))) {
99                 return ESP_ERR_INVALID_STATE;
100             }
101         }
102     }
103     return ESP_OK;
104 }
105
106 /**
107  * @brief  the receive callback of the raw udp api. Packets are received here
108  *
109  */
110 static void _udp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *pb, const ip_addr_t *raddr, uint16_t rport)
111 {
112
113     uint8_t i;
114     while (pb != NULL) {
115         struct pbuf * this_pb = pb;
116         pb = pb->next;
117         this_pb->next = NULL;
118
119         mdns_rx_packet_t * packet = (mdns_rx_packet_t *)malloc(sizeof(mdns_rx_packet_t));
120         if (!packet) {
121             //missed packet - no memory
122             pbuf_free(this_pb);
123             continue;
124         }
125
126         packet->tcpip_if = TCPIP_ADAPTER_IF_MAX;
127         packet->pb = this_pb;
128         packet->src_port = rport;
129         memcpy(&packet->src, raddr, sizeof(ip_addr_t));
130         packet->dest.type = packet->src.type;
131
132         if (packet->src.type == IPADDR_TYPE_V4) {
133             packet->ip_protocol = MDNS_IP_PROTOCOL_V4;
134             struct ip_hdr * iphdr = (struct ip_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP_HLEN);
135             packet->dest.u_addr.ip4.addr = iphdr->dest.addr;
136         } else {
137             packet->ip_protocol = MDNS_IP_PROTOCOL_V6;
138             struct ip6_hdr * ip6hdr = (struct ip6_hdr *)(((uint8_t *)(packet->pb->payload)) - UDP_HLEN - IP6_HLEN);
139             memcpy(&packet->dest.u_addr.ip6.addr, (uint8_t *)ip6hdr->dest.addr, 16);
140         }
141         packet->multicast = ip_addr_ismulticast(&(packet->dest));
142
143         //lwip does not return the proper pcb if you have more than one for the same multicast address (but different interfaces)
144         struct netif * netif = NULL;
145         void * nif = NULL;
146         struct udp_pcb * pcb = NULL;
147         for (i=0; i<TCPIP_ADAPTER_IF_MAX; i++) {
148             pcb = _mdns_server->interfaces[i].pcbs[packet->ip_protocol].pcb;
149             tcpip_adapter_get_netif (i, &nif);
150             netif = (struct netif *)nif;
151             if (pcb && netif && netif == ip_current_input_netif ()) {
152                 if (packet->src.type == IPADDR_TYPE_V4) {
153                     if ((packet->src.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr) != (netif->ip_addr.u_addr.ip4.addr & netif->netmask.u_addr.ip4.addr)) {
154                         //packet source is not in the same subnet
155                         pcb = NULL;
156                         break;
157                     }
158                 }
159                 packet->tcpip_if = i;
160                 break;
161             }
162             pcb = NULL;
163         }
164
165         if (!pcb || !_mdns_server || !_mdns_server->action_queue
166           || _mdns_send_rx_action(packet) != ESP_OK) {
167             pbuf_free(this_pb);
168             free(packet);
169         }
170     }
171
172 }
173
174 /**
175  * @brief  Check if any of the interfaces is up
176  */
177 static bool _udp_pcb_is_in_use(){
178     int i, p;
179     for (i=0; i<TCPIP_ADAPTER_IF_MAX; i++) {
180         for (p=0; p<MDNS_IP_PROTOCOL_MAX; p++) {
181             if(_mdns_server->interfaces[i].pcbs[p].pcb){
182                 return true;
183             }
184         }
185     }
186     return false;
187 }
188
189 /**
190  * @brief  Stop PCB Main code
191  */
192 static void _udp_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
193 {
194     if (!_mdns_server) {
195         return;
196     }
197     mdns_pcb_t * _pcb = &_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol];
198     if (_pcb->pcb) {
199         free(_pcb->probe_services);
200         _pcb->state = PCB_OFF;
201         _pcb->pcb = NULL;
202         _pcb->probe_ip = false;
203         _pcb->probe_services = NULL;
204         _pcb->probe_services_len = 0;
205         _pcb->probe_running = false;
206         _pcb->failed_probes = 0;
207         _udp_join_group(tcpip_if, ip_protocol, false);
208         if(!_udp_pcb_is_in_use()) {
209             _udp_pcb_main_deinit();
210         }
211     }
212 }
213
214 /**
215  * @brief  Start PCB Main code
216  */
217 static esp_err_t _udp_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
218 {
219     if (!_mdns_server || _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb) {
220         return ESP_ERR_INVALID_STATE;
221     }
222
223     esp_err_t err = _udp_join_group(tcpip_if, ip_protocol, true);
224     if(err){
225         return err;
226     }
227
228     err = _udp_pcb_main_init();
229     if(err){
230         return err;
231     }
232
233     _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb = _pcb_main;
234     _mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].failed_probes = 0;
235     return ESP_OK;
236 }
237
238 typedef struct {
239     struct tcpip_api_call_data call;
240     tcpip_adapter_if_t tcpip_if;
241     mdns_ip_protocol_t ip_protocol;
242     esp_err_t err;
243 } mdns_api_call_t;
244
245 /**
246  * @brief  Start PCB from LwIP thread
247  */
248 static err_t _mdns_pcb_init_api(struct tcpip_api_call_data *api_call_msg)
249 {
250     mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg;
251     msg->err = _udp_pcb_init(msg->tcpip_if, msg->ip_protocol);
252     return msg->err;
253 }
254
255 /**
256  * @brief  Stop PCB from LwIP thread
257  */
258 static err_t _mdns_pcb_deinit_api(struct tcpip_api_call_data *api_call_msg)
259 {
260     mdns_api_call_t * msg = (mdns_api_call_t *)api_call_msg;
261     _udp_pcb_deinit(msg->tcpip_if, msg->ip_protocol);
262     msg->err = ESP_OK;
263     return ESP_OK;
264 }
265
266 /*
267  * Non-static functions below are
268  *  - _mdns prefixed
269  *  - commented in mdns_networking.h header
270  */
271 esp_err_t _mdns_pcb_init(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
272 {
273     mdns_api_call_t msg = {
274         .tcpip_if = tcpip_if,
275         .ip_protocol = ip_protocol
276     };
277     tcpip_api_call(_mdns_pcb_init_api, (struct tcpip_api_call_data*)&msg);
278     return msg.err;
279 }
280
281 esp_err_t _mdns_pcb_deinit(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol)
282 {
283     mdns_api_call_t msg = {
284         .tcpip_if = tcpip_if,
285         .ip_protocol = ip_protocol
286     };
287     tcpip_api_call(_mdns_pcb_deinit_api, (struct tcpip_api_call_data*)&msg);
288     return msg.err;
289 }
290
291 size_t _mdns_udp_pcb_write(tcpip_adapter_if_t tcpip_if, mdns_ip_protocol_t ip_protocol, const ip_addr_t *ip, uint16_t port, uint8_t * data, size_t len)
292 {
293     struct netif * netif = NULL;
294     void * nif = NULL;
295     esp_err_t err = tcpip_adapter_get_netif(tcpip_if, &nif);
296     netif = (struct netif *)nif;
297     if (err) {
298         return 0;
299     }
300
301     struct pbuf* pbt = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
302     if (pbt == NULL) {
303         return 0;
304     }
305     memcpy((uint8_t *)pbt->payload, data, len);
306
307     err = udp_sendto_if (_mdns_server->interfaces[tcpip_if].pcbs[ip_protocol].pcb, pbt, ip, port, netif);
308     pbuf_free(pbt);
309     if (err) {
310         return 0;
311     }
312     return len;
313 }