NetBSD/sys/dev/ofw/ofw_network_subr.c

217 lines
5.9 KiB
C

/* $NetBSD: ofw_network_subr.c,v 1.7 2009/03/14 21:04:21 dsl Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ofw_network_subr.c,v 1.7 2009/03/14 21:04:21 dsl Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_media.h>
#include <dev/ofw/openfirm.h>
#define OFW_MAX_STACK_BUF_SIZE 256
#define OFW_PATH_BUF_SIZE 512
struct table_entry {
const char *t_string;
int t_value;
};
int of_network_parse_network_type(const char *);
/*
* int of_network_decode_media(phandle, nmediap, defmediap)
*
* This routine decodes the OFW properties `supported-network-types'
* and `chosen-network-type'.
*
* Arguments:
* phandle OFW phandle of device whos network media properties
* are to be decoded.
* nmediap Pointer to an integer which will be initialized
* with the number of returned media words.
* defmediap Pointer to an integer which will be initialized
* with the default network media.
*
* Return Values:
* An array of integers, allocated with malloc(), containing the
* decoded media values. The number of elements in the array will
* be stored in the location pointed to by the `nmediap' argument.
* The default media will be stored in the location pointed to by
* the `defmediap' argument.
*
* Side Effects:
* None.
*/
int *
of_network_decode_media(int phandle, int *nmediap, int *defmediap)
{
int i, len, count, med, *rv = NULL;
char *buf = NULL, *cp, *ncp;
len = OF_getproplen(phandle, "supported-network-types");
if (len <= 0)
return (NULL);
buf = malloc(len, M_TEMP, M_WAITOK);
/* `supported-network-types' should not change. */
if (OF_getprop(phandle, "supported-network-types", buf, len) != len)
goto bad;
/*
* Count the number of entries in the array. This is kind of tricky,
* because they're variable-length strings, yuck.
*/
for (count = 0, cp = buf; cp <= (buf + len); cp++) {
/*
* If we encounter nul, that marks the end of a string,
* and thus one complete media description.
*/
if (*cp == '\0')
count++;
}
/* Sanity. */
if (count == 0)
goto bad;
/* Allocate the return value array. */
rv = malloc(count * sizeof(int), M_DEVBUF, M_WAITOK);
/*
* Parse each media string. If we get -1 back from the parser,
* back off the count by one, to skip the bad entry.
*/
for (i = 0, cp = buf; cp <= (buf + len) && i < count; ) {
/*
* Find the next string now, as we may chop
* the current one up in the parser.
*/
for (ncp = cp; *ncp != '\0'; ncp++)
/* ...skip to the nul... */ ;
ncp++; /* ...and now past it. */
med = of_network_parse_network_type(cp);
if (med == -1)
count--;
else {
rv[i] = med;
i++;
}
cp = ncp;
}
/* Sanity... */
if (count == 0)
goto bad;
/*
* We now have the `supported-media-types' property decoded.
* Next step is to decode the `chosen-media-type' property,
* if it exists.
*/
free(buf, M_TEMP);
buf = NULL;
len = OF_getproplen(phandle, "chosen-network-type");
if (len <= 0) {
/* Property does not exist. */
*defmediap = -1;
goto done;
}
buf = malloc(len, M_TEMP, M_WAITOK);
if (OF_getprop(phandle, "chosen-network-type", buf, len) != len) {
/* Something went wrong... */
*defmediap = -1;
goto done;
}
*defmediap = of_network_parse_network_type(buf);
done:
if (buf != NULL)
free(buf, M_TEMP);
*nmediap = count;
return (rv);
bad:
if (rv != NULL)
free(rv, M_DEVBUF);
if (buf != NULL)
free(buf, M_TEMP);
return (NULL);
}
int
of_network_parse_network_type(const char *cp)
{
/*
* We could tokenize this, but that would be a pain in
* the neck given how the media are described. If this
* table grows any larger, we may want to consider doing
* that.
*
* Oh yes, we also only support combinations that actually
* make sense.
*/
static const struct table_entry mediatab[] = {
{ "ethernet,10,rj45,half",
IFM_ETHER|IFM_10_T },
{ "ethernet,10,rj45,full",
IFM_ETHER|IFM_10_T|IFM_FDX },
{ "ethernet,10,aui,half",
IFM_ETHER|IFM_10_5, },
{ "ethernet,10,bnc,half",
IFM_ETHER|IFM_10_2, },
{ "ethernet,100,rj45,half",
IFM_ETHER|IFM_100_TX },
{ "ethernet,100,rj45,full",
IFM_ETHER|IFM_100_TX|IFM_FDX },
{ NULL, -1 },
};
int i;
for (i = 0; mediatab[i].t_string != NULL; i++) {
if (strcmp(cp, mediatab[i].t_string) == 0)
return (mediatab[i].t_value);
}
/* Not found. */
return (-1);
}