iPXE
netdev_settings.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <string.h>
00027 #include <errno.h>
00028 #include <byteswap.h>
00029 #include <ipxe/dhcp.h>
00030 #include <ipxe/dhcpopts.h>
00031 #include <ipxe/settings.h>
00032 #include <ipxe/device.h>
00033 #include <ipxe/netdevice.h>
00034 #include <ipxe/init.h>
00035 
00036 /** @file
00037  *
00038  * Network device configuration settings
00039  *
00040  */
00041 
00042 /** Network device predefined settings */
00043 const struct setting mac_setting __setting ( SETTING_NETDEV, mac ) = {
00044         .name = "mac",
00045         .description = "MAC address",
00046         .type = &setting_type_hex,
00047 };
00048 const struct setting hwaddr_setting __setting ( SETTING_NETDEV, hwaddr ) = {
00049         .name = "hwaddr",
00050         .description = "Hardware address",
00051         .type = &setting_type_hex,
00052 };
00053 const struct setting bustype_setting __setting ( SETTING_NETDEV, bustype ) = {
00054         .name = "bustype",
00055         .description = "Bus type",
00056         .type = &setting_type_string,
00057 };
00058 const struct setting busloc_setting __setting ( SETTING_NETDEV, busloc ) = {
00059         .name = "busloc",
00060         .description = "Bus location",
00061         .type = &setting_type_uint32,
00062 };
00063 const struct setting busid_setting __setting ( SETTING_NETDEV, busid ) = {
00064         .name = "busid",
00065         .description = "Bus ID",
00066         .type = &setting_type_hex,
00067 };
00068 const struct setting chip_setting __setting ( SETTING_NETDEV, chip ) = {
00069         .name = "chip",
00070         .description = "Chip",
00071         .type = &setting_type_string,
00072 };
00073 const struct setting ifname_setting __setting ( SETTING_NETDEV, ifname ) = {
00074         .name = "ifname",
00075         .description = "Interface name",
00076         .type = &setting_type_string,
00077 };
00078 const struct setting mtu_setting __setting ( SETTING_NETDEV, mtu ) = {
00079         .name = "mtu",
00080         .description = "MTU",
00081         .type = &setting_type_int16,
00082         .tag = DHCP_MTU,
00083 };
00084 
00085 /**
00086  * Store link-layer address setting
00087  *
00088  * @v netdev            Network device
00089  * @v data              Setting data, or NULL to clear setting
00090  * @v len               Length of setting data
00091  * @ret rc              Return status code
00092  */
00093 static int netdev_store_mac ( struct net_device *netdev,
00094                               const void *data, size_t len ) {
00095         struct ll_protocol *ll_protocol = netdev->ll_protocol;
00096 
00097         /* Record new MAC address */
00098         if ( data ) {
00099                 if ( len != netdev->ll_protocol->ll_addr_len )
00100                         return -EINVAL;
00101                 memcpy ( netdev->ll_addr, data, len );
00102         } else {
00103                 /* Reset MAC address if clearing setting */
00104                 ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
00105         }
00106 
00107         return 0;
00108 }
00109 
00110 /**
00111  * Fetch link-layer address setting
00112  *
00113  * @v netdev            Network device
00114  * @v data              Buffer to fill with setting data
00115  * @v len               Length of buffer
00116  * @ret len             Length of setting data, or negative error
00117  */
00118 static int netdev_fetch_mac ( struct net_device *netdev, void *data,
00119                               size_t len ) {
00120         size_t max_len = netdev->ll_protocol->ll_addr_len;
00121 
00122         if ( len > max_len )
00123                 len = max_len;
00124         memcpy ( data, netdev->ll_addr, len );
00125         return max_len;
00126 }
00127 
00128 /**
00129  * Fetch hardware address setting
00130  *
00131  * @v netdev            Network device
00132  * @v data              Buffer to fill with setting data
00133  * @v len               Length of buffer
00134  * @ret len             Length of setting data, or negative error
00135  */
00136 static int netdev_fetch_hwaddr ( struct net_device *netdev, void *data,
00137                                  size_t len ) {
00138         size_t max_len = netdev->ll_protocol->hw_addr_len;
00139 
00140         if ( len > max_len )
00141                 len = max_len;
00142         memcpy ( data, netdev->hw_addr, len );
00143         return max_len;
00144 }
00145 
00146 /**
00147  * Fetch bus type setting
00148  *
00149  * @v netdev            Network device
00150  * @v data              Buffer to fill with setting data
00151  * @v len               Length of buffer
00152  * @ret len             Length of setting data, or negative error
00153  */
00154 static int netdev_fetch_bustype ( struct net_device *netdev, void *data,
00155                                   size_t len ) {
00156         static const char *bustypes[] = {
00157                 [BUS_TYPE_PCI] = "PCI",
00158                 [BUS_TYPE_ISAPNP] = "ISAPNP",
00159                 [BUS_TYPE_EISA] = "EISA",
00160                 [BUS_TYPE_MCA] = "MCA",
00161                 [BUS_TYPE_ISA] = "ISA",
00162                 [BUS_TYPE_TAP] = "TAP",
00163                 [BUS_TYPE_EFI] = "EFI",
00164                 [BUS_TYPE_XEN] = "XEN",
00165                 [BUS_TYPE_HV] = "HV",
00166                 [BUS_TYPE_USB] = "USB",
00167         };
00168         struct device_description *desc = &netdev->dev->desc;
00169         const char *bustype;
00170 
00171         assert ( desc->bus_type < ( sizeof ( bustypes ) /
00172                                     sizeof ( bustypes[0] ) ) );
00173         bustype = bustypes[desc->bus_type];
00174         if ( ! bustype )
00175                 return -ENOENT;
00176         strncpy ( data, bustype, len );
00177         return strlen ( bustype );
00178 }
00179 
00180 /**
00181  * Fetch bus location setting
00182  *
00183  * @v netdev            Network device
00184  * @v data              Buffer to fill with setting data
00185  * @v len               Length of buffer
00186  * @ret len             Length of setting data, or negative error
00187  */
00188 static int netdev_fetch_busloc ( struct net_device *netdev, void *data,
00189                                  size_t len ) {
00190         struct device_description *desc = &netdev->dev->desc;
00191         uint32_t busloc;
00192 
00193         busloc = cpu_to_be32 ( desc->location );
00194         if ( len > sizeof ( busloc ) )
00195                 len = sizeof ( busloc );
00196         memcpy ( data, &busloc, len );
00197         return sizeof ( busloc );
00198 }
00199 
00200 /**
00201  * Fetch bus ID setting
00202  *
00203  * @v netdev            Network device
00204  * @v data              Buffer to fill with setting data
00205  * @v len               Length of buffer
00206  * @ret len             Length of setting data, or negative error
00207  */
00208 static int netdev_fetch_busid ( struct net_device *netdev, void *data,
00209                                 size_t len ) {
00210         struct device_description *desc = &netdev->dev->desc;
00211         struct dhcp_netdev_desc dhcp_desc;
00212 
00213         dhcp_desc.type = desc->bus_type;
00214         dhcp_desc.vendor = htons ( desc->vendor );
00215         dhcp_desc.device = htons ( desc->device );
00216         if ( len > sizeof ( dhcp_desc ) )
00217                 len = sizeof ( dhcp_desc );
00218         memcpy ( data, &dhcp_desc, len );
00219         return sizeof ( dhcp_desc );
00220 }
00221 
00222 /**
00223  * Fetch chip setting
00224  *
00225  * @v netdev            Network device
00226  * @v data              Buffer to fill with setting data
00227  * @v len               Length of buffer
00228  * @ret len             Length of setting data, or negative error
00229  */
00230 static int netdev_fetch_chip ( struct net_device *netdev, void *data,
00231                                size_t len ) {
00232         const char *chip = netdev->dev->driver_name;
00233 
00234         strncpy ( data, chip, len );
00235         return strlen ( chip );
00236 }
00237 
00238 /**
00239  * Fetch ifname setting
00240  *
00241  * @v netdev            Network device
00242  * @v data              Buffer to fill with setting data
00243  * @v len               Length of buffer
00244  * @ret len             Length of setting data, or negative error
00245  */
00246 static int netdev_fetch_ifname ( struct net_device *netdev, void *data,
00247                                  size_t len ) {
00248         const char *ifname = netdev->name;
00249 
00250         strncpy ( data, ifname, len );
00251         return strlen ( ifname );
00252 }
00253 
00254 /** A network device setting operation */
00255 struct netdev_setting_operation {
00256         /** Setting */
00257         const struct setting *setting;
00258         /** Store setting (or NULL if not supported)
00259          *
00260          * @v netdev            Network device
00261          * @v data              Setting data, or NULL to clear setting
00262          * @v len               Length of setting data
00263          * @ret rc              Return status code
00264          */
00265         int ( * store ) ( struct net_device *netdev, const void *data,
00266                           size_t len );
00267         /** Fetch setting
00268          *
00269          * @v netdev            Network device
00270          * @v data              Buffer to fill with setting data
00271          * @v len               Length of buffer
00272          * @ret len             Length of setting data, or negative error
00273          */
00274         int ( * fetch ) ( struct net_device *netdev, void *data, size_t len );
00275 };
00276 
00277 /** Network device settings */
00278 static struct netdev_setting_operation netdev_setting_operations[] = {
00279         { &mac_setting, netdev_store_mac, netdev_fetch_mac },
00280         { &hwaddr_setting, NULL, netdev_fetch_hwaddr },
00281         { &bustype_setting, NULL, netdev_fetch_bustype },
00282         { &busloc_setting, NULL, netdev_fetch_busloc },
00283         { &busid_setting, NULL, netdev_fetch_busid },
00284         { &chip_setting, NULL, netdev_fetch_chip },
00285         { &ifname_setting, NULL, netdev_fetch_ifname },
00286 };
00287 
00288 /**
00289  * Store value of network device setting
00290  *
00291  * @v settings          Settings block
00292  * @v setting           Setting to store
00293  * @v data              Setting data, or NULL to clear setting
00294  * @v len               Length of setting data
00295  * @ret rc              Return status code
00296  */
00297 static int netdev_store ( struct settings *settings,
00298                           const struct setting *setting,
00299                           const void *data, size_t len ) {
00300         struct net_device *netdev = container_of ( settings, struct net_device,
00301                                                    settings.settings );
00302         struct netdev_setting_operation *op;
00303         unsigned int i;
00304 
00305         /* Handle network device-specific settings */
00306         for ( i = 0 ; i < ( sizeof ( netdev_setting_operations ) /
00307                             sizeof ( netdev_setting_operations[0] ) ) ; i++ ) {
00308                 op = &netdev_setting_operations[i];
00309                 if ( setting_cmp ( setting, op->setting ) == 0 ) {
00310                         if ( op->store ) {
00311                                 return op->store ( netdev, data, len );
00312                         } else {
00313                                 return -ENOTSUP;
00314                         }
00315                 }
00316         }
00317 
00318         return generic_settings_store ( settings, setting, data, len );
00319 }
00320 
00321 /**
00322  * Fetch value of network device setting
00323  *
00324  * @v settings          Settings block
00325  * @v setting           Setting to fetch
00326  * @v data              Buffer to fill with setting data
00327  * @v len               Length of buffer
00328  * @ret len             Length of setting data, or negative error
00329  */
00330 static int netdev_fetch ( struct settings *settings, struct setting *setting,
00331                           void *data, size_t len ) {
00332         struct net_device *netdev = container_of ( settings, struct net_device,
00333                                                    settings.settings );
00334         struct netdev_setting_operation *op;
00335         unsigned int i;
00336 
00337         /* Handle network device-specific settings */
00338         for ( i = 0 ; i < ( sizeof ( netdev_setting_operations ) /
00339                             sizeof ( netdev_setting_operations[0] ) ) ; i++ ) {
00340                 op = &netdev_setting_operations[i];
00341                 if ( setting_cmp ( setting, op->setting ) == 0 )
00342                         return op->fetch ( netdev, data, len );
00343         }
00344 
00345         return generic_settings_fetch ( settings, setting, data, len );
00346 }
00347 
00348 /**
00349  * Clear network device settings
00350  *
00351  * @v settings          Settings block
00352  */
00353 static void netdev_clear ( struct settings *settings ) {
00354         generic_settings_clear ( settings );
00355 }
00356 
00357 /** Network device configuration settings operations */
00358 struct settings_operations netdev_settings_operations = {
00359         .store = netdev_store,
00360         .fetch = netdev_fetch,
00361         .clear = netdev_clear,
00362 };
00363 
00364 /**
00365  * Redirect "netX" settings block
00366  *
00367  * @v settings          Settings block
00368  * @ret settings        Underlying settings block
00369  */
00370 static struct settings * netdev_redirect ( struct settings *settings ) {
00371         struct net_device *netdev;
00372 
00373         /* Redirect to most recently opened network device */
00374         netdev = last_opened_netdev();
00375         if ( netdev ) {
00376                 return netdev_settings ( netdev );
00377         } else {
00378                 return settings;
00379         }
00380 }
00381 
00382 /** "netX" settings operations */
00383 static struct settings_operations netdev_redirect_settings_operations = {
00384         .redirect = netdev_redirect,
00385 };
00386 
00387 /** "netX" settings */
00388 static struct settings netdev_redirect_settings = {
00389         .refcnt = NULL,
00390         .siblings = LIST_HEAD_INIT ( netdev_redirect_settings.siblings ),
00391         .children = LIST_HEAD_INIT ( netdev_redirect_settings.children ),
00392         .op = &netdev_redirect_settings_operations,
00393 };
00394 
00395 /** Initialise "netX" settings */
00396 static void netdev_redirect_settings_init ( void ) {
00397         int rc;
00398 
00399         if ( ( rc = register_settings ( &netdev_redirect_settings, NULL,
00400                                         "netX" ) ) != 0 ) {
00401                 DBG ( "Could not register netX settings: %s\n",
00402                       strerror ( rc ) );
00403                 return;
00404         }
00405 }
00406 
00407 /** "netX" settings initialiser */
00408 struct init_fn netdev_redirect_settings_init_fn __init_fn ( INIT_LATE ) = {
00409         .initialise = netdev_redirect_settings_init,
00410 };
00411 
00412 /**
00413  * Apply network device settings
00414  *
00415  * @ret rc              Return status code
00416  */
00417 static int apply_netdev_settings ( void ) {
00418         struct net_device *netdev;
00419         struct settings *settings;
00420         struct ll_protocol *ll_protocol;
00421         size_t max_mtu;
00422         size_t old_mtu;
00423         size_t mtu;
00424         int rc;
00425 
00426         /* Process settings for each network device */
00427         for_each_netdev ( netdev ) {
00428 
00429                 /* Get network device settings */
00430                 settings = netdev_settings ( netdev );
00431 
00432                 /* Get MTU */
00433                 mtu = fetch_uintz_setting ( settings, &mtu_setting );
00434 
00435                 /* Do nothing unless MTU is specified */
00436                 if ( ! mtu )
00437                         continue;
00438 
00439                 /* Limit MTU to maximum supported by hardware */
00440                 ll_protocol = netdev->ll_protocol;
00441                 max_mtu = ( netdev->max_pkt_len - ll_protocol->ll_header_len );
00442                 if ( mtu > max_mtu ) {
00443                         DBGC ( netdev, "NETDEV %s cannot support MTU %zd (max "
00444                                "%zd)\n", netdev->name, mtu, max_mtu );
00445                         mtu = max_mtu;
00446                 }
00447 
00448                 /* Update maximum packet length */
00449                 old_mtu = netdev->mtu;
00450                 netdev->mtu = mtu;
00451                 if ( mtu != old_mtu ) {
00452                         DBGC ( netdev, "NETDEV %s MTU is %zd\n",
00453                                netdev->name, mtu );
00454                 }
00455 
00456                 /* Close and reopen network device if MTU has increased */
00457                 if ( netdev_is_open ( netdev ) && ( mtu > old_mtu ) ) {
00458                         netdev_close ( netdev );
00459                         if ( ( rc = netdev_open ( netdev ) ) != 0 ) {
00460                                 DBGC ( netdev, "NETDEV %s could not reopen: "
00461                                        "%s\n", netdev->name, strerror ( rc ) );
00462                                 return rc;
00463                         }
00464                 }
00465         }
00466 
00467         return 0;
00468 }
00469 
00470 /** Network device settings applicator */
00471 struct settings_applicator netdev_applicator __settings_applicator = {
00472         .apply = apply_netdev_settings,
00473 };