luci-0.9: merge r5782
[project/luci.git] / libs / luanet / src / ifconfig.c
1 /*
2 * Licensed under the Apache License, Version 2.0 (the "License");
3 * you may not use this file except in compliance with the License.
4 * You may obtain a copy of the License at
5 *
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Unless required by applicable law or agreed to in writing, software
9 * distributed under the License is distributed on an "AS IS" BASIS,
10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and
12 * limitations under the License.
13 *
14 * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
15 * Copyright (C) 2008 Steven Barth <steven@midlink.org>
16 */
17
18 #include <net/if.h>
19 #include <net/if_arp.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <linux/sockios.h>
25 #include <sys/ioctl.h>
26 #include <dirent.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <stdlib.h>
30
31 #include <lua.h>
32 #include <lualib.h>
33 #include <lauxlib.h>
34
35 #include "helper.h"
36
37 int sock_ifconfig = 0;
38
39 int ifc_startup(void)
40 {
41 if(!sock_ifconfig)
42 sock_ifconfig = socket(AF_INET, SOCK_DGRAM, 0);
43 return sock_ifconfig;
44 }
45
46 void ifc_shutdown(void)
47 {
48 if(!sock_ifconfig)
49 return;
50 close(sock_ifconfig);
51 sock_ifconfig = 0;
52 }
53
54 static int isdev(const struct dirent *entry)
55 {
56 if(*entry->d_name == '.')
57 return 0;
58 return 1;
59 }
60
61 static void ifc_addif(lua_State *L, char *ifname)
62 {
63 char *ip = malloc(32);
64 struct ifreq ifr;
65 lua_pushstring(L, ifname);
66 lua_newtable(L);
67 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
68
69 if(!ioctl(sock_ifconfig, SIOCGIFADDR, &ifr))
70 {
71 ipv42char(&ifr.ifr_addr.sa_data[2], ip);
72 add_table_entry(L, "ip", ip);
73 }
74
75 if(!ioctl(sock_ifconfig, SIOCGIFNETMASK, &ifr))
76 {
77 ipv42char(&ifr.ifr_netmask.sa_data[2], ip);
78 add_table_entry(L, "netmask", ip);
79 }
80
81 if(!ioctl(sock_ifconfig, SIOCGIFBRDADDR, &ifr))
82 {
83 ipv42char(&ifr.ifr_broadaddr.sa_data[2], ip);
84 add_table_entry(L, "broadaddr", ip);
85 }
86
87 if(!ioctl(sock_ifconfig, SIOCGIFHWADDR, &ifr))
88 {
89 mac2char(ifr.ifr_hwaddr.sa_data, ip);
90 add_table_entry(L, "mac", ip);
91 }
92
93 if(!ioctl(sock_ifconfig, SIOCGIFFLAGS, &ifr))
94 {
95 if(ifr.ifr_flags & IFF_UP)
96 add_table_entry(L, "up", "1");
97 else
98 add_table_entry(L, "up", "0");
99 }
100
101 ioctl(sock_ifconfig, SIOCGIFMTU, &ifr);
102 lua_pushstring(L, "mtu");
103 lua_pushinteger(L, ifr.ifr_mtu);
104 lua_settable(L, -3);
105 free(ip);
106 lua_settable(L, -3);
107 }
108
109 #define SYSFS_CLASS_NET "/sys/class/net/"
110 int ifc_getall(lua_State *L)
111 {
112 int numreqs = 50;
113 struct dirent **namelist;
114 int i, count = 0;
115 struct ifconf ifc;
116 struct ifreq *ifr;
117 ifc.ifc_buf = NULL;
118 count = scandir(SYSFS_CLASS_NET, &namelist, isdev, alphasort);
119 if (count < 0)
120 {
121 return 0;
122 }
123 lua_newtable(L);
124 for (i = 0; i < count; i++)
125 {
126 ifc_addif(L, namelist[i]->d_name);
127 free(namelist[i]);
128 }
129 free(namelist);
130
131 ifc.ifc_len = sizeof(struct ifreq) * numreqs;
132 ifc.ifc_buf = malloc(ifc.ifc_len);
133 if(ioctl(sock_ifconfig, SIOCGIFCONF, &ifc) < 0)
134 goto out;
135 ifr = ifc.ifc_req;
136 for(i = 0; i < ifc.ifc_len; i += sizeof(struct ifreq))
137 {
138 if(strchr(ifr->ifr_name, ':'))
139 ifc_addif(L, ifr->ifr_name);
140 ifr++;
141 }
142 out:
143 free(ifc.ifc_buf);
144 return 1;
145 }
146
147 static inline int _ifc_setip(lua_State *L, int i)
148 {
149 struct ifreq ifr;
150 char *ifname, *ip;
151 if(lua_gettop(L) != 2)
152 {
153 lua_pushstring(L, "invalid arg list");
154 lua_error(L);
155 return 0;
156 }
157 ifname = (char *)lua_tostring (L, 1);
158 ip = (char *)lua_tostring (L, 2);
159 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
160 ifr.ifr_addr.sa_family = AF_INET;
161 if(char2ipv4(ip, &ifr.ifr_addr.sa_data[2]))
162 {
163 lua_pushstring(L, "invalid ip");
164 lua_error(L);
165 return 0;
166 }
167 if(!ioctl(sock_ifconfig, i, &ifr))
168 lua_pushboolean(L, 1);
169 else
170 lua_pushboolean(L, 0);
171 return 1;
172 }
173
174 int ifc_setip(lua_State *L)
175 {
176 return _ifc_setip(L, SIOCSIFADDR);
177 }
178
179 int ifc_setnetmask(lua_State *L)
180 {
181 return _ifc_setip(L, SIOCGIFNETMASK);
182 }
183
184 int ifc_setbroadcast(lua_State *L)
185 {
186 return _ifc_setip(L, SIOCSIFBRDADDR);
187 }
188
189 int ifc_setmtu(lua_State *L)
190 {
191 struct ifreq ifr;
192 char *ifname;
193 int mtu;
194 if(lua_gettop(L) != 2)
195 {
196 lua_pushstring(L, "invalid arg list");
197 lua_error(L);
198 return 0;
199 }
200 ifname = (char *)lua_tostring (L, 1);
201 mtu = (int)lua_tointeger (L, 2);
202 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
203 ifr.ifr_mtu = mtu;
204 if(!ioctl(sock_ifconfig, SIOCSIFMTU, &ifr))
205 lua_pushboolean(L, 1);
206 else
207 lua_pushboolean(L, 0);
208 return 1;
209 }
210
211 static int _ifc_up(lua_State *L, int up)
212 {
213 struct ifreq ifr;
214 char *ifname;
215 if(lua_gettop(L) != 1)
216 {
217 lua_pushstring(L, "invalid arg list");
218 lua_error(L);
219 return 0;
220 }
221
222 ifname = (char *)lua_tostring (L, 1);
223 strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
224
225 if(ioctl(sock_ifconfig, SIOCGIFFLAGS, &ifr) < 0)
226 {
227 lua_pushboolean(L, 0);
228 return 1;
229 }
230 if(up)
231 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
232 else
233 ifr.ifr_flags &= ~IFF_UP;
234 if(!ioctl(sock_ifconfig, SIOCSIFFLAGS, &ifr))
235 lua_pushboolean(L, 1);
236 else
237 lua_pushboolean(L, 0);
238 return 1;
239 }
240
241 int ifc_up(lua_State *L)
242 {
243 return _ifc_up(L, 1);
244 }
245
246 int ifc_down(lua_State *L)
247 {
248 return _ifc_up(L, 0);
249 }
250