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; |
