2 * Linux network interface code
4 * Copyright 2005, Broadcom Corporation
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.
12 * $Id: interface.c,v 1.13 2005/03/07 08:35:32 kanki Exp $
22 #include <sys/ioctl.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <net/route.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <net/if_arp.h>
29 #include <proto/ethernet.h>
34 #include <bcmparams.h>
40 int _ifconfig(const char *name
, int flags
, const char *addr
, const char *netmask
, const char *dstaddr
)
44 struct in_addr in_addr
, in_netmask
, in_broadaddr
;
46 _dprintf("%s: name=%s flags=%s addr=%s netmask=%s\n", __FUNCTION__
, name
, flags
== IFUP
? "IFUP" : "0", addr
, netmask
);
48 /* Open a raw socket to the kernel */
49 if ((s
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0) return errno
;
51 /* Set interface name */
52 strlcpy(ifr
.ifr_name
, name
, IFNAMSIZ
);
54 /* Set interface flags */
55 ifr
.ifr_flags
= flags
;
56 if (ioctl(s
, SIOCSIFFLAGS
, &ifr
) < 0)
61 inet_aton(addr
, &in_addr
);
62 sin_addr(&ifr
.ifr_addr
).s_addr
= in_addr
.s_addr
;
63 ifr
.ifr_addr
.sa_family
= AF_INET
;
64 if (ioctl(s
, SIOCSIFADDR
, &ifr
) < 0)
68 /* Set IP netmask and broadcast */
69 if (addr
&& netmask
) {
70 inet_aton(netmask
, &in_netmask
);
71 sin_addr(&ifr
.ifr_netmask
).s_addr
= in_netmask
.s_addr
;
72 ifr
.ifr_netmask
.sa_family
= AF_INET
;
73 if (ioctl(s
, SIOCSIFNETMASK
, &ifr
) < 0)
76 in_broadaddr
.s_addr
= (in_addr
.s_addr
& in_netmask
.s_addr
) | ~in_netmask
.s_addr
;
77 sin_addr(&ifr
.ifr_broadaddr
).s_addr
= in_broadaddr
.s_addr
;
78 ifr
.ifr_broadaddr
.sa_family
= AF_INET
;
79 if (ioctl(s
, SIOCSIFBRDADDR
, &ifr
) < 0)
83 /* Set dst or P-t-P IP address */
85 inet_aton(dstaddr
, &in_addr
);
86 sin_addr(&ifr
.ifr_dstaddr
).s_addr
= in_addr
.s_addr
;
87 ifr
.ifr_dstaddr
.sa_family
= AF_INET
;
88 if (ioctl(s
, SIOCSIFDSTADDR
, &ifr
) < 0)
101 static int route_manip(int cmd
, char *name
, int metric
, char *dst
, char *gateway
, char *genmask
)
106 _dprintf("%s: cmd=%s name=%s addr=%s netmask=%s gateway=%s metric=%d\n",
107 __FUNCTION__
, cmd
== SIOCADDRT
? "ADD" : "DEL", name
, dst
, genmask
, gateway
, metric
);
109 /* Open a raw socket to the kernel */
110 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0) return errno
;
112 /* Fill in rtentry */
113 memset(&rt
, 0, sizeof(rt
));
115 inet_aton(dst
, &sin_addr(&rt
.rt_dst
));
117 inet_aton(gateway
, &sin_addr(&rt
.rt_gateway
));
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
;
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
;
133 if (ioctl(s
, cmd
, &rt
) < 0) {
144 int route_add(char *name
, int metric
, char *dst
, char *gateway
, char *genmask
)
146 return route_manip(SIOCADDRT
, name
, metric
+ 1, dst
, gateway
, genmask
);
149 void route_del(char *name
, int metric
, char *dst
, char *gateway
, char *genmask
)
151 while (route_manip(SIOCDELRT
, name
, metric
+ 1, dst
, gateway
, genmask
) == 0) {
156 /* configure loopback interface */
157 void config_loopback(void)
159 /* Bring up loopback interface */
160 ifconfig("lo", IFUP
, "127.0.0.1", "255.0.0.0");
162 /* Add to routing table */
163 route_add("lo", 0, "127.0.0.0", "0.0.0.0", "255.0.0.0");
167 int ipv6_mapaddr4(struct in6_addr
*addr6
, int ip6len
, struct in_addr
*addr4
, int ip4mask
)
170 int m
= ip6len
& 0x1f;
171 int ret
= ip6len
+ 32 - ip4mask
;
173 u_int32_t mask
= 0xffffffffUL
<< ip4mask
;
175 if (ip6len
> 128 || ip4mask
> 32 || ret
> 128)
181 addr
= ntohl(addr4
->s_addr
) << ip4mask
;
183 addr6
->s6_addr32
[i
] &= ~htonl(mask
>> m
);
184 addr6
->s6_addr32
[i
] |= htonl(addr
>> m
);
187 addr6
->s6_addr32
[i
] &= ~htonl(mask
<< (32 - m
));
188 addr6
->s6_addr32
[i
] |= htonl(addr
<< (32 - m
));
195 /* configure/start vlan interface(s) based on nvram settings */
201 char ea
[ETHER_ADDR_LEN
];
203 if ((strtoul(nvram_safe_get("boardflags"), NULL
, 0) & BFL_ENETVLAN
) == 0) return 0;
205 /* set vlan i/f name to style "vlan<ID>" */
206 eval("vconfig", "set_name_type", "VLAN_PLUS_VID_NO_PAD");
208 /* create vlan interfaces */
209 if ((s
= socket(AF_INET
, SOCK_RAW
, IPPROTO_RAW
)) < 0)
212 vlan0tag
= nvram_get_int("vlan0tag");
214 for (i
= 0; i
<= VLAN_MAXVID
; i
++) {
217 char *hwname
, *hwaddr
;
221 /* get the address of the EMAC on which the VLAN sits */
222 snprintf(nvvar_name
, sizeof(nvvar_name
), "vlan%dhwname", i
);
223 if (!(hwname
= nvram_get(nvvar_name
)))
225 snprintf(nvvar_name
, sizeof(nvvar_name
), "%smacaddr", hwname
);
226 if (!(hwaddr
= nvram_get(nvvar_name
)))
228 ether_atoe(hwaddr
, ea
);
229 /* find the interface name to which the address is assigned */
230 for (j
= 1; j
<= DEV_NUMIFS
; j
++) {
232 if (ioctl(s
, SIOCGIFNAME
, &ifr
))
234 if (ioctl(s
, SIOCGIFHWADDR
, &ifr
))
236 if (ifr
.ifr_hwaddr
.sa_family
!= ARPHRD_ETHER
)
238 if (!bcmp(ifr
.ifr_hwaddr
.sa_data
, ea
, ETHER_ADDR_LEN
))
243 if (ioctl(s
, SIOCGIFFLAGS
, &ifr
))
245 if (!(ifr
.ifr_flags
& IFF_UP
))
246 ifconfig(ifr
.ifr_name
, IFUP
, 0, 0);
248 /* vlan ID mapping */
249 snprintf(nvvar_name
, sizeof(nvvar_name
), "vlan%dvid", i
);
250 vid_map
= nvram_get_int(nvvar_name
);
251 if ((vid_map
< 1) || (vid_map
> 4094)) vid_map
= vlan0tag
| i
;
253 /* create the VLAN interface */
254 snprintf(vlan_id
, sizeof(vlan_id
), "%d", vid_map
);
255 eval("vconfig", "add", ifr
.ifr_name
, vlan_id
);
256 /* setup ingress map (vlan->priority => skb->priority) */
257 snprintf(vlan_id
, sizeof(vlan_id
), "vlan%d", vid_map
);
258 for (j
= 0; j
< VLAN_NUMPRIS
; j
++) {
259 snprintf(prio
, sizeof(prio
), "%d", j
);
260 eval("vconfig", "set_ingress_map", vlan_id
, prio
, prio
);
269 /* stop/rem vlan interface(s) based on nvram settings */
273 int vlan0tag
, vid_map
;
278 if ((strtoul(nvram_safe_get("boardflags"), NULL
, 0) & BFL_ENETVLAN
) == 0) return 0;
280 vlan0tag
= nvram_get_int("vlan0tag");
282 for (i
= 0; i
<= VLAN_MAXVID
; i
++) {
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
)))
288 /* vlan ID mapping */
289 snprintf(nvvar_name
, sizeof(nvvar_name
), "vlan%dvid", i
);
290 vid_map
= nvram_get_int(nvvar_name
);
291 if ((vid_map
< 1) || (vid_map
> 4094)) vid_map
= vlan0tag
| i
;
293 /* remove the VLAN interface */
294 snprintf(vlan_id
, sizeof(vlan_id
), "vlan%d", vid_map
);
295 eval("vconfig", "rem", vlan_id
);