summaryrefslogtreecommitdiffstats
path: root/cpukit/libnetworking/rtems/rtems_mii_ioctl.c
blob: fa6261459a378fd316e85d12c9943ab4ff8356eb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* $Id$ */

/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA
 * to be used by ethernet drivers [from their ioctl].
 *
 * USERSPACE UTILITIES
 *
 * NOTE: This much simpler than the BSD ifmedia API 
 */

/* Author: Till Straumann, <straumanatslacdotstandorddotedu>, 2005 */

#include <rtems.h>
#include <inttypes.h>

#undef _KERNEL
#undef KERNEL

#include <rtems/rtems_mii_ioctl.h>

#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

static struct ifmedia_description shared_media_strings[] =
  IFM_SUBTYPE_SHARED_DESCRIPTIONS;
static struct ifmedia_description ethern_media_strings[] =
  IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
static struct ifmedia_description eth_al_media_strings[] =
  IFM_SUBTYPE_ETHERNET_ALIASES;

static const char *
find_desc (int tag, struct ifmedia_description *list)
{
  while (list->ifmt_string && tag != list->ifmt_word)
    list++;
  return list->ifmt_string;
}

#define WHATPRINT(buf,sz,fmt...)	\
	( (sz) > 0 ? snprintf((buf),(sz),fmt) : fprintf((buf) ? (FILE*)(buf) : stdout, fmt) )

int
rtems_ifmedia2str (int media, char *buf, int bufsz)
{
  const char *mdesc;
  const char *dupdesc = 0;

  /* only ethernet supported, so far */
  if (IFM_ETHER != IFM_TYPE (media))
    return -1;

  if (!(mdesc = find_desc (IFM_SUBTYPE (media), shared_media_strings)))
    mdesc = find_desc (IFM_SUBTYPE (media), ethern_media_strings);

  if (!mdesc)
    return -1;

  if (IFM_NONE != IFM_SUBTYPE (media))
    dupdesc = IFM_FDX & media ? " full-duplex" : " half-duplex";

  return WHATPRINT (buf, bufsz,
                    "Ethernet [phy instance: %" PRId32 "]: (link %s, autoneg %s) -- media: %s%s",
                    (int32_t) IFM_INST (media),
                    IFM_LINK_OK & media ? "ok" : "down",
                    IFM_ANEG_DIS & media ? "off" : "on",
                    mdesc, dupdesc ? dupdesc : "");
}

static int
find_tag (const char *desc, struct ifmedia_description *list)
{
  while (list->ifmt_string) {
    if (strstr (desc, list->ifmt_string))
      return list->ifmt_word;
    list++;
  }
  return -1;
}


/* convert a string to a media word
 * RETURNS: 0 on failure; valid results have always at least IFM_ETHER set
 */
int
rtems_str2ifmedia (const char *str, int phy)
{
  int sub, opt = 0;
  char *chpt;

  if (!strncmp (str, "auto", 4)) {
    sub = IFM_AUTO;
  } else if ((sub = find_tag (str, ethern_media_strings)) < 0) {
    if ((sub = find_tag (str, eth_al_media_strings)) < 0) {
      /* allow more */

      /* if no number, 0 is returned which will not pass the test */
      switch (strtol (str, &chpt, 10)) {
      case 10:
        sub = IFM_10_T;
        break;
      case 100:
        sub = IFM_100_TX;
        break;
      case 1000:
        sub = IFM_1000_T;
        break;
      default:
        return 0;
      }

      /* need 'b' or 'base' */
      if ('b' != *chpt++)
        return 0;
      if (!strncmp (chpt, "ase", 3))
        chpt += 3;
      if (toupper (*chpt++) != 'T')
        return 0;
      if (IFM_100_TX == sub && toupper (*chpt++) != 'X')
        return 0;
    }
  }

  if (strstr (str, "full") || strstr (str, "FDX") || strstr (str, "fdx"))
    opt |= IFM_FDX;

  return IFM_MAKEWORD (IFM_ETHER, sub, opt, phy);
}