aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ndisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r--net/ipv6/ndisc.c49
1 files changed, 45 insertions, 4 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index cb8856b1d951..dfa20d3be9b6 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -156,7 +156,11 @@ struct neigh_table nd_tbl = {
156 156
157/* ND options */ 157/* ND options */
158struct ndisc_options { 158struct ndisc_options {
159 struct nd_opt_hdr *nd_opt_array[__ND_OPT_MAX]; 159 struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX];
160#ifdef CONFIG_IPV6_ROUTE_INFO
161 struct nd_opt_hdr *nd_opts_ri;
162 struct nd_opt_hdr *nd_opts_ri_end;
163#endif
160}; 164};
161 165
162#define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR] 166#define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR]
@@ -255,6 +259,13 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
255 if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0) 259 if (ndopts->nd_opt_array[nd_opt->nd_opt_type] == 0)
256 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; 260 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
257 break; 261 break;
262#ifdef CONFIG_IPV6_ROUTE_INFO
263 case ND_OPT_ROUTE_INFO:
264 ndopts->nd_opts_ri_end = nd_opt;
265 if (!ndopts->nd_opts_ri)
266 ndopts->nd_opts_ri = nd_opt;
267 break;
268#endif
258 default: 269 default:
259 /* 270 /*
260 * Unknown options must be silently ignored, 271 * Unknown options must be silently ignored,
@@ -1019,10 +1030,11 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1019 struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw; 1030 struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
1020 struct neighbour *neigh = NULL; 1031 struct neighbour *neigh = NULL;
1021 struct inet6_dev *in6_dev; 1032 struct inet6_dev *in6_dev;
1022 struct rt6_info *rt; 1033 struct rt6_info *rt = NULL;
1023 int lifetime; 1034 int lifetime;
1024 struct ndisc_options ndopts; 1035 struct ndisc_options ndopts;
1025 int optlen; 1036 int optlen;
1037 unsigned int pref = 0;
1026 1038
1027 __u8 * opt = (__u8 *)(ra_msg + 1); 1039 __u8 * opt = (__u8 *)(ra_msg + 1);
1028 1040
@@ -1081,8 +1093,19 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1081 (ra_msg->icmph.icmp6_addrconf_other ? 1093 (ra_msg->icmph.icmp6_addrconf_other ?
1082 IF_RA_OTHERCONF : 0); 1094 IF_RA_OTHERCONF : 0);
1083 1095
1096 if (!in6_dev->cnf.accept_ra_defrtr)
1097 goto skip_defrtr;
1098
1084 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); 1099 lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
1085 1100
1101#ifdef CONFIG_IPV6_ROUTER_PREF
1102 pref = ra_msg->icmph.icmp6_router_pref;
1103 /* 10b is handled as if it were 00b (medium) */
1104 if (pref == ICMPV6_ROUTER_PREF_INVALID ||
1105 in6_dev->cnf.accept_ra_rtr_pref)
1106 pref = ICMPV6_ROUTER_PREF_MEDIUM;
1107#endif
1108
1086 rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); 1109 rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
1087 1110
1088 if (rt) 1111 if (rt)
@@ -1098,7 +1121,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1098 ND_PRINTK3(KERN_DEBUG 1121 ND_PRINTK3(KERN_DEBUG
1099 "ICMPv6 RA: adding default router.\n"); 1122 "ICMPv6 RA: adding default router.\n");
1100 1123
1101 rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); 1124 rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref);
1102 if (rt == NULL) { 1125 if (rt == NULL) {
1103 ND_PRINTK0(KERN_ERR 1126 ND_PRINTK0(KERN_ERR
1104 "ICMPv6 RA: %s() failed to add default route.\n", 1127 "ICMPv6 RA: %s() failed to add default route.\n",
@@ -1117,6 +1140,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1117 return; 1140 return;
1118 } 1141 }
1119 neigh->flags |= NTF_ROUTER; 1142 neigh->flags |= NTF_ROUTER;
1143 } else if (rt) {
1144 rt->rt6i_flags |= (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);
1120 } 1145 }
1121 1146
1122 if (rt) 1147 if (rt)
@@ -1128,6 +1153,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1128 rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit; 1153 rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
1129 } 1154 }
1130 1155
1156skip_defrtr:
1157
1131 /* 1158 /*
1132 * Update Reachable Time and Retrans Timer 1159 * Update Reachable Time and Retrans Timer
1133 */ 1160 */
@@ -1186,7 +1213,21 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1186 NEIGH_UPDATE_F_ISROUTER); 1213 NEIGH_UPDATE_F_ISROUTER);
1187 } 1214 }
1188 1215
1189 if (ndopts.nd_opts_pi) { 1216#ifdef CONFIG_IPV6_ROUTE_INFO
1217 if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
1218 struct nd_opt_hdr *p;
1219 for (p = ndopts.nd_opts_ri;
1220 p;
1221 p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
1222 if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
1223 continue;
1224 rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
1225 &skb->nh.ipv6h->saddr);
1226 }
1227 }
1228#endif
1229
1230 if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
1190 struct nd_opt_hdr *p; 1231 struct nd_opt_hdr *p;
1191 for (p = ndopts.nd_opts_pi; 1232 for (p = ndopts.nd_opts_pi;
1192 p; 1233 p;