diff options
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r-- | net/ipv6/ndisc.c | 49 |
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 */ |
158 | struct ndisc_options { | 158 | struct 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 | ||
1156 | skip_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; |