1/*
2 * Linux network interface code
3 *
4 * Copyright 2004, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
11 *
12 * $Id: interface.c,v 1.1.1.1 2008/10/15 03:28:48 james26_jang Exp $
13 */
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <ctype.h>
18#include <errno.h>
19#include <error.h>
20#include <string.h>
21#include <unistd.h>
22#include <sys/ioctl.h>
23#include <sys/types.h>
24#include <sys/socket.h>
25#include <net/if.h>
26#include <net/route.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29#include <net/if_arp.h>
30#include <proto/ethernet.h>
31#include <shutils.h>
32#include <bcmnvram.h>
33#include <bcmutils.h>
34#include <bcmparams.h>
35#include <rc.h>
36
37in_addr_t
38inet_addr_(const char *cp)
39{
40        struct in_addr a;
41
42        if (!inet_aton(cp, &a))
43                return INADDR_ANY;
44        else
45                return a.s_addr;
46}
47
48
49int
50ifconfig(char *name, int flags, char *addr, char *netmask)
51{
52	int s;
53	struct ifreq ifr;
54	struct in_addr in_addr, in_netmask, in_broadaddr;
55
56	/* Open a raw socket to the kernel */
57	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
58		goto err;
59
60	/* Set interface name */
61	strncpy(ifr.ifr_name, name, IFNAMSIZ);
62
63	/* Set interface flags */
64	ifr.ifr_flags = flags;
65	if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
66		goto err;
67
68	/* Set IP address */
69	if (addr) {
70		inet_aton(addr, &in_addr);
71		sin_addr(&ifr.ifr_addr).s_addr = in_addr.s_addr;
72		ifr.ifr_addr.sa_family = AF_INET;
73		if (ioctl(s, SIOCSIFADDR, &ifr) < 0)
74			goto err;
75	}
76
77	/* Set IP netmask and broadcast */
78	if (addr && netmask) {
79		inet_aton(netmask, &in_netmask);
80		sin_addr(&ifr.ifr_netmask).s_addr = in_netmask.s_addr;
81		ifr.ifr_netmask.sa_family = AF_INET;
82		if (ioctl(s, SIOCSIFNETMASK, &ifr) < 0)
83			goto err;
84
85		in_broadaddr.s_addr = (in_addr.s_addr & in_netmask.s_addr) | ~in_netmask.s_addr;
86		sin_addr(&ifr.ifr_broadaddr).s_addr = in_broadaddr.s_addr;
87		ifr.ifr_broadaddr.sa_family = AF_INET;
88		if (ioctl(s, SIOCSIFBRDADDR, &ifr) < 0)
89			goto err;
90	}
91
92	close(s);
93
94	return 0;
95
96 err:
97	close(s);
98	perror(name);
99	return errno;
100}
101
102static int
103route_manip(int cmd, char *name, int metric, char *dst, char *gateway, char *genmask)
104{
105	int s;
106	struct rtentry rt;
107
108	/* Open a raw socket to the kernel */
109	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
110		goto err;
111
112	/* Fill in rtentry */
113	memset(&rt, 0, sizeof(rt));
114	if (dst)
115		inet_aton(dst, &sin_addr(&rt.rt_dst));
116	if (gateway)
117		inet_aton(gateway, &sin_addr(&rt.rt_gateway));
118	if (genmask)
119		inet_aton(genmask, &sin_addr(&rt.rt_genmask));
120	rt.rt_metric = metric;
121	rt.rt_flags = RTF_UP;
122	if (sin_addr(&rt.rt_gateway).s_addr)
123		rt.rt_flags |= RTF_GATEWAY;
124	if (sin_addr(&rt.rt_genmask).s_addr == INADDR_BROADCAST)
125		rt.rt_flags |= RTF_HOST;
126	rt.rt_dev = name;
127
128	/* Force address family to AF_INET */
129	rt.rt_dst.sa_family = AF_INET;
130	rt.rt_gateway.sa_family = AF_INET;
131	rt.rt_genmask.sa_family = AF_INET;
132
133	if (ioctl(s, cmd, &rt) < 0)
134		goto err;
135
136	close(s);
137	return 0;
138
139 err:
140	close(s);
141	perror(name);
142	return errno;
143}
144
145int
146route_add(char *name, int metric, char *dst, char *gateway, char *genmask)
147{
148	return route_manip(SIOCADDRT, name, metric, dst, gateway, genmask);
149}
150
151int
152route_del(char *name, int metric, char *dst, char *gateway, char *genmask)
153{
154	return route_manip(SIOCDELRT, name, metric, dst, gateway, genmask);
155}
156
157/* configure loopback interface */
158void
159config_loopback(void)
160{
161	/* Bring up loopback interface */
162	ifconfig("lo", IFUP, "127.0.0.1", "255.0.0.0");
163
164	/* Add to routing table */
165	route_add("lo", 0, "127.0.0.0", "0.0.0.0", "255.0.0.0");
166}
167
168#ifndef CONFIG_SENTRY5
169/* configure/start vlan interface(s) based on nvram settings */
170int
171start_vlan(void)
172{
173	int s;
174	struct ifreq ifr;
175	int i, j;
176	char ea[ETHER_ADDR_LEN];
177
178	/* set vlan i/f name to style "vlan<ID>" */
179	//printf("vconfig setname_type VLAN_PLUS_VID_NO_PAD\n");
180	eval("vconfig", "set_name_type", "VLAN_PLUS_VID_NO_PAD");
181
182	/* create vlan interfaces */
183	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
184		return errno;
185
186	for (i = 0; i <= VLAN_MAXVID; i ++) {
187		char nvvar_name[16];
188		char vlan_id[16];
189		char *hwname, *hwaddr;
190		char prio[8];
191		/* get the address of the EMAC on which the VLAN sits */
192		snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dhwname", i);
193		if (!(hwname = nvram_get(nvvar_name)))
194			continue;
195		snprintf(nvvar_name, sizeof(nvvar_name), "%smacaddr", hwname);
196		if (!(hwaddr = nvram_get(nvvar_name)))
197			continue;
198		ether_atoe(hwaddr, ea);
199		/* find the interface name to which the address is assigned */
200		for (j = 1; j <= DEV_NUMIFS; j ++) {
201			ifr.ifr_ifindex = j;
202			if (ioctl(s, SIOCGIFNAME, &ifr))
203				continue;
204			if (ioctl(s, SIOCGIFHWADDR, &ifr))
205				continue;
206			if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
207				continue;
208			if (!bcmp(ifr.ifr_hwaddr.sa_data, ea, ETHER_ADDR_LEN))
209				break;
210		}
211		if (j > DEV_NUMIFS)
212			continue;
213		if (ioctl(s, SIOCGIFFLAGS, &ifr))
214			continue;
215		if (!(ifr.ifr_flags & IFF_UP))
216			ifconfig(ifr.ifr_name, IFUP, 0, 0);
217		/* create the VLAN interface */
218		snprintf(vlan_id, sizeof(vlan_id), "%d", i);
219		//printf("vconfig add %s %s\n", ifr.ifr_name, vlan_id);
220		eval("vconfig", "add", ifr.ifr_name, vlan_id);
221		/* setup ingress map (vlan->priority => skb->priority) */
222		snprintf(vlan_id, sizeof(vlan_id), "vlan%d", i);
223		for (j = 0; j < VLAN_NUMPRIS; j ++) {
224			snprintf(prio, sizeof(prio), "%d", j);
225			//printf("vconfig set_ingress_map %s %s %s\n", vlan_id, prio, prio);
226			eval("vconfig", "set_ingress_map", vlan_id, prio, prio);
227		}
228	}
229
230	close(s);
231
232	return 0;
233}
234
235/* stop/rem vlan interface(s) based on nvram settings */
236int
237stop_vlan(void)
238{
239	int i;
240	char nvvar_name[16];
241	char vlan_id[16];
242	char *hwname;
243
244	for (i = 0; i <= VLAN_MAXVID; i ++) {
245		/* get the address of the EMAC on which the VLAN sits */
246		snprintf(nvvar_name, sizeof(nvvar_name), "vlan%dhwname", i);
247		if (!(hwname = nvram_get(nvvar_name)))
248			continue;
249
250		/* remove the VLAN interface */
251		snprintf(vlan_id, sizeof(vlan_id), "vlan%d", i);
252		//printf("vconfig rem %s\n", vlan_id);
253		eval("vconfig", "rem", vlan_id);
254	}
255
256	return 0;
257}
258#endif
259