+static int cidr_mapped4(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL);
+ cidr_t *p2;
+
+ if (!_is_mapped4(p1))
+ return 0;
+
+ if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
+ return 0;
+
+ p2->family = AF_INET;
+ p2->bits = (p1->bits > AF_BITS(AF_INET)) ? AF_BITS(AF_INET) : p1->bits;
+ memcpy(&p2->addr.v4, p1->addr.v6.s6_addr + 12, sizeof(p2->addr.v4));
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_tolinklocal(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL);
+ cidr_t *p2;
+ int i;
+
+ if (p1->family != AF_PACKET)
+ return 0;
+
+ if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
+ return 0;
+
+ p2->family = AF_INET6;
+ p2->bits = AF_BITS(AF_INET6);
+ p2->addr.u8[0] = 0xFE;
+ p2->addr.u8[1] = 0x80;
+ p2->addr.u8[8] = p1->addr.u8[0] ^ 0x02;
+ p2->addr.u8[9] = p1->addr.u8[1];
+ p2->addr.u8[10] = p1->addr.u8[2];
+ p2->addr.u8[11] = 0xFF;
+ p2->addr.u8[12] = 0xFE;
+ p2->addr.u8[13] = p1->addr.u8[3];
+ p2->addr.u8[14] = p1->addr.u8[4];
+ p2->addr.u8[15] = p1->addr.u8[5];
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int cidr_tomac(lua_State *L)
+{
+ cidr_t *p1 = L_checkcidr(L, 1, NULL);
+ cidr_t *p2;
+ int i;
+
+ if (p1->family != AF_INET6 ||
+ p1->addr.u8[0] != 0xFE ||
+ p1->addr.u8[1] != 0x80 ||
+ p1->addr.u8[2] != 0x00 ||
+ p1->addr.u8[3] != 0x00 ||
+ p1->addr.u8[4] != 0x00 ||
+ p1->addr.u8[5] != 0x00 ||
+ p1->addr.u8[6] != 0x00 ||
+ p1->addr.u8[7] != 0x00 ||
+ p1->addr.u8[11] != 0xFF ||
+ p1->addr.u8[12] != 0xFE)
+ return 0;
+
+ if (!(p2 = lua_newuserdata(L, sizeof(*p2))))
+ return 0;
+
+ p2->family = AF_PACKET;
+ p2->bits = AF_BITS(AF_PACKET);
+ p2->addr.u8[0] = p1->addr.u8[8] ^ 0x02;
+ p2->addr.u8[1] = p1->addr.u8[9];
+ p2->addr.u8[2] = p1->addr.u8[10];
+ p2->addr.u8[3] = p1->addr.u8[13];
+ p2->addr.u8[4] = p1->addr.u8[14];
+ p2->addr.u8[5] = p1->addr.u8[15];
+
+ luaL_getmetatable(L, LUCI_IP_CIDR);
+ lua_setmetatable(L, -2);
+ return 1;
+}
+