Root/package/robocfg/src/robocfg.c

1/*
2 * Broadcom BCM5325E/536x switch configuration utility
3 *
4 * Copyright (C) 2005 Oleg I. Vdovikin
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 */
21 
22#include <errno.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/param.h>
27#include <sys/ioctl.h>
28#include <sys/socket.h>
29
30/* linux stuff */
31typedef u_int64_t u64;
32typedef u_int32_t u32;
33typedef u_int16_t u16;
34typedef u_int8_t u8;
35
36#include <linux/if.h>
37#include <linux/sockios.h>
38#include <linux/ethtool.h>
39#include <linux/mii.h>
40
41#include "etc53xx.h"
42#define ROBO_PHY_ADDR 0x1E /* robo switch phy address */
43
44/* MII registers */
45#define REG_MII_PAGE 0x10 /* MII Page register */
46#define REG_MII_ADDR 0x11 /* MII Address register */
47#define REG_MII_DATA0 0x18 /* MII Data register 0 */
48
49#define REG_MII_PAGE_ENABLE 1
50#define REG_MII_ADDR_WRITE 1
51#define REG_MII_ADDR_READ 2
52
53/* Private et.o ioctls */
54#define SIOCGETCPHYRD (SIOCDEVPRIVATE + 9)
55#define SIOCSETCPHYWR (SIOCDEVPRIVATE + 10)
56
57typedef struct {
58    struct ifreq ifr;
59    int fd;
60    int et; /* use private ioctls */
61} robo_t;
62
63static u16 mdio_read(robo_t *robo, u16 phy_id, u8 reg)
64{
65    if (robo->et) {
66        int args[2] = { reg };
67        
68        if (phy_id != ROBO_PHY_ADDR) {
69            fprintf(stderr,
70                "Access to real 'phy' registers unavaliable.\n"
71                "Upgrade kernel driver.\n");
72
73            return 0xffff;
74        }
75    
76        robo->ifr.ifr_data = (caddr_t) args;
77        if (ioctl(robo->fd, SIOCGETCPHYRD, (caddr_t)&robo->ifr) < 0) {
78            perror("SIOCGETCPHYRD");
79            exit(1);
80        }
81    
82        return args[1];
83    } else {
84        struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo->ifr.ifr_data;
85        mii->phy_id = phy_id;
86        mii->reg_num = reg;
87        if (ioctl(robo->fd, SIOCGMIIREG, &robo->ifr) < 0) {
88            perror("SIOCGMIIREG");
89            exit(1);
90        }
91        return mii->val_out;
92    }
93}
94
95static void mdio_write(robo_t *robo, u16 phy_id, u8 reg, u16 val)
96{
97    if (robo->et) {
98        int args[2] = { reg, val };
99
100        if (phy_id != ROBO_PHY_ADDR) {
101            fprintf(stderr,
102                "Access to real 'phy' registers unavaliable.\n"
103                "Upgrade kernel driver.\n");
104            return;
105        }
106        
107        robo->ifr.ifr_data = (caddr_t) args;
108        if (ioctl(robo->fd, SIOCSETCPHYWR, (caddr_t)&robo->ifr) < 0) {
109            perror("SIOCGETCPHYWR");
110            exit(1);
111        }
112    } else {
113        struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo->ifr.ifr_data;
114        mii->phy_id = phy_id;
115        mii->reg_num = reg;
116        mii->val_in = val;
117        if (ioctl(robo->fd, SIOCSMIIREG, &robo->ifr) < 0) {
118            perror("SIOCSMIIREG");
119            exit(1);
120        }
121    }
122}
123
124static int robo_reg(robo_t *robo, u8 page, u8 reg, u8 op)
125{
126    int i = 3;
127    
128    /* set page number */
129    mdio_write(robo, ROBO_PHY_ADDR, REG_MII_PAGE,
130        (page << 8) | REG_MII_PAGE_ENABLE);
131    
132    /* set register address */
133    mdio_write(robo, ROBO_PHY_ADDR, REG_MII_ADDR,
134        (reg << 8) | op);
135
136    /* check if operation completed */
137    while (i--) {
138        if ((mdio_read(robo, ROBO_PHY_ADDR, REG_MII_ADDR) & 3) == 0)
139            return 0;
140    }
141
142    fprintf(stderr, "robo_reg: timeout\n");
143    exit(1);
144    
145    return 0;
146}
147
148static void robo_read(robo_t *robo, u8 page, u8 reg, u16 *val, int count)
149{
150    int i;
151    
152    robo_reg(robo, page, reg, REG_MII_ADDR_READ);
153    
154    for (i = 0; i < count; i++)
155        val[i] = mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + i);
156}
157
158static u16 robo_read16(robo_t *robo, u8 page, u8 reg)
159{
160    robo_reg(robo, page, reg, REG_MII_ADDR_READ);
161    
162    return mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0);
163}
164
165static u32 robo_read32(robo_t *robo, u8 page, u8 reg)
166{
167    robo_reg(robo, page, reg, REG_MII_ADDR_READ);
168    
169    return mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0) +
170        (mdio_read(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + 1) << 16);
171}
172
173static void robo_write16(robo_t *robo, u8 page, u8 reg, u16 val16)
174{
175    /* write data */
176    mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0, val16);
177
178    robo_reg(robo, page, reg, REG_MII_ADDR_WRITE);
179}
180
181static void robo_write32(robo_t *robo, u8 page, u8 reg, u32 val32)
182{
183    /* write data */
184    mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0, val32 & 65535);
185    mdio_write(robo, ROBO_PHY_ADDR, REG_MII_DATA0 + 1, val32 >> 16);
186    
187    robo_reg(robo, page, reg, REG_MII_ADDR_WRITE);
188}
189
190/* checks that attached switch is 5325E/5350 */
191static int robo_vlan5350(robo_t *robo)
192{
193    /* set vlan access id to 15 and read it back */
194    u16 val16 = 15;
195    robo_write16(robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
196    
197    /* 5365 will refuse this as it does not have this reg */
198    return (robo_read16(robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350) == val16);
199}
200
201u8 port[6] = { 0, 1, 2, 3, 4, 8 };
202char ports[6] = { 'W', '4', '3', '2', '1', 'C' };
203char *rxtx[4] = { "enabled", "rx_disabled", "tx_disabled", "disabled" };
204char *stp[8] = { "none", "disable", "block", "listen", "learn", "forward", "6", "7" };
205
206struct {
207    char *name;
208    u16 bmcr;
209} media[5] = { { "auto", BMCR_ANENABLE | BMCR_ANRESTART },
210    { "10HD", 0 }, { "10FD", BMCR_FULLDPLX },
211    { "100HD", BMCR_SPEED100 }, { "100FD", BMCR_SPEED100 | BMCR_FULLDPLX } };
212
213struct {
214    char *name;
215    u16 value;
216} mdix[3] = { { "auto", 0x0000 }, { "on", 0x1800 }, { "off", 0x0800 } };
217
218void usage()
219{
220    fprintf(stderr, "Broadcom BCM5325E/536x switch configuration utility\n"
221        "Copyright (C) 2005 Oleg I. Vdovikin\n\n"
222        "This program is distributed in the hope that it will be useful,\n"
223        "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
224        "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
225        "GNU General Public License for more details.\n\n");
226
227    fprintf(stderr, "Usage: robocfg <op> ... <op>\n"
228            "Operations are as below:\n"
229            "\tshow\n"
230            "\tswitch <enable|disable>\n"
231            "\tport <port_number> [state <%s|%s|%s|%s>]\n\t\t[stp %s|%s|%s|%s|%s|%s] [tag <vlan_tag>]\n"
232            "\t\t[media %s|%s|%s|%s|%s] [mdi-x %s|%s|%s]\n"
233            "\tvlan <vlan_number> [ports <ports_list>]\n"
234            "\tvlans <enable|disable|reset>\n\n"
235            "\tports_list should be one argument, space separated, quoted if needed,\n"
236            "\tport number could be followed by 't' to leave packet vlan tagged (CPU \n"
237            "\tport default) or by 'u' to untag packet (other ports default) before \n"
238            "\tbringing it to the port, '*' is ignored\n"
239            "\nSamples:\n"
240            "1) ASUS WL-500g Deluxe stock config (eth0 is WAN, eth0.1 is LAN):\n"
241            "robocfg switch disable vlans enable reset vlan 0 ports \"0 5u\" vlan 1 ports \"1 2 3 4 5t\""
242            " port 0 state enabled stp none switch enable\n"
243            "2) WRT54g, WL-500g Deluxe OpenWRT config (vlan0 is LAN, vlan1 is WAN):\n"
244            "robocfg switch disable vlans enable reset vlan 0 ports \"1 2 3 4 5t\" vlan 1 ports \"0 5t\""
245            " port 0 state enabled stp none switch enable\n",
246            rxtx[0], rxtx[1], rxtx[2], rxtx[3], stp[0], stp[1], stp[2], stp[3], stp[4], stp[5],
247            media[0].name, media[1].name, media[2].name, media[3].name, media[4].name,
248            mdix[0].name, mdix[1].name, mdix[2].name);
249}
250
251static robo_t robo;
252int bcm53xx_probe(const char *dev)
253{
254    struct ethtool_drvinfo info;
255    unsigned int phyid;
256    int ret;
257
258    fprintf(stderr, "probing %s\n", dev);
259
260    strcpy(robo.ifr.ifr_name, dev);
261    memset(&info, 0, sizeof(info));
262    info.cmd = ETHTOOL_GDRVINFO;
263    robo.ifr.ifr_data = (caddr_t)&info;
264    ret = ioctl(robo.fd, SIOCETHTOOL, (caddr_t)&robo.ifr);
265    if (ret < 0) {
266        perror("SIOCETHTOOL");
267        return ret;
268    }
269
270    if ( strcmp(info.driver, "et0") &&
271        strcmp(info.driver, "b44") &&
272        strcmp(info.driver, "bcm63xx_enet") ) {
273            fprintf(stderr, "driver not supported %s\n", info.driver);
274            return -ENOSYS;
275    }
276
277    /* try access using MII ioctls - get phy address */
278    robo.et = 0;
279    if (ioctl(robo.fd, SIOCGMIIPHY, &robo.ifr) < 0)
280        robo.et = 1;
281
282    if (robo.et) {
283        unsigned int args[2] = { 2 };
284        
285        robo.ifr.ifr_data = (caddr_t) args;
286        ret = ioctl(robo.fd, SIOCGETCPHYRD, (caddr_t)&robo.ifr);
287        if (ret < 0) {
288            perror("SIOCGETCPHYRD");
289            return ret;
290        }
291        phyid = args[1] & 0xffff;
292    
293        args[0] = 3;
294        robo.ifr.ifr_data = (caddr_t) args;
295        ret = ioctl(robo.fd, SIOCGETCPHYRD, (caddr_t)&robo.ifr);
296        if (ret < 0) {
297            perror("SIOCGETCPHYRD");
298            return ret;
299        }
300        phyid |= args[1] << 16;
301    } else {
302        struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&robo.ifr.ifr_data;
303        mii->phy_id = ROBO_PHY_ADDR;
304        mii->reg_num = 2;
305        ret = ioctl(robo.fd, SIOCGMIIREG, &robo.ifr);
306        if (ret < 0) {
307            perror("SIOCGMIIREG");
308            return ret;
309        }
310        phyid = mii->val_out & 0xffff;
311
312        mii->phy_id = ROBO_PHY_ADDR;
313        mii->reg_num = 3;
314        ret = ioctl(robo.fd, SIOCGMIIREG, &robo.ifr);
315        if (ret < 0) {
316            perror("SIOCGMIIREG");
317            return ret;
318        }
319        phyid |= mii->val_out << 16;
320    }
321
322    if (phyid == 0xffffffff || phyid == 0x55210022) {
323        perror("phyid");
324        return -EIO;
325    }
326    
327    return 0;
328}
329
330int
331main(int argc, char *argv[])
332{
333    u16 val16;
334    u16 mac[3];
335    int i = 0, j;
336    int robo5350 = 0;
337    u32 phyid;
338    
339    if ((robo.fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
340        perror("socket");
341        exit(1);
342    }
343
344    if (bcm53xx_probe("eth1")) {
345        if (bcm53xx_probe("eth0")) {
346            perror("bcm53xx_probe");
347            exit(1);
348        }
349    }
350
351    robo5350 = robo_vlan5350(&robo);
352    
353    for (i = 1; i < argc;) {
354        if (strcasecmp(argv[i], "port") == 0 && (i + 1) < argc)
355        {
356            int index = atoi(argv[++i]);
357            /* read port specs */
358            while (++i < argc) {
359                if (strcasecmp(argv[i], "state") == 0 && ++i < argc) {
360                    for (j = 0; j < 4 && strcasecmp(argv[i], rxtx[j]); j++);
361                    if (j < 4) {
362                        /* change state */
363                        robo_write16(&robo,ROBO_CTRL_PAGE, port[index],
364                            (robo_read16(&robo, ROBO_CTRL_PAGE, port[index]) & ~(3 << 0)) | (j << 0));
365                    } else {
366                        fprintf(stderr, "Invalid state '%s'.\n", argv[i]);
367                        exit(1);
368                    }
369                } else
370                if (strcasecmp(argv[i], "stp") == 0 && ++i < argc) {
371                    for (j = 0; j < 8 && strcasecmp(argv[i], stp[j]); j++);
372                    if (j < 8) {
373                        /* change stp */
374                        robo_write16(&robo,ROBO_CTRL_PAGE, port[index],
375                            (robo_read16(&robo, ROBO_CTRL_PAGE, port[index]) & ~(7 << 5)) | (j << 5));
376                    } else {
377                        fprintf(stderr, "Invalid stp '%s'.\n", argv[i]);
378                        exit(1);
379                    }
380                } else
381                if (strcasecmp(argv[i], "media") == 0 && ++i < argc) {
382                    for (j = 0; j < 5 && strcasecmp(argv[i], media[j].name); j++);
383                    if (j < 5) {
384                                            mdio_write(&robo, port[index], MII_BMCR, media[j].bmcr);
385                    } else {
386                        fprintf(stderr, "Invalid media '%s'.\n", argv[i]);
387                        exit(1);
388                    }
389                } else
390                if (strcasecmp(argv[i], "mdi-x") == 0 && ++i < argc) {
391                    for (j = 0; j < 3 && strcasecmp(argv[i], mdix[j].name); j++);
392                    if (j < 3) {
393                                            mdio_write(&robo, port[index], 0x1c, mdix[j].value |
394                            (mdio_read(&robo, port[index], 0x1c) & ~0x1800));
395                    } else {
396                        fprintf(stderr, "Invalid mdi-x '%s'.\n", argv[i]);
397                        exit(1);
398                    }
399                } else
400                if (strcasecmp(argv[i], "tag") == 0 && ++i < argc) {
401                    j = atoi(argv[i]);
402                    /* change vlan tag */
403                    robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (index << 1), j);
404                } else break;
405            }
406        } else
407        if (strcasecmp(argv[i], "vlan") == 0 && (i + 1) < argc)
408        {
409            int index = atoi(argv[++i]);
410            while (++i < argc) {
411                if (strcasecmp(argv[i], "ports") == 0 && ++i < argc) {
412                    char *ports = argv[i];
413                    int untag = 0;
414                    int member = 0;
415                    
416                    while (*ports >= '0' && *ports <= '9') {
417                        j = *ports++ - '0';
418                        member |= 1 << j;
419                        
420                        /* untag if needed, CPU port requires special handling */
421                        if (*ports == 'u' || (j != 5 && (*ports == ' ' || *ports == 0)))
422                        {
423                            untag |= 1 << j;
424                            if (*ports) ports++;
425                            /* change default vlan tag */
426                            robo_write16(&robo, ROBO_VLAN_PAGE,
427                                ROBO_VLAN_PORT0_DEF_TAG + (j << 1), index);
428                        } else
429                        if (*ports == '*' || *ports == 't' || *ports == ' ') ports++;
430                        else break;
431                        
432                        while (*ports == ' ') ports++;
433                    }
434                    
435                    if (*ports) {
436                        fprintf(stderr, "Invalid ports '%s'.\n", argv[i]);
437                        exit(1);
438                    } else {
439                        /* write config now */
440                        val16 = (index) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
441                        if (robo5350) {
442                            robo_write32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350,
443                                (1 << 20) /* valid */ | (untag << 6) | member);
444                            robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
445                        } else {
446                            robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE,
447                                (1 << 14) /* valid */ | (untag << 7) | member);
448                            robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
449                        }
450                    }
451                } else break;
452            }
453        } else
454        if (strcasecmp(argv[i], "switch") == 0 && (i + 1) < argc)
455        {
456            /* enable/disable switching */
457            robo_write16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE,
458                (robo_read16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & ~2) |
459                (*argv[++i] == 'e' ? 2 : 0));
460            i++;
461        } else
462        if (strcasecmp(argv[i], "vlans") == 0 && (i + 1) < argc)
463        {
464            while (++i < argc) {
465                if (strcasecmp(argv[i], "reset") == 0) {
466                    /* reset vlan validity bit */
467                    for (j = 0; j <= (robo5350 ? VLAN_ID_MAX5350 : VLAN_ID_MAX); j++)
468                    {
469                        /* write config now */
470                        val16 = (j) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */;
471                        if (robo5350) {
472                            robo_write32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, 0);
473                            robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
474                        } else {
475                            robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_WRITE, 0);
476                            robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
477                        }
478                    }
479                } else
480                if (strcasecmp(argv[i], "enable") == 0 || strcasecmp(argv[i], "disable") == 0)
481                {
482                    int disable = (*argv[i] == 'd') || (*argv[i] == 'D');
483                    /* enable/disable vlans */
484                    robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0, disable ? 0 :
485                        (1 << 7) /* 802.1Q VLAN */ | (3 << 5) /* mac check and hash */);
486
487                    robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL1, disable ? 0 :
488                        (1 << 1) | (1 << 2) | (1 << 3) /* RSV multicast */);
489
490                    robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL4, disable ? 0 :
491                        (1 << 6) /* drop invalid VID frames */);
492
493                    robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL5, disable ? 0 :
494                        (1 << 3) /* drop miss V table frames */);
495
496                } else break;
497            }
498        } else
499        if (strcasecmp(argv[i], "show") == 0)
500        {
501            break;
502        } else {
503            fprintf(stderr, "Invalid option %s\n", argv[i]);
504            usage();
505            exit(1);
506        }
507    }
508
509    if (i == argc) {
510        if (argc == 1) usage();
511        return 0;
512    }
513    
514    /* show config */
515        
516    printf("Switch: %sabled\n", robo_read16(&robo, ROBO_CTRL_PAGE, ROBO_SWITCH_MODE) & 2 ? "en" : "dis");
517
518    for (i = 0; i < 6; i++) {
519        printf(robo_read16(&robo, ROBO_STAT_PAGE, ROBO_LINK_STAT_SUMMARY) & (1 << port[i]) ?
520            "Port %d(%c): %s%s " : "Port %d(%c): DOWN ", i, ports[i],
521            robo_read16(&robo, ROBO_STAT_PAGE, ROBO_SPEED_STAT_SUMMARY) & (1 << port[i]) ? "100" : " 10",
522            robo_read16(&robo, ROBO_STAT_PAGE, ROBO_DUPLEX_STAT_SUMMARY) & (1 << port[i]) ? "FD" : "HD");
523        
524        val16 = robo_read16(&robo, ROBO_CTRL_PAGE, port[i]);
525        
526        printf("%s stp: %s vlan: %d ", rxtx[val16 & 3], stp[(val16 >> 5) & 7],
527            robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (i << 1)));
528            
529        robo_read(&robo, ROBO_STAT_PAGE, ROBO_LSA_PORT0 + port[i] * 6, mac, 3);
530        
531        printf("mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
532            mac[2] >> 8, mac[2] & 255, mac[1] >> 8, mac[1] & 255, mac[0] >> 8, mac[0] & 255);
533    }
534    
535    val16 = robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_CTRL0);
536    
537    printf("VLANs: %s %sabled%s%s\n",
538        robo5350 ? "BCM5325/535x" : "BCM536x",
539        (val16 & (1 << 7)) ? "en" : "dis",
540        (val16 & (1 << 6)) ? " mac_check" : "",
541        (val16 & (1 << 5)) ? " mac_hash" : "");
542    
543    /* scan VLANs */
544    for (i = 0; i <= (robo5350 ? VLAN_ID_MAX5350 : VLAN_ID_MAX); i++) {
545        /* issue read */
546        val16 = (i) /* vlan */ | (0 << 12) /* read */ | (1 << 13) /* enable */;
547        
548        if (robo5350) {
549            u32 val32;
550            robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);
551            /* actual read */
552            val32 = robo_read32(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_READ);
553            if ((val32 & (1 << 20)) /* valid */) {
554                printf("vlan%d:", i);
555                for (j = 0; j < 6; j++) {
556                    if (val32 & (1 << j)) {
557                        printf(" %d%s", j, (val32 & (1 << (j + 6))) ?
558                            (j == 5 ? "u" : "") : "t");
559                    }
560                }
561                printf("\n");
562            }
563        } else {
564            robo_write16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);
565            /* actual read */
566            val16 = robo_read16(&robo, ROBO_VLAN_PAGE, ROBO_VLAN_READ);
567            if ((val16 & (1 << 14)) /* valid */) {
568                printf("vlan%d:", i);
569                for (j = 0; j < 6; j++) {
570                    if (val16 & (1 << j)) {
571                        printf(" %d%s", j, (val16 & (1 << (j + 7))) ?
572                            (j == 5 ? "u" : "") : "t");
573                    }
574                }
575                printf("\n");
576            }
577        }
578    }
579    
580    return (0);
581}
582

Archive Download this file



interactive