1 /* $NetBSD: ofw_network_subr.c,v 1.5 2008/04/28 20:23:54 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: ofw_network_subr.c,v 1.5 2008/04/28 20:23:54 martin Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/malloc.h> 39 #include <sys/socket.h> 40 41 #include <net/if.h> 42 #include <net/if_media.h> 43 44 #include <dev/ofw/openfirm.h> 45 46 #define OFW_MAX_STACK_BUF_SIZE 256 47 #define OFW_PATH_BUF_SIZE 512 48 49 struct table_entry { 50 const char *t_string; 51 int t_value; 52 }; 53 54 int of_network_parse_network_type(const char *); 55 56 /* 57 * int of_network_decode_media(phandle, nmediap, defmediap) 58 * 59 * This routine decodes the OFW properties `supported-network-types' 60 * and `chosen-network-type'. 61 * 62 * Arguments: 63 * phandle OFW phandle of device whos network media properties 64 * are to be decoded. 65 * nmediap Pointer to an integer which will be initialized 66 * with the number of returned media words. 67 * defmediap Pointer to an integer which will be initialized 68 * with the default network media. 69 * 70 * Return Values: 71 * An array of integers, allocated with malloc(), containing the 72 * decoded media values. The number of elements in the array will 73 * be stored in the location pointed to by the `nmediap' argument. 74 * The default media will be stored in the location pointed to by 75 * the `defmediap' argument. 76 * 77 * Side Effects: 78 * None. 79 */ 80 int * 81 of_network_decode_media(phandle, nmediap, defmediap) 82 int phandle, *nmediap, *defmediap; 83 { 84 int i, len, count, med, *rv = NULL; 85 char *buf = NULL, *cp, *ncp; 86 87 len = OF_getproplen(phandle, "supported-network-types"); 88 if (len <= 0) 89 return (NULL); 90 91 buf = malloc(len, M_TEMP, M_WAITOK); 92 93 /* `supported-network-types' should not change. */ 94 if (OF_getprop(phandle, "supported-network-types", buf, len) != len) 95 goto bad; 96 97 /* 98 * Count the number of entries in the array. This is kind of tricky, 99 * because they're variable-length strings, yuck. 100 */ 101 for (count = 0, cp = buf; cp <= (buf + len); cp++) { 102 /* 103 * If we encounter nul, that marks the end of a string, 104 * and thus one complete media description. 105 */ 106 if (*cp == '\0') 107 count++; 108 } 109 110 /* Sanity. */ 111 if (count == 0) 112 goto bad; 113 114 /* Allocate the return value array. */ 115 rv = malloc(count * sizeof(int), M_DEVBUF, M_WAITOK); 116 117 /* 118 * Parse each media string. If we get -1 back from the parser, 119 * back off the count by one, to skip the bad entry. 120 */ 121 for (i = 0, cp = buf; cp <= (buf + len) && i < count; ) { 122 /* 123 * Find the next string now, as we may chop 124 * the current one up in the parser. 125 */ 126 for (ncp = cp; *ncp != '\0'; ncp++) 127 /* ...skip to the nul... */ ; 128 ncp++; /* ...and now past it. */ 129 130 med = of_network_parse_network_type(cp); 131 if (med == -1) 132 count--; 133 else { 134 rv[i] = med; 135 i++; 136 } 137 cp = ncp; 138 } 139 140 /* Sanity... */ 141 if (count == 0) 142 goto bad; 143 144 /* 145 * We now have the `supported-media-types' property decoded. 146 * Next step is to decode the `chosen-media-type' property, 147 * if it exists. 148 */ 149 free(buf, M_TEMP); 150 buf = NULL; 151 len = OF_getproplen(phandle, "chosen-network-type"); 152 if (len <= 0) { 153 /* Property does not exist. */ 154 *defmediap = -1; 155 goto done; 156 } 157 158 buf = malloc(len, M_TEMP, M_WAITOK); 159 if (OF_getprop(phandle, "chosen-network-type", buf, len) != len) { 160 /* Something went wrong... */ 161 *defmediap = -1; 162 goto done; 163 } 164 165 *defmediap = of_network_parse_network_type(buf); 166 167 done: 168 if (buf != NULL) 169 free(buf, M_TEMP); 170 *nmediap = count; 171 return (rv); 172 173 bad: 174 if (rv != NULL) 175 free(rv, M_DEVBUF); 176 if (buf != NULL) 177 free(buf, M_TEMP); 178 return (NULL); 179 } 180 181 int 182 of_network_parse_network_type(cp) 183 const char *cp; 184 { 185 /* 186 * We could tokenize this, but that would be a pain in 187 * the neck given how the media are described. If this 188 * table grows any larger, we may want to consider doing 189 * that. 190 * 191 * Oh yes, we also only support combinations that actually 192 * make sense. 193 */ 194 static const struct table_entry mediatab[] = { 195 { "ethernet,10,rj45,half", 196 IFM_ETHER|IFM_10_T }, 197 { "ethernet,10,rj45,full", 198 IFM_ETHER|IFM_10_T|IFM_FDX }, 199 { "ethernet,10,aui,half", 200 IFM_ETHER|IFM_10_5, }, 201 { "ethernet,10,bnc,half", 202 IFM_ETHER|IFM_10_2, }, 203 { "ethernet,100,rj45,half", 204 IFM_ETHER|IFM_100_TX }, 205 { "ethernet,100,rj45,full", 206 IFM_ETHER|IFM_100_TX|IFM_FDX }, 207 { NULL, -1 }, 208 }; 209 int i; 210 211 for (i = 0; mediatab[i].t_string != NULL; i++) { 212 if (strcmp(cp, mediatab[i].t_string) == 0) 213 return (mediatab[i].t_value); 214 } 215 216 /* Not found. */ 217 return (-1); 218 } 219