|  | @@ -79,11 +79,11 @@ static struct profiler ipv4_rx_profiler __profiler = { .name = "ipv4.rx" };
 | 
		
	
		
			
			| 79 | 79 |   * @v address		IPv4 address
 | 
		
	
		
			
			| 80 | 80 |   * @v netmask		Subnet mask
 | 
		
	
		
			
			| 81 | 81 |   * @v gateway		Gateway address (if any)
 | 
		
	
		
			
			| 82 |  | - * @ret miniroute	Routing table entry, or NULL
 | 
		
	
		
			
			|  | 82 | + * @ret rc		Return status code
 | 
		
	
		
			
			| 83 | 83 |   */
 | 
		
	
		
			
			| 84 |  | -static struct ipv4_miniroute * __malloc
 | 
		
	
		
			
			| 85 |  | -add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
 | 
		
	
		
			
			| 86 |  | -		     struct in_addr netmask, struct in_addr gateway ) {
 | 
		
	
		
			
			|  | 84 | +static int add_ipv4_miniroute ( struct net_device *netdev,
 | 
		
	
		
			
			|  | 85 | +				struct in_addr address, struct in_addr netmask,
 | 
		
	
		
			
			|  | 86 | +				struct in_addr gateway ) {
 | 
		
	
		
			
			| 87 | 87 |  	struct ipv4_miniroute *miniroute;
 | 
		
	
		
			
			| 88 | 88 |  
 | 
		
	
		
			
			| 89 | 89 |  	DBGC ( netdev, "IPv4 add %s", inet_ntoa ( address ) );
 | 
		
	
	
		
			
			|  | @@ -96,7 +96,7 @@ add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
 | 
		
	
		
			
			| 96 | 96 |  	miniroute = malloc ( sizeof ( *miniroute ) );
 | 
		
	
		
			
			| 97 | 97 |  	if ( ! miniroute ) {
 | 
		
	
		
			
			| 98 | 98 |  		DBGC ( netdev, "IPv4 could not add miniroute\n" );
 | 
		
	
		
			
			| 99 |  | -		return NULL;
 | 
		
	
		
			
			|  | 99 | +		return -ENOMEM;
 | 
		
	
		
			
			| 100 | 100 |  	}
 | 
		
	
		
			
			| 101 | 101 |  
 | 
		
	
		
			
			| 102 | 102 |  	/* Record routing information */
 | 
		
	
	
		
			
			|  | @@ -114,7 +114,7 @@ add_ipv4_miniroute ( struct net_device *netdev, struct in_addr address,
 | 
		
	
		
			
			| 114 | 114 |  		list_add ( &miniroute->list, &ipv4_miniroutes );
 | 
		
	
		
			
			| 115 | 115 |  	}
 | 
		
	
		
			
			| 116 | 116 |  
 | 
		
	
		
			
			| 117 |  | -	return miniroute;
 | 
		
	
		
			
			|  | 117 | +	return 0;
 | 
		
	
		
			
			| 118 | 118 |  }
 | 
		
	
		
			
			| 119 | 119 |  
 | 
		
	
		
			
			| 120 | 120 |  /**
 | 
		
	
	
		
			
			|  | @@ -812,33 +812,69 @@ const struct setting gateway_setting __setting ( SETTING_IP, gateway ) = {
 | 
		
	
		
			
			| 812 | 812 |  };
 | 
		
	
		
			
			| 813 | 813 |  
 | 
		
	
		
			
			| 814 | 814 |  /**
 | 
		
	
		
			
			| 815 |  | - * Create IPv4 routing table based on configured settings
 | 
		
	
		
			
			|  | 815 | + * Send gratuitous ARP, if applicable
 | 
		
	
		
			
			| 816 | 816 |   *
 | 
		
	
		
			
			|  | 817 | + * @v netdev		Network device
 | 
		
	
		
			
			|  | 818 | + * @v address		IPv4 address
 | 
		
	
		
			
			|  | 819 | + * @v netmask		Subnet mask
 | 
		
	
		
			
			|  | 820 | + * @v gateway		Gateway address (if any)
 | 
		
	
		
			
			| 817 | 821 |   * @ret rc		Return status code
 | 
		
	
		
			
			| 818 | 822 |   */
 | 
		
	
		
			
			| 819 |  | -static int ipv4_create_routes ( void ) {
 | 
		
	
		
			
			| 820 |  | -	struct ipv4_miniroute *miniroute;
 | 
		
	
		
			
			| 821 |  | -	struct ipv4_miniroute *tmp;
 | 
		
	
		
			
			|  | 823 | +static int ipv4_gratuitous_arp ( struct net_device *netdev,
 | 
		
	
		
			
			|  | 824 | +				 struct in_addr address,
 | 
		
	
		
			
			|  | 825 | +				 struct in_addr netmask __unused,
 | 
		
	
		
			
			|  | 826 | +				 struct in_addr gateway __unused ) {
 | 
		
	
		
			
			|  | 827 | +	int rc;
 | 
		
	
		
			
			|  | 828 | +
 | 
		
	
		
			
			|  | 829 | +	/* Do nothing if network device already has this IPv4 address */
 | 
		
	
		
			
			|  | 830 | +	if ( ipv4_has_addr ( netdev, address ) )
 | 
		
	
		
			
			|  | 831 | +		return 0;
 | 
		
	
		
			
			|  | 832 | +
 | 
		
	
		
			
			|  | 833 | +	/* Transmit gratuitous ARP */
 | 
		
	
		
			
			|  | 834 | +	DBGC ( netdev, "IPv4 sending gratuitous ARP for %s via %s\n",
 | 
		
	
		
			
			|  | 835 | +	       inet_ntoa ( address ), netdev->name );
 | 
		
	
		
			
			|  | 836 | +	if ( ( rc = arp_tx_request ( netdev, &ipv4_protocol, &address,
 | 
		
	
		
			
			|  | 837 | +				     &address ) ) != 0 ) {
 | 
		
	
		
			
			|  | 838 | +		DBGC ( netdev, "IPv4 could not transmit gratuitous ARP: %s\n",
 | 
		
	
		
			
			|  | 839 | +		       strerror ( rc ) );
 | 
		
	
		
			
			|  | 840 | +		/* Treat failures as non-fatal */
 | 
		
	
		
			
			|  | 841 | +	}
 | 
		
	
		
			
			|  | 842 | +
 | 
		
	
		
			
			|  | 843 | +	return 0;
 | 
		
	
		
			
			|  | 844 | +}
 | 
		
	
		
			
			|  | 845 | +
 | 
		
	
		
			
			|  | 846 | +/**
 | 
		
	
		
			
			|  | 847 | + * Process IPv4 network device settings
 | 
		
	
		
			
			|  | 848 | + *
 | 
		
	
		
			
			|  | 849 | + * @v apply		Application method
 | 
		
	
		
			
			|  | 850 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 851 | + */
 | 
		
	
		
			
			|  | 852 | +static int ipv4_settings ( int ( * apply ) ( struct net_device *netdev,
 | 
		
	
		
			
			|  | 853 | +					     struct in_addr address,
 | 
		
	
		
			
			|  | 854 | +					     struct in_addr netmask,
 | 
		
	
		
			
			|  | 855 | +					     struct in_addr gateway ) ) {
 | 
		
	
		
			
			| 822 | 856 |  	struct net_device *netdev;
 | 
		
	
		
			
			| 823 | 857 |  	struct settings *settings;
 | 
		
	
		
			
			| 824 | 858 |  	struct in_addr address = { 0 };
 | 
		
	
		
			
			| 825 | 859 |  	struct in_addr netmask = { 0 };
 | 
		
	
		
			
			| 826 | 860 |  	struct in_addr gateway = { 0 };
 | 
		
	
		
			
			|  | 861 | +	int rc;
 | 
		
	
		
			
			| 827 | 862 |  
 | 
		
	
		
			
			| 828 |  | -	/* Delete all existing routes */
 | 
		
	
		
			
			| 829 |  | -	list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
 | 
		
	
		
			
			| 830 |  | -		del_ipv4_miniroute ( miniroute );
 | 
		
	
		
			
			| 831 |  | -
 | 
		
	
		
			
			| 832 |  | -	/* Create a route for each configured network device */
 | 
		
	
		
			
			|  | 863 | +	/* Process settings for each network device */
 | 
		
	
		
			
			| 833 | 864 |  	for_each_netdev ( netdev ) {
 | 
		
	
		
			
			|  | 865 | +
 | 
		
	
		
			
			|  | 866 | +		/* Get network device settings */
 | 
		
	
		
			
			| 834 | 867 |  		settings = netdev_settings ( netdev );
 | 
		
	
		
			
			|  | 868 | +
 | 
		
	
		
			
			| 835 | 869 |  		/* Get IPv4 address */
 | 
		
	
		
			
			| 836 | 870 |  		address.s_addr = 0;
 | 
		
	
		
			
			| 837 | 871 |  		fetch_ipv4_setting ( settings, &ip_setting, &address );
 | 
		
	
		
			
			| 838 | 872 |  		if ( ! address.s_addr )
 | 
		
	
		
			
			| 839 | 873 |  			continue;
 | 
		
	
		
			
			|  | 874 | +
 | 
		
	
		
			
			| 840 | 875 |  		/* Get subnet mask */
 | 
		
	
		
			
			| 841 | 876 |  		fetch_ipv4_setting ( settings, &netmask_setting, &netmask );
 | 
		
	
		
			
			|  | 877 | +
 | 
		
	
		
			
			| 842 | 878 |  		/* Calculate default netmask, if necessary */
 | 
		
	
		
			
			| 843 | 879 |  		if ( ! netmask.s_addr ) {
 | 
		
	
		
			
			| 844 | 880 |  			if ( IN_IS_CLASSA ( address.s_addr ) ) {
 | 
		
	
	
		
			
			|  | @@ -849,18 +885,42 @@ static int ipv4_create_routes ( void ) {
 | 
		
	
		
			
			| 849 | 885 |  				netmask.s_addr = INADDR_NET_CLASSC;
 | 
		
	
		
			
			| 850 | 886 |  			}
 | 
		
	
		
			
			| 851 | 887 |  		}
 | 
		
	
		
			
			|  | 888 | +
 | 
		
	
		
			
			| 852 | 889 |  		/* Get default gateway, if present */
 | 
		
	
		
			
			| 853 | 890 |  		fetch_ipv4_setting ( settings, &gateway_setting, &gateway );
 | 
		
	
		
			
			| 854 |  | -		/* Configure route */
 | 
		
	
		
			
			| 855 |  | -		miniroute = add_ipv4_miniroute ( netdev, address,
 | 
		
	
		
			
			| 856 |  | -						 netmask, gateway );
 | 
		
	
		
			
			| 857 |  | -		if ( ! miniroute )
 | 
		
	
		
			
			| 858 |  | -			return -ENOMEM;
 | 
		
	
		
			
			|  | 891 | +
 | 
		
	
		
			
			|  | 892 | +		/* Apply settings */
 | 
		
	
		
			
			|  | 893 | +		if ( ( rc = apply ( netdev, address, netmask, gateway ) ) != 0 )
 | 
		
	
		
			
			|  | 894 | +			return rc;
 | 
		
	
		
			
			| 859 | 895 |  	}
 | 
		
	
		
			
			| 860 | 896 |  
 | 
		
	
		
			
			| 861 | 897 |  	return 0;
 | 
		
	
		
			
			| 862 | 898 |  }
 | 
		
	
		
			
			| 863 | 899 |  
 | 
		
	
		
			
			|  | 900 | +/**
 | 
		
	
		
			
			|  | 901 | + * Create IPv4 routing table based on configured settings
 | 
		
	
		
			
			|  | 902 | + *
 | 
		
	
		
			
			|  | 903 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 904 | + */
 | 
		
	
		
			
			|  | 905 | +static int ipv4_create_routes ( void ) {
 | 
		
	
		
			
			|  | 906 | +	struct ipv4_miniroute *miniroute;
 | 
		
	
		
			
			|  | 907 | +	struct ipv4_miniroute *tmp;
 | 
		
	
		
			
			|  | 908 | +	int rc;
 | 
		
	
		
			
			|  | 909 | +
 | 
		
	
		
			
			|  | 910 | +	/* Send gratuitous ARPs for any new IPv4 addresses */
 | 
		
	
		
			
			|  | 911 | +	ipv4_settings ( ipv4_gratuitous_arp );
 | 
		
	
		
			
			|  | 912 | +
 | 
		
	
		
			
			|  | 913 | +	/* Delete all existing routes */
 | 
		
	
		
			
			|  | 914 | +	list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list )
 | 
		
	
		
			
			|  | 915 | +		del_ipv4_miniroute ( miniroute );
 | 
		
	
		
			
			|  | 916 | +
 | 
		
	
		
			
			|  | 917 | +	/* Create a route for each configured network device */
 | 
		
	
		
			
			|  | 918 | +	if ( ( rc = ipv4_settings ( add_ipv4_miniroute ) ) != 0 )
 | 
		
	
		
			
			|  | 919 | +		return rc;
 | 
		
	
		
			
			|  | 920 | +
 | 
		
	
		
			
			|  | 921 | +	return 0;
 | 
		
	
		
			
			|  | 922 | +}
 | 
		
	
		
			
			|  | 923 | +
 | 
		
	
		
			
			| 864 | 924 |  /** IPv4 settings applicator */
 | 
		
	
		
			
			| 865 | 925 |  struct settings_applicator ipv4_settings_applicator __settings_applicator = {
 | 
		
	
		
			
			| 866 | 926 |  	.apply = ipv4_create_routes,
 |