#include #include #include "ql_type.h" #include "ql_func.h" #include "ql_application.h" #include "ql_data_call.h" #include "ql_xlat.h" #include "ip6_addr.h" #include "sockets.h" /* ========= Minimal config ========= */ #define PROFILE_IDX 1 #define IP_VER_V6 1 /* 1 = IPv6 only */ #define APN_NAME "diginet" /* DigiNet */ /* Send 1 UDP packet to an IPv4 destination (no reply needed) */ #define DST_IPV4_HEX 0x08080808 /* 8.8.8.8 */ #define DST_PORT 12345 static void print_ipv6_bytes(const unsigned char *p16) { for (int i = 0; i < 16; i++) { printf("%02X", p16[i]); if (i != 15) printf(":"); } printf("\r\n"); } static int start_ipv6_pdp(void) { int ret; struct ql_data_call_info info; /* Give SIM/RF some time */ ql_rtos_task_sleep_ms(5000); printf("[XLAT] wait network register...\r\n"); ret = ql_network_register_wait(180); printf("[XLAT] network register ret=%d\r\n", ret); if (ret != 0) return -1; /* Set default netif for this profile (good practice) */ (void)ql_set_lwip_netif_default_by_profile_idx(PROFILE_IDX); printf("[XLAT] start IPv6 PDP: profile=%d apn=%s\r\n", PROFILE_IDX, APN_NAME); ret = ql_start_data_call(PROFILE_IDX, IP_VER_V6, (char *)APN_NAME, NULL, NULL, 0); printf("[XLAT] ql_start_data_call ret=%d\r\n", ret); if (ret != 0) return -2; memset(&info, 0, sizeof(info)); ret = ql_get_data_call_info(PROFILE_IDX, IP_VER_V6, &info); printf("[XLAT] ql_get_data_call_info ret=%d\r\n", ret); if (ret != 0) return -3; printf("[XLAT] IPv6 addr = "); print_ipv6_bytes((unsigned char *)info.v6.addr.ip.s6_addr); return 0; } static int enable_clat_min(void) { int ret; int prefix_len; ip6_addr_t prefix; printf("[XLAT] clat_is_enable(before)=%d\r\n", (int)ql_clat_is_enable()); prefix_len = ql_get_clat_prefix_len(); printf("[XLAT] nat64 prefix_len=%d\r\n", prefix_len); memset(&prefix, 0, sizeof(prefix)); ret = ql_get_clat_prefix_addr(&prefix); printf("[XLAT] get_prefix_addr ret=%d\r\n", ret); if (prefix_len <= 0 || prefix_len > 128) { printf("[XLAT] invalid prefix_len, stop\r\n"); return -1; } ret = ql_set_clat(TRUE, &prefix, (char)prefix_len); printf("[XLAT] ql_set_clat ret=%d\r\n", ret); printf("[XLAT] clat_is_enable(after)=%d\r\n", (int)ql_clat_is_enable()); return ret; } static int send_one_ipv4_udp(void) { int fd; struct sockaddr_in dst; const char payload[] = "XLAT_MIN_PROOF"; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { printf("[XLAT] socket(AF_INET,UDP) fail\r\n"); return -1; } memset(&dst, 0, sizeof(dst)); dst.sin_family = AF_INET; dst.sin_port = htons(DST_PORT); dst.sin_addr.s_addr = htonl(DST_IPV4_HEX); printf("[XLAT] send UDP via IPv4 socket to %d.%d.%d.%d:%d\r\n", (DST_IPV4_HEX >> 24) & 0xFF, (DST_IPV4_HEX >> 16) & 0xFF, (DST_IPV4_HEX >> 8) & 0xFF, (DST_IPV4_HEX >> 0) & 0xFF, DST_PORT); int n = sendto(fd, payload, (int)sizeof(payload) - 1, 0, (struct sockaddr *)&dst, sizeof(dst)); if (n > 0) printf("[XLAT] sendto OK, bytes=%d\r\n", n); else printf("[XLAT] sendto FAIL, ret=%d\r\n", n); /* IMPORTANT: use close(), not closesocket() */ close(fd); return (n > 0) ? 0 : -2; } static void xlat_min_task(void *arg) { (void)arg; printf("\r\n[XLAT] ===== XLAT MIN UDP PROOF START =====\r\n"); if (start_ipv6_pdp() == 0) { if (enable_clat_min() == 0) { int ret = send_one_ipv4_udp(); if (ret == 0) printf("[XLAT] >>> MIN PASS (local): IPv4 UDP send succeeded on IPv6 PDP\r\n"); else printf("[XLAT] >>> MIN FAIL: send failed\r\n"); } else { printf("[XLAT] >>> FAIL: enable CLAT failed\r\n"); } } else { printf("[XLAT] >>> FAIL: IPv6 PDP/network not ready\r\n"); } printf("[XLAT] ===== XLAT MIN UDP PROOF END =====\r\n\r\n"); } /* Register app at global scope */ //application_init(xlat_min_task, "xlat_min", 10, 0);