197dc5e69SMatthias Ringwald /* 297dc5e69SMatthias Ringwald * The MIT License (MIT) 397dc5e69SMatthias Ringwald * 497dc5e69SMatthias Ringwald * Copyright (c) 2015 by Sergey Fetisov <[email protected]> 597dc5e69SMatthias Ringwald * 697dc5e69SMatthias Ringwald * Permission is hereby granted, free of charge, to any person obtaining a copy 797dc5e69SMatthias Ringwald * of this software and associated documentation files (the "Software"), to deal 897dc5e69SMatthias Ringwald * in the Software without restriction, including without limitation the rights 997dc5e69SMatthias Ringwald * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1097dc5e69SMatthias Ringwald * copies of the Software, and to permit persons to whom the Software is 1197dc5e69SMatthias Ringwald * furnished to do so, subject to the following conditions: 1297dc5e69SMatthias Ringwald * 1397dc5e69SMatthias Ringwald * The above copyright notice and this permission notice shall be included in all 1497dc5e69SMatthias Ringwald * copies or substantial portions of the Software. 1597dc5e69SMatthias Ringwald * 1697dc5e69SMatthias Ringwald * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1797dc5e69SMatthias Ringwald * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1897dc5e69SMatthias Ringwald * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1997dc5e69SMatthias Ringwald * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2097dc5e69SMatthias Ringwald * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2197dc5e69SMatthias Ringwald * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2297dc5e69SMatthias Ringwald * SOFTWARE. 2397dc5e69SMatthias Ringwald */ 2497dc5e69SMatthias Ringwald 2597dc5e69SMatthias Ringwald #include "dhserver.h" 2697dc5e69SMatthias Ringwald 2797dc5e69SMatthias Ringwald /* DHCP message type */ 2897dc5e69SMatthias Ringwald #define DHCP_DISCOVER 1 2997dc5e69SMatthias Ringwald #define DHCP_OFFER 2 3097dc5e69SMatthias Ringwald #define DHCP_REQUEST 3 3197dc5e69SMatthias Ringwald #define DHCP_DECLINE 4 3297dc5e69SMatthias Ringwald #define DHCP_ACK 5 3397dc5e69SMatthias Ringwald #define DHCP_NAK 6 3497dc5e69SMatthias Ringwald #define DHCP_RELEASE 7 3597dc5e69SMatthias Ringwald #define DHCP_INFORM 8 3697dc5e69SMatthias Ringwald 3797dc5e69SMatthias Ringwald /* DHCP options */ 3897dc5e69SMatthias Ringwald enum DHCP_OPTIONS 3997dc5e69SMatthias Ringwald { 4097dc5e69SMatthias Ringwald DHCP_PAD = 0, 4197dc5e69SMatthias Ringwald DHCP_SUBNETMASK = 1, 4297dc5e69SMatthias Ringwald DHCP_ROUTER = 3, 4397dc5e69SMatthias Ringwald DHCP_DNSSERVER = 6, 4497dc5e69SMatthias Ringwald DHCP_HOSTNAME = 12, 4597dc5e69SMatthias Ringwald DHCP_DNSDOMAIN = 15, 4697dc5e69SMatthias Ringwald DHCP_MTU = 26, 4797dc5e69SMatthias Ringwald DHCP_BROADCAST = 28, 4897dc5e69SMatthias Ringwald DHCP_PERFORMROUTERDISC = 31, 4997dc5e69SMatthias Ringwald DHCP_STATICROUTE = 33, 5097dc5e69SMatthias Ringwald DHCP_NISDOMAIN = 40, 5197dc5e69SMatthias Ringwald DHCP_NISSERVER = 41, 5297dc5e69SMatthias Ringwald DHCP_NTPSERVER = 42, 5397dc5e69SMatthias Ringwald DHCP_VENDOR = 43, 5497dc5e69SMatthias Ringwald DHCP_IPADDRESS = 50, 5597dc5e69SMatthias Ringwald DHCP_LEASETIME = 51, 5697dc5e69SMatthias Ringwald DHCP_OPTIONSOVERLOADED = 52, 5797dc5e69SMatthias Ringwald DHCP_MESSAGETYPE = 53, 5897dc5e69SMatthias Ringwald DHCP_SERVERID = 54, 5997dc5e69SMatthias Ringwald DHCP_PARAMETERREQUESTLIST = 55, 6097dc5e69SMatthias Ringwald DHCP_MESSAGE = 56, 6197dc5e69SMatthias Ringwald DHCP_MAXMESSAGESIZE = 57, 6297dc5e69SMatthias Ringwald DHCP_RENEWALTIME = 58, 6397dc5e69SMatthias Ringwald DHCP_REBINDTIME = 59, 6497dc5e69SMatthias Ringwald DHCP_CLASSID = 60, 6597dc5e69SMatthias Ringwald DHCP_CLIENTID = 61, 6697dc5e69SMatthias Ringwald DHCP_USERCLASS = 77, /* RFC 3004 */ 6797dc5e69SMatthias Ringwald DHCP_FQDN = 81, 6897dc5e69SMatthias Ringwald DHCP_DNSSEARCH = 119, /* RFC 3397 */ 6997dc5e69SMatthias Ringwald DHCP_CSR = 121, /* RFC 3442 */ 7097dc5e69SMatthias Ringwald DHCP_MSCSR = 249, /* MS code for RFC 3442 */ 7197dc5e69SMatthias Ringwald DHCP_END = 255 7297dc5e69SMatthias Ringwald }; 7397dc5e69SMatthias Ringwald 7497dc5e69SMatthias Ringwald typedef struct 7597dc5e69SMatthias Ringwald { 7697dc5e69SMatthias Ringwald uint8_t dp_op; /* packet opcode type */ 7797dc5e69SMatthias Ringwald uint8_t dp_htype; /* hardware addr type */ 7897dc5e69SMatthias Ringwald uint8_t dp_hlen; /* hardware addr length */ 7997dc5e69SMatthias Ringwald uint8_t dp_hops; /* gateway hops */ 8097dc5e69SMatthias Ringwald uint32_t dp_xid; /* transaction ID */ 8197dc5e69SMatthias Ringwald uint16_t dp_secs; /* seconds since boot began */ 8297dc5e69SMatthias Ringwald uint16_t dp_flags; 8397dc5e69SMatthias Ringwald uint8_t dp_ciaddr[4]; /* client IP address */ 8497dc5e69SMatthias Ringwald uint8_t dp_yiaddr[4]; /* 'your' IP address */ 8597dc5e69SMatthias Ringwald uint8_t dp_siaddr[4]; /* server IP address */ 8697dc5e69SMatthias Ringwald uint8_t dp_giaddr[4]; /* gateway IP address */ 8797dc5e69SMatthias Ringwald uint8_t dp_chaddr[16]; /* client hardware address */ 8897dc5e69SMatthias Ringwald uint8_t dp_legacy[192]; 8997dc5e69SMatthias Ringwald uint8_t dp_magic[4]; 9097dc5e69SMatthias Ringwald uint8_t dp_options[275]; /* options area */ 9197dc5e69SMatthias Ringwald } DHCP_TYPE; 9297dc5e69SMatthias Ringwald 9397dc5e69SMatthias Ringwald DHCP_TYPE dhcp_data; 9497dc5e69SMatthias Ringwald static struct udp_pcb *pcb = NULL; 9597dc5e69SMatthias Ringwald static dhcp_config_t *config = NULL; 9697dc5e69SMatthias Ringwald 9797dc5e69SMatthias Ringwald char magic_cookie[] = {0x63,0x82,0x53,0x63}; 9897dc5e69SMatthias Ringwald 9997dc5e69SMatthias Ringwald static dhcp_entry_t *entry_by_ip(uint32_t ip) 10097dc5e69SMatthias Ringwald { 10197dc5e69SMatthias Ringwald int i; 10297dc5e69SMatthias Ringwald for (i = 0; i < config->num_entry; i++) 10397dc5e69SMatthias Ringwald if (*(uint32_t *)config->entries[i].addr == ip) 10497dc5e69SMatthias Ringwald return &config->entries[i]; 10597dc5e69SMatthias Ringwald return NULL; 10697dc5e69SMatthias Ringwald } 10797dc5e69SMatthias Ringwald 10897dc5e69SMatthias Ringwald static dhcp_entry_t *entry_by_mac(uint8_t *mac) 10997dc5e69SMatthias Ringwald { 11097dc5e69SMatthias Ringwald int i; 11197dc5e69SMatthias Ringwald for (i = 0; i < config->num_entry; i++) 11297dc5e69SMatthias Ringwald if (memcmp(config->entries[i].mac, mac, 6) == 0) 11397dc5e69SMatthias Ringwald return &config->entries[i]; 11497dc5e69SMatthias Ringwald return NULL; 11597dc5e69SMatthias Ringwald } 11697dc5e69SMatthias Ringwald 11797dc5e69SMatthias Ringwald static __inline bool is_vacant(dhcp_entry_t *entry) 11897dc5e69SMatthias Ringwald { 11997dc5e69SMatthias Ringwald return memcmp("\0\0\0\0\0", entry->mac, 6) == 0; 12097dc5e69SMatthias Ringwald } 12197dc5e69SMatthias Ringwald 122946d87baSMatthias Ringwald static dhcp_entry_t *vacant_address(void) 12397dc5e69SMatthias Ringwald { 12497dc5e69SMatthias Ringwald int i; 12597dc5e69SMatthias Ringwald for (i = 0; i < config->num_entry; i++) 12697dc5e69SMatthias Ringwald if (is_vacant(config->entries + i)) 12797dc5e69SMatthias Ringwald return config->entries + i; 12897dc5e69SMatthias Ringwald return NULL; 12997dc5e69SMatthias Ringwald } 13097dc5e69SMatthias Ringwald 13197dc5e69SMatthias Ringwald static __inline void free_entry(dhcp_entry_t *entry) 13297dc5e69SMatthias Ringwald { 13397dc5e69SMatthias Ringwald memset(entry->mac, 0, 6); 13497dc5e69SMatthias Ringwald } 13597dc5e69SMatthias Ringwald 13697dc5e69SMatthias Ringwald static uint8_t *find_dhcp_option(uint8_t *attrs, int size, uint8_t attr) 13797dc5e69SMatthias Ringwald { 13897dc5e69SMatthias Ringwald int i = 0; 13997dc5e69SMatthias Ringwald while ((i + 1) < size) 14097dc5e69SMatthias Ringwald { 14197dc5e69SMatthias Ringwald int next = i + attrs[i + 1] + 2; 14297dc5e69SMatthias Ringwald if (next > size) return NULL; 14397dc5e69SMatthias Ringwald if (attrs[i] == attr) 14497dc5e69SMatthias Ringwald return attrs + i; 14597dc5e69SMatthias Ringwald i = next; 14697dc5e69SMatthias Ringwald } 14797dc5e69SMatthias Ringwald return NULL; 14897dc5e69SMatthias Ringwald } 14997dc5e69SMatthias Ringwald 15097dc5e69SMatthias Ringwald static int fill_options(void *dest, 15197dc5e69SMatthias Ringwald uint8_t msg_type, 15297dc5e69SMatthias Ringwald const char *domain, 15397dc5e69SMatthias Ringwald uint32_t dns, 15497dc5e69SMatthias Ringwald int lease_time, 15597dc5e69SMatthias Ringwald uint32_t serverid, 15697dc5e69SMatthias Ringwald uint32_t router, 15797dc5e69SMatthias Ringwald uint32_t subnet) 15897dc5e69SMatthias Ringwald { 15997dc5e69SMatthias Ringwald uint8_t *ptr = (uint8_t *)dest; 16097dc5e69SMatthias Ringwald /* ACK message type */ 16197dc5e69SMatthias Ringwald *ptr++ = 53; 16297dc5e69SMatthias Ringwald *ptr++ = 1; 16397dc5e69SMatthias Ringwald *ptr++ = msg_type; 16497dc5e69SMatthias Ringwald 16597dc5e69SMatthias Ringwald /* dhcp server identifier */ 16697dc5e69SMatthias Ringwald *ptr++ = DHCP_SERVERID; 16797dc5e69SMatthias Ringwald *ptr++ = 4; 16897dc5e69SMatthias Ringwald *(uint32_t *)ptr = serverid; 16997dc5e69SMatthias Ringwald ptr += 4; 17097dc5e69SMatthias Ringwald 17197dc5e69SMatthias Ringwald /* lease time */ 17297dc5e69SMatthias Ringwald *ptr++ = DHCP_LEASETIME; 17397dc5e69SMatthias Ringwald *ptr++ = 4; 17497dc5e69SMatthias Ringwald *ptr++ = (lease_time >> 24) & 0xFF; 17597dc5e69SMatthias Ringwald *ptr++ = (lease_time >> 16) & 0xFF; 17697dc5e69SMatthias Ringwald *ptr++ = (lease_time >> 8) & 0xFF; 17797dc5e69SMatthias Ringwald *ptr++ = (lease_time >> 0) & 0xFF; 17897dc5e69SMatthias Ringwald 17997dc5e69SMatthias Ringwald /* subnet mask */ 18097dc5e69SMatthias Ringwald *ptr++ = DHCP_SUBNETMASK; 18197dc5e69SMatthias Ringwald *ptr++ = 4; 18297dc5e69SMatthias Ringwald *(uint32_t *)ptr = subnet; 18397dc5e69SMatthias Ringwald ptr += 4; 18497dc5e69SMatthias Ringwald 18597dc5e69SMatthias Ringwald /* router */ 18697dc5e69SMatthias Ringwald if (router != 0) 18797dc5e69SMatthias Ringwald { 18897dc5e69SMatthias Ringwald *ptr++ = DHCP_ROUTER; 18997dc5e69SMatthias Ringwald *ptr++ = 4; 19097dc5e69SMatthias Ringwald *(uint32_t *)ptr = router; 19197dc5e69SMatthias Ringwald ptr += 4; 19297dc5e69SMatthias Ringwald } 19397dc5e69SMatthias Ringwald 19497dc5e69SMatthias Ringwald /* domain name */ 19597dc5e69SMatthias Ringwald if (domain != NULL) 19697dc5e69SMatthias Ringwald { 19797dc5e69SMatthias Ringwald int len = strlen(domain); 19897dc5e69SMatthias Ringwald *ptr++ = DHCP_DNSDOMAIN; 19997dc5e69SMatthias Ringwald *ptr++ = len; 20097dc5e69SMatthias Ringwald memcpy(ptr, domain, len); 20197dc5e69SMatthias Ringwald ptr += len; 20297dc5e69SMatthias Ringwald } 20397dc5e69SMatthias Ringwald 20497dc5e69SMatthias Ringwald /* domain name server (DNS) */ 20597dc5e69SMatthias Ringwald if (dns != 0) 20697dc5e69SMatthias Ringwald { 20797dc5e69SMatthias Ringwald *ptr++ = DHCP_DNSSERVER; 20897dc5e69SMatthias Ringwald *ptr++ = 4; 20997dc5e69SMatthias Ringwald *(uint32_t *)ptr = dns; 21097dc5e69SMatthias Ringwald ptr += 4; 21197dc5e69SMatthias Ringwald } 21297dc5e69SMatthias Ringwald 21397dc5e69SMatthias Ringwald /* end */ 21497dc5e69SMatthias Ringwald *ptr++ = DHCP_END; 21597dc5e69SMatthias Ringwald return ptr - (uint8_t *)dest; 21697dc5e69SMatthias Ringwald } 21797dc5e69SMatthias Ringwald 218*77da83a6SMatthias Ringwald static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) 21997dc5e69SMatthias Ringwald { 22097dc5e69SMatthias Ringwald (void) arg; 22197dc5e69SMatthias Ringwald (void) addr; 22297dc5e69SMatthias Ringwald 22397dc5e69SMatthias Ringwald uint8_t *ptr; 22497dc5e69SMatthias Ringwald dhcp_entry_t *entry; 22597dc5e69SMatthias Ringwald struct pbuf *pp; 22697dc5e69SMatthias Ringwald 22797dc5e69SMatthias Ringwald unsigned int n = p->len; 22897dc5e69SMatthias Ringwald if (n > sizeof(dhcp_data)) n = sizeof(dhcp_data); 22997dc5e69SMatthias Ringwald memcpy(&dhcp_data, p->payload, n); 23097dc5e69SMatthias Ringwald switch (dhcp_data.dp_options[2]) 23197dc5e69SMatthias Ringwald { 23297dc5e69SMatthias Ringwald case DHCP_DISCOVER: 23397dc5e69SMatthias Ringwald entry = entry_by_mac(dhcp_data.dp_chaddr); 23497dc5e69SMatthias Ringwald if (entry == NULL) entry = vacant_address(); 23597dc5e69SMatthias Ringwald if (entry == NULL) break; 23697dc5e69SMatthias Ringwald 23797dc5e69SMatthias Ringwald dhcp_data.dp_op = 2; /* reply */ 23897dc5e69SMatthias Ringwald dhcp_data.dp_secs = 0; 23997dc5e69SMatthias Ringwald dhcp_data.dp_flags = 0; 24097dc5e69SMatthias Ringwald *(uint32_t *)dhcp_data.dp_yiaddr = *(uint32_t *)entry->addr; 24197dc5e69SMatthias Ringwald memcpy(dhcp_data.dp_magic, magic_cookie, 4); 24297dc5e69SMatthias Ringwald 24397dc5e69SMatthias Ringwald memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options)); 24497dc5e69SMatthias Ringwald 24597dc5e69SMatthias Ringwald fill_options(dhcp_data.dp_options, 24697dc5e69SMatthias Ringwald DHCP_OFFER, 24797dc5e69SMatthias Ringwald config->domain, 24897dc5e69SMatthias Ringwald *(uint32_t *)config->dns, 24997dc5e69SMatthias Ringwald entry->lease, 25097dc5e69SMatthias Ringwald *(uint32_t *)config->addr, 25197dc5e69SMatthias Ringwald *(uint32_t *)config->addr, 25297dc5e69SMatthias Ringwald *(uint32_t *)entry->subnet); 25397dc5e69SMatthias Ringwald 25497dc5e69SMatthias Ringwald pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL); 25597dc5e69SMatthias Ringwald if (pp == NULL) break; 25697dc5e69SMatthias Ringwald memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data)); 25797dc5e69SMatthias Ringwald udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port); 25897dc5e69SMatthias Ringwald pbuf_free(pp); 25997dc5e69SMatthias Ringwald break; 26097dc5e69SMatthias Ringwald 26197dc5e69SMatthias Ringwald case DHCP_REQUEST: 26297dc5e69SMatthias Ringwald /* 1. find requested ipaddr in option list */ 26397dc5e69SMatthias Ringwald ptr = find_dhcp_option(dhcp_data.dp_options, sizeof(dhcp_data.dp_options), DHCP_IPADDRESS); 26497dc5e69SMatthias Ringwald if (ptr == NULL) break; 26597dc5e69SMatthias Ringwald if (ptr[1] != 4) break; 26697dc5e69SMatthias Ringwald ptr += 2; 26797dc5e69SMatthias Ringwald 26897dc5e69SMatthias Ringwald /* 2. does hw-address registered? */ 26997dc5e69SMatthias Ringwald entry = entry_by_mac(dhcp_data.dp_chaddr); 27097dc5e69SMatthias Ringwald if (entry != NULL) free_entry(entry); 27197dc5e69SMatthias Ringwald 27297dc5e69SMatthias Ringwald /* 3. find requested ipaddr */ 27397dc5e69SMatthias Ringwald entry = entry_by_ip(*(uint32_t *)ptr); 27497dc5e69SMatthias Ringwald if (entry == NULL) break; 27597dc5e69SMatthias Ringwald if (!is_vacant(entry)) break; 27697dc5e69SMatthias Ringwald 27797dc5e69SMatthias Ringwald /* 4. fill struct fields */ 27897dc5e69SMatthias Ringwald memcpy(dhcp_data.dp_yiaddr, ptr, 4); 27997dc5e69SMatthias Ringwald dhcp_data.dp_op = 2; /* reply */ 28097dc5e69SMatthias Ringwald dhcp_data.dp_secs = 0; 28197dc5e69SMatthias Ringwald dhcp_data.dp_flags = 0; 28297dc5e69SMatthias Ringwald memcpy(dhcp_data.dp_magic, magic_cookie, 4); 28397dc5e69SMatthias Ringwald 28497dc5e69SMatthias Ringwald /* 5. fill options */ 28597dc5e69SMatthias Ringwald memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options)); 28697dc5e69SMatthias Ringwald 28797dc5e69SMatthias Ringwald fill_options(dhcp_data.dp_options, 28897dc5e69SMatthias Ringwald DHCP_ACK, 28997dc5e69SMatthias Ringwald config->domain, 29097dc5e69SMatthias Ringwald *(uint32_t *)config->dns, 29197dc5e69SMatthias Ringwald entry->lease, 29297dc5e69SMatthias Ringwald *(uint32_t *)config->addr, 29397dc5e69SMatthias Ringwald *(uint32_t *)config->addr, 29497dc5e69SMatthias Ringwald *(uint32_t *)entry->subnet); 29597dc5e69SMatthias Ringwald 29697dc5e69SMatthias Ringwald /* 6. send ACK */ 29797dc5e69SMatthias Ringwald pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL); 29897dc5e69SMatthias Ringwald if (pp == NULL) break; 29997dc5e69SMatthias Ringwald memcpy(entry->mac, dhcp_data.dp_chaddr, 6); 30097dc5e69SMatthias Ringwald memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data)); 30197dc5e69SMatthias Ringwald udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port); 30297dc5e69SMatthias Ringwald pbuf_free(pp); 30397dc5e69SMatthias Ringwald break; 30497dc5e69SMatthias Ringwald 30597dc5e69SMatthias Ringwald default: 30697dc5e69SMatthias Ringwald break; 30797dc5e69SMatthias Ringwald } 30897dc5e69SMatthias Ringwald pbuf_free(p); 30997dc5e69SMatthias Ringwald } 31097dc5e69SMatthias Ringwald 31197dc5e69SMatthias Ringwald err_t dhserv_init(dhcp_config_t *c) 31297dc5e69SMatthias Ringwald { 31397dc5e69SMatthias Ringwald err_t err; 31497dc5e69SMatthias Ringwald // udp_init(); already called from lwip_init 31597dc5e69SMatthias Ringwald dhserv_free(); 31697dc5e69SMatthias Ringwald pcb = udp_new(); 31797dc5e69SMatthias Ringwald if (pcb == NULL) 31897dc5e69SMatthias Ringwald return ERR_MEM; 31997dc5e69SMatthias Ringwald err = udp_bind(pcb, IP_ADDR_ANY, c->port); 32097dc5e69SMatthias Ringwald if (err != ERR_OK) 32197dc5e69SMatthias Ringwald { 32297dc5e69SMatthias Ringwald dhserv_free(); 32397dc5e69SMatthias Ringwald return err; 32497dc5e69SMatthias Ringwald } 32597dc5e69SMatthias Ringwald udp_recv(pcb, udp_recv_proc, NULL); 32697dc5e69SMatthias Ringwald config = c; 32797dc5e69SMatthias Ringwald return ERR_OK; 32897dc5e69SMatthias Ringwald } 32997dc5e69SMatthias Ringwald 33097dc5e69SMatthias Ringwald void dhserv_free(void) 33197dc5e69SMatthias Ringwald { 33297dc5e69SMatthias Ringwald if (pcb == NULL) return; 33397dc5e69SMatthias Ringwald udp_remove(pcb); 33497dc5e69SMatthias Ringwald pcb = NULL; 33597dc5e69SMatthias Ringwald } 336