};
-static int _cidr_new(lua_State *L, int index, int family);
+static int _cidr_new(lua_State *L, int index, int family, bool mask);
static cidr_t *L_checkcidr (lua_State *L, int index, cidr_t *p)
{
if (lua_type(L, index) == LUA_TUSERDATA)
return luaL_checkudata(L, index, LUCI_IP_CIDR);
- if (_cidr_new(L, index, p ? p->family : 0))
+ if (_cidr_new(L, index, p ? p->family : 0, false))
return lua_touserdata(L, -1);
luaL_error(L, "Invalid operand");
return bits;
}
-static int _cidr_new(lua_State *L, int index, int family)
+static int _cidr_new(lua_State *L, int index, int family, bool mask)
{
uint32_t n;
const char *addr;
cidr.family = AF_INET6;
cidr.bits = 128;
cidr.len = sizeof(cidr.addr.v6);
- cidr.addr.v6.s6_addr[15] = n;
- cidr.addr.v6.s6_addr[14] = (n >> 8);
- cidr.addr.v6.s6_addr[13] = (n >> 16);
- cidr.addr.v6.s6_addr[12] = (n >> 24);
+ cidr.addr.v6.s6_addr[12] = n;
+ cidr.addr.v6.s6_addr[13] = (n >> 8);
+ cidr.addr.v6.s6_addr[14] = (n >> 16);
+ cidr.addr.v6.s6_addr[15] = (n >> 24);
}
else
{
if (family && cidr.family != family)
return 0;
+
+ if (mask)
+ cidr.bits = L_checkbits(L, index + 1, &cidr);
}
if (!(cidrp = lua_newuserdata(L, sizeof(*cidrp))))
static int cidr_new(lua_State *L)
{
- return _cidr_new(L, 1, 0);
+ return _cidr_new(L, 1, 0, true);
}
static int cidr_ipv4(lua_State *L)
{
- return _cidr_new(L, 1, AF_INET);
+ return _cidr_new(L, 1, AF_INET, true);
}
static int cidr_ipv6(lua_State *L)
{
- return _cidr_new(L, 1, AF_INET6);
+ return _cidr_new(L, 1, AF_INET6, true);
}
static int cidr_is4(lua_State *L)
{
if (p1->family == AF_INET6)
{
- for (i = 0, carry = 0; i < sizeof(r); i++)
+ for (i = 0, carry = 0; i < sizeof(r.addr.v6.s6_addr); i++)
{
if (add)
{
static int neighbor_dump(lua_State *L)
{
- cidr_t p;
+ cidr_t p = { };
const char *s;
struct ether_addr *mac;
struct dump_filter filter = { .type = 0xFF & ~NUD_NOARP };
}
+static int cb_dump_link(struct nl_msg *msg, void *arg)
+{
+ char *p, *addr, buf[48];
+ struct dump_state *s = arg;
+ struct nlmsghdr *hdr = nlmsg_hdr(msg);
+ struct ifinfomsg *ifm = NLMSG_DATA(hdr);
+ struct nlattr *tb[IFLA_MAX+1];
+ int i, len;
+
+ if (hdr->nlmsg_type != RTM_NEWLINK)
+ return NL_SKIP;
+
+ nlmsg_parse(hdr, sizeof(*ifm), tb, IFLA_MAX, NULL);
+
+ L_setbool(s->L, "up", (ifm->ifi_flags & IFF_RUNNING));
+ L_setint(s->L, "type", ifm->ifi_type);
+ L_setstr(s->L, "name", if_indextoname(ifm->ifi_index, buf));
+
+ if (tb[IFLA_MTU])
+ L_setint(s->L, "mtu", RTA_U32(tb[IFLA_MTU]));
+
+ if (tb[IFLA_TXQLEN])
+ L_setint(s->L, "qlen", RTA_U32(tb[IFLA_TXQLEN]));
+
+ if (tb[IFLA_MASTER])
+ L_setdev(s->L, "master", tb[IFLA_MASTER]);
+
+ if (tb[IFLA_ADDRESS])
+ {
+ len = nla_len(tb[IFLA_ADDRESS]);
+ addr = nla_get_string(tb[IFLA_ADDRESS]);
+
+ if ((len * 3) <= sizeof(buf))
+ {
+ for (p = buf, i = 0; i < len; i++)
+ p += sprintf(p, "%s%02x", (i ? ":" : ""), (uint8_t)*addr++);
+
+ L_setstr(s->L, "mac", buf);
+ }
+ }
+
+ s->pending = 0;
+ return NL_SKIP;
+}
+
+static int link_get(lua_State *L)
+{
+ const char *dev = luaL_checkstring(L, 1);
+ struct dump_state st = {
+ .pending = 1,
+ .L = L
+ };
+
+ if (!sock)
+ {
+ sock = nl_socket_alloc();
+ if (!sock)
+ return _error(L, -1, "Out of memory");
+
+ if (nl_connect(sock, NETLINK_ROUTE))
+ return _error(L, 0, NULL);
+ }
+
+ struct nl_msg *msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST);
+ struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
+ struct ifinfomsg ifm = { .ifi_index = if_nametoindex(dev) };
+
+ if (!msg || !cb)
+ return 0;
+
+ nlmsg_append(msg, &ifm, sizeof(ifm), 0);
+
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_dump_link, &st);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &st);
+ nl_cb_err(cb, NL_CB_CUSTOM, cb_error, &st);
+
+ lua_newtable(L);
+
+ nl_send_auto_complete(sock, msg);
+
+ while (st.pending > 0)
+ nl_recvmsgs(sock, cb);
+
+ nlmsg_free(msg);
+ nl_cb_put(cb);
+
+ return 1;
+}
+
+
static const luaL_reg ip_methods[] = {
{ "new", cidr_new },
{ "IPv4", cidr_ipv4 },
{ "neighbors", neighbor_dump },
+ { "link", link_get },
+
{ }
};