|
@@ -139,6 +139,7 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
|
139
|
139
|
/**
|
140
|
140
|
* Perform IPv4 routing
|
141
|
141
|
*
|
|
142
|
+ * @v scope_id Destination address scope ID
|
142
|
143
|
* @v dest Final destination address
|
143
|
144
|
* @ret dest Next hop destination address
|
144
|
145
|
* @ret miniroute Routing table entry to use, or NULL if no route
|
|
@@ -146,22 +147,42 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) {
|
146
|
147
|
* If the route requires use of a gateway, the next hop destination
|
147
|
148
|
* address will be overwritten with the gateway address.
|
148
|
149
|
*/
|
149
|
|
-static struct ipv4_miniroute * ipv4_route ( struct in_addr *dest ) {
|
|
150
|
+static struct ipv4_miniroute * ipv4_route ( unsigned int scope_id,
|
|
151
|
+ struct in_addr *dest ) {
|
150
|
152
|
struct ipv4_miniroute *miniroute;
|
151
|
|
- int local;
|
152
|
|
- int has_gw;
|
153
|
153
|
|
154
|
154
|
/* Find first usable route in routing table */
|
155
|
155
|
list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) {
|
|
156
|
+
|
|
157
|
+ /* Skip closed network devices */
|
156
|
158
|
if ( ! netdev_is_open ( miniroute->netdev ) )
|
157
|
159
|
continue;
|
158
|
|
- local = ( ( ( dest->s_addr ^ miniroute->address.s_addr )
|
159
|
|
- & miniroute->netmask.s_addr ) == 0 );
|
160
|
|
- has_gw = ( miniroute->gateway.s_addr );
|
161
|
|
- if ( local || has_gw ) {
|
162
|
|
- if ( ! local )
|
|
160
|
+
|
|
161
|
+ if ( IN_IS_MULTICAST ( dest->s_addr ) ) {
|
|
162
|
+
|
|
163
|
+ /* If destination is non-global, and the scope ID
|
|
164
|
+ * matches this network device, then use this route.
|
|
165
|
+ */
|
|
166
|
+ if ( miniroute->netdev->index == scope_id )
|
|
167
|
+ return miniroute;
|
|
168
|
+
|
|
169
|
+ } else {
|
|
170
|
+
|
|
171
|
+ /* If destination is an on-link global
|
|
172
|
+ * address, then use this route.
|
|
173
|
+ */
|
|
174
|
+ if ( ( ( dest->s_addr ^ miniroute->address.s_addr )
|
|
175
|
+ & miniroute->netmask.s_addr ) == 0 )
|
|
176
|
+ return miniroute;
|
|
177
|
+
|
|
178
|
+ /* If destination is an off-link global
|
|
179
|
+ * address, and we have a default gateway,
|
|
180
|
+ * then use this route.
|
|
181
|
+ */
|
|
182
|
+ if ( miniroute->gateway.s_addr ) {
|
163
|
183
|
*dest = miniroute->gateway;
|
164
|
|
- return miniroute;
|
|
184
|
+ return miniroute;
|
|
185
|
+ }
|
165
|
186
|
}
|
166
|
187
|
}
|
167
|
188
|
|
|
@@ -180,7 +201,7 @@ static struct net_device * ipv4_netdev ( struct sockaddr_tcpip *st_dest ) {
|
180
|
201
|
struct ipv4_miniroute *miniroute;
|
181
|
202
|
|
182
|
203
|
/* Find routing table entry */
|
183
|
|
- miniroute = ipv4_route ( &dest );
|
|
204
|
+ miniroute = ipv4_route ( sin_dest->sin_scope_id, &dest );
|
184
|
205
|
if ( ! miniroute )
|
185
|
206
|
return NULL;
|
186
|
207
|
|
|
@@ -314,8 +335,8 @@ static int ipv4_tx ( struct io_buffer *iobuf,
|
314
|
335
|
if ( sin_src )
|
315
|
336
|
iphdr->src = sin_src->sin_addr;
|
316
|
337
|
if ( ( next_hop.s_addr != INADDR_BROADCAST ) &&
|
317
|
|
- ( ! IN_IS_MULTICAST ( next_hop.s_addr ) ) &&
|
318
|
|
- ( ( miniroute = ipv4_route ( &next_hop ) ) != NULL ) ) {
|
|
338
|
+ ( ( miniroute = ipv4_route ( sin_dest->sin_scope_id,
|
|
339
|
+ &next_hop ) ) != NULL ) ) {
|
319
|
340
|
iphdr->src = miniroute->address;
|
320
|
341
|
netmask = miniroute->netmask;
|
321
|
342
|
netdev = miniroute->netdev;
|