1/*
2 * Linux network interface code
3 *
4 * Copyright (C) 2013, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * $Id: interface.c 291523 2011-10-24 06:12:27Z $
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <ctype.h>
24#include <errno.h>
25#include <error.h>
26#include <string.h>
27#include <unistd.h>
28#include <sys/ioctl.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <linux/route.h>
32#include <linux/if.h>
33#include <netinet/in.h>
34#include <arpa/inet.h>
35#include <net/if_arp.h>
36#include <proto/ethernet.h>
37#include <shutils.h>
38#include <bcmnvram.h>
39#include <bcmutils.h>
40#include <bcmparams.h>
41#include <rc.h>
42
43int
44ifconfig(char *name, int flags, char *addr, char *netmask)
45{
46	int s;
47	struct ifreq ifr;
48	struct in_addr in_addr, in_netmask, in_broadaddr;
49
50	/* Open a raw socket to the kernel */
51	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
52		goto err;
53
54	/* Set interface name */
55	strncpy(ifr.ifr_name, name, IFNAMSIZ);
56
57	/* Set interface flags */
58	ifr.ifr_flags = flags;
59	if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
60		goto err;
61
62	/* Set IP address */
63	if (addr) {
64		inet_aton(addr, &in_addr);
65		sin_addr(&ifr.ifr_addr).s_addr = in_addr.s_addr;
66		ifr.ifr_addr.sa_family = AF_INET;
67		if (ioctl(s, SIOCSIFADDR, &ifr) < 0)
68			goto err;
69	}
70
71	/* Set IP netmask and broadcast */
72	if (addr && netmask) {
73		inet_aton(netmask, &in_netmask);
74		sin_addr(&ifr.ifr_netmask).s_addr = in_netmask.s_addr;
75		ifr.ifr_netmask.sa_family = AF_INET;
76		if (ioctl(s, SIOCSIFNETMASK, &ifr) < 0)
77			goto err;
78
79		in_broadaddr.s_addr = (in_addr.s_addr & in_netmask.s_addr) | ~in_netmask.s_addr;
80		sin_addr(&ifr.ifr_broadaddr).s_addr = in_broadaddr.s_addr;
81		ifr.ifr_broadaddr.sa_family = AF_INET;
82		if (ioctl(s, SIOCSIFBRDADDR, &ifr) < 0)
83			goto err;
84	}
85
86	close(s);
87
88	return 0;
89
90err:
91	close(s);
92	perror(name);
93	return errno;
94}
95
96int
97ifconfig_get(char *name, int *flags, unsigned long *addr, unsigned long *netmask)
98{
99	int s;
100	struct ifreq ifr;
101
102	/* Open a raw socket to the kernel */
103	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
104		goto err;
105
106	/* Set interface name */
107	strncpy(ifr.ifr_name, name, IFNAMSIZ);
108
109	/* Check MAC first */
110	if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
111		goto err;
112	else if (memcmp(ifr.ifr_hwaddr.sa_data, "\0\0\0\0\0\0", 6) == 0)
113		goto err;
114
115	/* Get interface flags */
116	if (flags) {
117		if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
118			goto err;
119		else
120			memcpy(flags, &(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr),
121				sizeof(*flags));
122	}
123
124	/* Get IP address */
125	if (addr) {
126		if (ioctl(s, SIOCGIFADDR, &ifr) < 0)
127			goto err;
128		else
129			memcpy(addr, &(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr),
130				sizeof(*addr));
131	}
132
133	/* Get Net mask */
134	if (netmask) {
135		if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0)
136			goto err;
137		else {
138			memcpy(netmask, &(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr),
139				sizeof(*netmask));
140		}
141	}
142
143	close(s);
144
145	return 0;
146
147err:
148	close(s);
149	perror(name);
150	return errno;
151}
152
153static int
154route_manip(int cmd, char *name, int metric, char *dst, char *gateway, char *genmask)
155{
156	int s;
157	struct rtentry rt;
158
159	/* Open a raw socket to the kernel */
160	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
161		goto err;
162
163	/* Fill in rtentry */
164	memset(&rt, 0, sizeof(rt));
165	if (dst)
166		inet_aton(dst, &sin_addr(&rt.rt_dst));
167	if (gateway)
168		inet_aton(gateway, &sin_addr(&rt.rt_gateway));
169	if (genmask)
170		inet_aton(genmask, &sin_addr(&rt.rt_genmask));
171	rt.rt_metric = metric;
172	rt.rt_flags = RTF_UP;
173	if (sin_addr(&rt.rt_gateway).s_addr)
174		rt.rt_flags |= RTF_GATEWAY;
175	if (sin_addr(&rt.rt_genmask).s_addr == INADDR_BROADCAST)
176		rt.rt_flags |= RTF_HOST;
177	rt.rt_dev = name;
178
179	/* Force address family to AF_INET */
180	rt.rt_dst.sa_family = AF_INET;
181	rt.rt_gateway.sa_family = AF_INET;
182	rt.rt_genmask.sa_family = AF_INET;
183
184	if (ioctl(s, cmd, &rt) < 0)
185		goto err;
186
187	close(s);
188	return 0;
189
190err:
191	close(s);
192	perror(name);
193	return errno;
194}
195
196int
197route_add(char *name, int metric, char *dst, char *gateway, char *genmask)
198{
199	return route_manip(SIOCADDRT, name, metric, dst, gateway, genmask);
200}
201
202int
203route_del(char *name, int metric, char *dst, char *gateway, char *genmask)
204{
205	return route_manip(SIOCDELRT, name, metric, dst, gateway, genmask);
206}
207
208/* configure loopback interface */
209void
210config_loopback(void)
211{
212	/* Bring up loopback interface */
213	ifconfig("lo", IFUP, "127.0.0.1", "255.0.0.0");
214
215	/* Add to routing table */
216	route_add("lo", 0, "127.0.0.0", "0.0.0.0", "255.0.0.0");
217}
218
219/* configure/start vlan interface(s) based on nvram settings */
220int
221start_vlan(void)
222{
223	int s;
224	struct ifreq ifr;
225	int i, j;
226	unsigned char ea[ETHER_ADDR_LEN];
227	char buf[256];
228
229
230
231	/* Bob added start, 09/03/2009, to avoid sending router solicitation packets */
232#ifdef INCLUDE_IPV6
233	system("echo 0 > /proc/sys/net/ipv6/conf/all/router_solicitations");
234	system("echo 0 > /proc/sys/net/ipv6/conf/default/router_solicitations"); // pling added 08/16/2010
235#endif
236    /* Bob added end, 09/03/2009, to avoid sending router solicitation packets */
237
238	/* set vlan i/f name to style "vlan<ID>" */
239	eval("vconfig", "set_name_type", "VLAN_PLUS_VID_NO_PAD");
240
241	/* create vlan interfaces */
242	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
243		return errno;
244
245	for (i = 0; i <= VLAN_MAXVID; i ++)
246	{
247		char nvvar_name[16];
248		char vlan_id[16];
249		char *hwname, *hwaddr;
250		char prio[8];
251
252		/* get the address of the EMAC on which the VLAN sits */
253		snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dhwname", i);
254		if (!(hwname = nvram_get(nvvar_name)))
255			continue;
256		snprintf(nvvar_name, sizeof(nvvar_name), "%smacaddr", hwname);
257		if (!(hwaddr = nvram_get(nvvar_name)))
258			continue;
259		ether_atoe(hwaddr, ea);
260		/* find the interface name to which the address is assigned */
261		for (j = 1; j <= DEV_NUMIFS; j ++) {
262			ifr.ifr_ifindex = j;
263			if (ioctl(s, SIOCGIFNAME, &ifr))
264				continue;
265			if (ioctl(s, SIOCGIFHWADDR, &ifr))
266				continue;
267			if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
268				continue;
269			if (!bcmp(ifr.ifr_hwaddr.sa_data, ea, ETHER_ADDR_LEN))
270				break;
271		}
272		if (j > DEV_NUMIFS)
273			continue;
274		if (ioctl(s, SIOCGIFFLAGS, &ifr))
275			continue;
276
277		/* Bob added start, 09/03/2009, to avoid sending router solicitation packets */
278#ifdef INCLUDE_IPV6
279		sprintf(buf, "echo 0 > /proc/sys/net/ipv6/conf/%s/router_solicitations", ifr.ifr_name);
280		system(buf);
281#endif
282		/* Bob added end, 09/03/2009, to avoid sending router solicitation packets */
283
284		if (!(ifr.ifr_flags & IFF_UP))
285			ifconfig(ifr.ifr_name, IFUP, 0, 0);
286		/* create the VLAN interface */
287		snprintf(vlan_id, sizeof(vlan_id), "%d", i);
288		eval("vconfig", "add", ifr.ifr_name, vlan_id);
289		/* setup ingress map (vlan->priority => skb->priority) */
290		snprintf(vlan_id, sizeof(vlan_id), "vlan%d", i);
291		/* Bob added start, 09/03/2009, to avoid sending router solicitation packets */
292#ifdef INCLUDE_IPV6
293		sprintf(buf, "echo 0 > /proc/sys/net/ipv6/conf/%s/router_solicitations", vlan_id);
294		system(buf);
295#endif
296		/* Bob added end, 09/03/2009, to avoid sending router solicitation packets */
297		for (j = 0; j < VLAN_NUMPRIS; j ++) {
298			snprintf(prio, sizeof(prio), "%d", j);
299			eval("vconfig", "set_ingress_map", vlan_id, prio, prio);
300		}
301	}
302
303    /* Bob added start 09/03/2009 */
304#ifdef INCLUDE_IPV6
305	if (nvram_match("ipv6ready", "1"))
306	{
307	    char cmd[32];
308	    sprintf(cmd, "ifconfig vlan1 hw ether %s", nvram_get("lan_hwaddr"));
309	    system(cmd);
310	}
311#endif
312	/* Bob added end 09/03/2009 */
313
314	close(s);
315
316	return 0;
317}
318
319/* stop/rem vlan interface(s) based on nvram settings */
320int
321stop_vlan(void)
322{
323	int i;
324	char nvvar_name[16];
325	char vlan_id[16];
326	char *hwname;
327
328	for (i = 0; i <= VLAN_MAXVID; i ++) {
329		/* get the address of the EMAC on which the VLAN sits */
330		snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dhwname", i);
331		if (!(hwname = nvram_get(nvvar_name)))
332			continue;
333
334		/* remove the VLAN interface */
335		snprintf(vlan_id, sizeof(vlan_id), "vlan%d", i);
336		eval("vconfig", "rem", vlan_id);
337	}
338
339	return 0;
340}
341