1/*
2 * Linux network interface code
3 *
4 * Copyright (C) 2014, 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 <linux/sockios.h>
34#include <linux/ethtool.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37#include <net/if_arp.h>
38#include <proto/ethernet.h>
39#include <shutils.h>
40#include <bcmnvram.h>
41#include <bcmutils.h>
42#include <bcmparams.h>
43#include <rc.h>
44
45int
46ifconfig(char *name, int flags, char *addr, char *netmask)
47{
48	int s;
49	struct ifreq ifr;
50	struct in_addr in_addr, in_netmask, in_broadaddr;
51
52	/* Open a raw socket to the kernel */
53	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
54		goto err;
55
56	/* Set interface name */
57	strncpy(ifr.ifr_name, name, IFNAMSIZ);
58
59	/* Set interface flags */
60	ifr.ifr_flags = flags;
61	if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
62		goto err;
63
64	/* Set IP address */
65	if (addr) {
66		inet_aton(addr, &in_addr);
67		sin_addr(&ifr.ifr_addr).s_addr = in_addr.s_addr;
68		ifr.ifr_addr.sa_family = AF_INET;
69		if (ioctl(s, SIOCSIFADDR, &ifr) < 0)
70			goto err;
71	}
72
73	/* Set IP netmask and broadcast */
74	if (addr && netmask) {
75		inet_aton(netmask, &in_netmask);
76		sin_addr(&ifr.ifr_netmask).s_addr = in_netmask.s_addr;
77		ifr.ifr_netmask.sa_family = AF_INET;
78		if (ioctl(s, SIOCSIFNETMASK, &ifr) < 0)
79			goto err;
80
81		in_broadaddr.s_addr = (in_addr.s_addr & in_netmask.s_addr) | ~in_netmask.s_addr;
82		sin_addr(&ifr.ifr_broadaddr).s_addr = in_broadaddr.s_addr;
83		ifr.ifr_broadaddr.sa_family = AF_INET;
84		if (ioctl(s, SIOCSIFBRDADDR, &ifr) < 0)
85			goto err;
86	}
87
88	close(s);
89
90	return 0;
91
92err:
93	close(s);
94	perror(name);
95	return errno;
96}
97
98int
99ifconfig_get(char *name, int *flags, unsigned long *addr, unsigned long *netmask)
100{
101	int s;
102	struct ifreq ifr;
103
104	/* Open a raw socket to the kernel */
105	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
106		goto err;
107
108	/* Set interface name */
109	strncpy(ifr.ifr_name, name, IFNAMSIZ);
110
111	/* Check MAC first */
112	if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
113		goto err;
114	else if (memcmp(ifr.ifr_hwaddr.sa_data, "\0\0\0\0\0\0", 6) == 0)
115		goto err;
116
117	/* Get interface flags */
118	if (flags) {
119		if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
120			goto err;
121		else
122			memcpy(flags, &(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr),
123				sizeof(*flags));
124	}
125
126	/* Get IP address */
127	if (addr) {
128		if (ioctl(s, SIOCGIFADDR, &ifr) < 0)
129			goto err;
130		else
131			memcpy(addr, &(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr),
132				sizeof(*addr));
133	}
134
135	/* Get Net mask */
136	if (netmask) {
137		if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0)
138			goto err;
139		else {
140			memcpy(netmask, &(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr),
141				sizeof(*netmask));
142		}
143	}
144
145	close(s);
146
147	return 0;
148
149err:
150	close(s);
151	perror(name);
152	return errno;
153}
154
155static int
156route_manip(int cmd, char *name, int metric, char *dst, char *gateway, char *genmask)
157{
158	int s;
159	struct rtentry rt;
160
161	/* Open a raw socket to the kernel */
162	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
163		goto err;
164
165	/* Fill in rtentry */
166	memset(&rt, 0, sizeof(rt));
167	if (dst)
168		inet_aton(dst, &sin_addr(&rt.rt_dst));
169	if (gateway)
170		inet_aton(gateway, &sin_addr(&rt.rt_gateway));
171	if (genmask)
172		inet_aton(genmask, &sin_addr(&rt.rt_genmask));
173	rt.rt_metric = metric;
174	rt.rt_flags = RTF_UP;
175	if (sin_addr(&rt.rt_gateway).s_addr)
176		rt.rt_flags |= RTF_GATEWAY;
177	if (sin_addr(&rt.rt_genmask).s_addr == INADDR_BROADCAST)
178		rt.rt_flags |= RTF_HOST;
179	rt.rt_dev = name;
180
181	/* Force address family to AF_INET */
182	rt.rt_dst.sa_family = AF_INET;
183	rt.rt_gateway.sa_family = AF_INET;
184	rt.rt_genmask.sa_family = AF_INET;
185
186	if (ioctl(s, cmd, &rt) < 0)
187		goto err;
188
189	close(s);
190	return 0;
191
192err:
193	close(s);
194	perror(name);
195	return errno;
196}
197
198int
199route_add(char *name, int metric, char *dst, char *gateway, char *genmask)
200{
201	return route_manip(SIOCADDRT, name, metric, dst, gateway, genmask);
202}
203
204int
205route_del(char *name, int metric, char *dst, char *gateway, char *genmask)
206{
207	return route_manip(SIOCDELRT, name, metric, dst, gateway, genmask);
208}
209
210/* configure loopback interface */
211void
212config_loopback(void)
213{
214	/* Bring up loopback interface */
215	ifconfig("lo", IFUP, "127.0.0.1", "255.0.0.0");
216
217	/* Add to routing table */
218	route_add("lo", 0, "127.0.0.0", "0.0.0.0", "255.0.0.0");
219}
220
221void update_port_priority(int vlan_id,char *vlan_interface,int priority)
222{
223    char *ports;
224    char vlanxxports[64];
225
226    sprintf(vlanxxports,"vlan%dports",vlan_id);
227
228    ports=acosNvramConfig_get(vlanxxports);
229
230    if(strlen(ports))
231    {
232        char port_str[32],*next;
233        int port;
234        char priority_command[64];
235   	    foreach(port_str, ports, next) {
236   	        port=atoi(port_str);
237#if defined(R8000)
238   	        if(port==5 || port == 4) // WAN port or CPU port
239   	            break;
240#else
241   	        if(port==5 || port == 0) // WAN port or CPU port
242   	            break;
243#endif
244   	        sprintf(priority_command,"et robowr 0x34 %d %d",0x10+port*2,vlan_id+(priority << 13));
245   	        system(priority_command);
246   	    }
247    }
248}
249
250/* configure/start vlan interface(s) based on nvram settings */
251int
252start_vlan(void)
253{
254	int s;
255	struct ifreq ifr;
256	int i, j;
257	unsigned char ea[ETHER_ADDR_LEN];
258	char buf[256];
259
260
261
262	/* Bob added start, 09/03/2009, to avoid sending router solicitation packets */
263#ifdef INCLUDE_IPV6
264	system("echo 0 > /proc/sys/net/ipv6/conf/all/router_solicitations");
265	system("echo 0 > /proc/sys/net/ipv6/conf/default/router_solicitations"); // pling added 08/16/2010
266#endif
267    /* Bob added end, 09/03/2009, to avoid sending router solicitation packets */
268
269	/* set vlan i/f name to style "vlan<ID>" */
270	eval("vconfig", "set_name_type", "VLAN_PLUS_VID_NO_PAD");
271
272	/* create vlan interfaces */
273	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
274		return errno;
275
276	for (i = 0; i <= VLAN_MAXVID; i ++)
277	{
278		char nvvar_name[16];
279		char vlan_id[16];
280		char *hwname, *hwaddr;
281		char prio[8];
282
283		/* get the address of the EMAC on which the VLAN sits */
284		snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dhwname", i);
285		if (!(hwname = nvram_get(nvvar_name)))
286			continue;
287		snprintf(nvvar_name, sizeof(nvvar_name), "%smacaddr", hwname);
288		if (!(hwaddr = nvram_get(nvvar_name)))
289			continue;
290		ether_atoe(hwaddr, ea);
291		/* find the interface name to which the address is assigned */
292		for (j = 1; j <= DEV_NUMIFS; j ++) {
293			ifr.ifr_ifindex = j;
294			if (ioctl(s, SIOCGIFNAME, &ifr))
295				continue;
296			if (ioctl(s, SIOCGIFHWADDR, &ifr))
297				continue;
298			if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
299				continue;
300			if (!bcmp(ifr.ifr_hwaddr.sa_data, ea, ETHER_ADDR_LEN))
301				break;
302		}
303		if (j > DEV_NUMIFS)
304			continue;
305		if (ioctl(s, SIOCGIFFLAGS, &ifr))
306			continue;
307
308		/* Bob added start, 09/03/2009, to avoid sending router solicitation packets */
309#ifdef INCLUDE_IPV6
310		sprintf(buf, "echo 0 > /proc/sys/net/ipv6/conf/%s/router_solicitations", ifr.ifr_name);
311		system(buf);
312#endif
313		/* Bob added end, 09/03/2009, to avoid sending router solicitation packets */
314
315		if (!(ifr.ifr_flags & IFF_UP))
316			ifconfig(ifr.ifr_name, IFUP, 0, 0);
317		/* create the VLAN interface */
318		sprintf(vlan_id,"%d", i);
319		eval("vconfig", "add", ifr.ifr_name, vlan_id);
320		/* setup ingress map (vlan->priority => skb->priority) */
321		sprintf(vlan_id, "vlan%d", i);
322		/* Bob added start, 09/03/2009, to avoid sending router solicitation packets */
323#ifdef INCLUDE_IPV6
324		sprintf(buf, "echo 0 > /proc/sys/net/ipv6/conf/%s/router_solicitations", vlan_id);
325		system(buf);
326#endif
327		/* Bob added end, 09/03/2009, to avoid sending router solicitation packets */
328		for (j = 0; j < VLAN_NUMPRIS; j ++) {
329			sprintf(prio, "%d", j);
330			eval("vconfig", "set_ingress_map", vlan_id, prio, prio);
331
332/*Foxconn add start, edward zhang, 2013/07/03*/
333#ifdef VLAN_SUPPORT
334
335        /*setup egress vlan priority*/
336        if(nvram_match("enable_vlan","enable"))
337        {
338            char vlan_prio[16];
339            sprintf(vlan_prio,"%s_prio",vlan_id);
340            if(nvram_get(vlan_prio))
341            {
342                update_port_priority(i,vlan_id,atoi(nvram_get(vlan_prio)));
343                if(i==atoi(nvram_get("internet_vlan")))
344                {
345                    if(j==0)
346                    {
347                        eval("vconfig", "set_egress_map",vlan_id, "0", nvram_get("internet_prio"));
348                    }
349                }
350                else
351                    eval("vconfig", "set_egress_map",vlan_id, prio, nvram_get(vlan_prio));
352            }
353        }
354#endif
355/*Foxconn add end, edward zhang, 2013/07/03*/
356		}
357	}
358
359    /* Bob added start 09/03/2009 */
360#ifdef INCLUDE_IPV6
361	if (nvram_match("ipv6ready", "1"))
362	{
363	    char cmd[32];
364	    sprintf(cmd, "ifconfig %s hw ether %s",nvram_get("lan_interface"), nvram_get("lan_hwaddr"));
365	    system(cmd);
366	}
367#endif
368	/* Bob added end 09/03/2009 */
369
370	close(s);
371
372	return 0;
373}
374
375/* stop/rem vlan interface(s) based on nvram settings */
376int
377stop_vlan(void)
378{
379	int i;
380	char nvvar_name[16];
381	char vlan_id[16];
382	char *hwname;
383
384	for (i = 0; i <= VLAN_MAXVID; i ++) {
385		/* get the address of the EMAC on which the VLAN sits */
386		snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dhwname", i);
387		if (!(hwname = nvram_get(nvvar_name)))
388			continue;
389
390		/* remove the VLAN interface */
391		snprintf(vlan_id, sizeof(vlan_id), "vlan%d", i);
392		eval("vconfig", "rem", vlan_id);
393	}
394
395	return 0;
396}
397