summaryrefslogtreecommitdiffstats
path: root/cpukit/libnetworking/rtems/rtems_mii_ioctl.c
blob: 5ee8186f056263b91a96150ad828432f1cc84dd0 (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
/* $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>

#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: %i]: (link %s, autoneg %s) -- media: %s%s",
                    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);
}