1 /* $OpenBSD: if.c,v 1.8 2006/11/28 19:21:15 reyk Exp $ */ 2 /* 3 * Copyright (c) 2004 Markus Friedl <markus@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #include <sys/param.h> 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <sys/sysctl.h> 21 #include <net/if.h> 22 #include <net/if_dl.h> 23 #include <net/route.h> 24 25 #include <stdlib.h> 26 #include <string.h> 27 28 #include "systat.h" 29 #include "extern.h" 30 31 static enum state { BOOT, TIME, RUN } state = TIME; 32 33 struct ifcount { 34 u_long ifc_ib; /* input bytes */ 35 u_long ifc_ip; /* input packets */ 36 u_long ifc_ie; /* input errors */ 37 u_long ifc_ob; /* output bytes */ 38 u_long ifc_op; /* output packets */ 39 u_long ifc_oe; /* output errors */ 40 u_long ifc_co; /* collisions */ 41 int ifc_flags; /* up / down */ 42 int ifc_state; /* link state */ 43 } sum; 44 45 struct ifstat { 46 char ifs_name[IFNAMSIZ]; /* interface name */ 47 struct ifcount ifs_cur; 48 struct ifcount ifs_old; 49 struct ifcount ifs_now; 50 } *ifstats; 51 52 static int nifs = 0; 53 extern u_int naptime; 54 55 const char *showlinkstate(int); 56 57 WINDOW * 58 openifstat(void) 59 { 60 61 return (subwin(stdscr, LINES-5-1, 0, 5, 0)); 62 } 63 64 void 65 closeifstat(WINDOW *w) 66 { 67 68 if (w == NULL) 69 return; 70 wclear(w); 71 wrefresh(w); 72 delwin(w); 73 } 74 75 int 76 initifstat(void) 77 { 78 79 fetchifstat(); 80 return(1); 81 } 82 83 #define UPDATE(x, y) do { \ 84 ifs->ifs_now.x = ifm.y; \ 85 ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \ 86 if (state == TIME) {\ 87 ifs->ifs_old.x = ifs->ifs_now.x; \ 88 ifs->ifs_cur.x /= naptime; \ 89 } \ 90 sum.x += ifs->ifs_cur.x; \ 91 } while(0) 92 93 94 void 95 rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info) 96 { 97 int i; 98 99 for (i = 0; i < RTAX_MAX; i++) { 100 if (addrs & (1 << i)) { 101 info[i] = sa; 102 sa = (struct sockaddr *) ((char *)(sa) + 103 roundup(sa->sa_len, sizeof(long))); 104 } else 105 info[i] = NULL; 106 } 107 } 108 109 void 110 fetchifstat(void) 111 { 112 struct ifstat *newstats, *ifs; 113 struct if_msghdr ifm; 114 struct sockaddr *info[RTAX_MAX]; 115 struct sockaddr_dl *sdl; 116 char *buf, *next, *lim; 117 int mib[6]; 118 size_t need; 119 120 mib[0] = CTL_NET; 121 mib[1] = AF_ROUTE; 122 mib[2] = 0; 123 mib[3] = 0; 124 mib[4] = NET_RT_IFLIST; 125 mib[5] = 0; 126 127 if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1) 128 return; 129 if ((buf = malloc(need)) == NULL) 130 return; 131 if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) { 132 free(buf); 133 return; 134 } 135 136 bzero(&sum, sizeof(sum)); 137 138 lim = buf + need; 139 for (next = buf; next < lim; next += ifm.ifm_msglen) { 140 bcopy(next, &ifm, sizeof ifm); 141 if (ifm.ifm_type != RTM_IFINFO || 142 !(ifm.ifm_addrs & RTA_IFP)) 143 continue; 144 if (ifm.ifm_index >= nifs) { 145 if ((newstats = realloc(ifstats, (ifm.ifm_index + 4) * 146 sizeof(struct ifstat))) == NULL) 147 continue; 148 ifstats = newstats; 149 for (; nifs < ifm.ifm_index + 4; nifs++) 150 ifstats[nifs].ifs_name[0] = '\0'; 151 } 152 ifs = &ifstats[ifm.ifm_index]; 153 if (ifs->ifs_name[0] == '\0') { 154 bzero(&info, sizeof(info)); 155 rt_getaddrinfo( 156 (struct sockaddr *)((struct if_msghdr *)next + 1), 157 ifm.ifm_addrs, info); 158 if ((sdl = (struct sockaddr_dl *)info[RTAX_IFP])) { 159 if (sdl->sdl_family == AF_LINK && 160 sdl->sdl_nlen > 0) { 161 bcopy(sdl->sdl_data, ifs->ifs_name, 162 sdl->sdl_nlen); 163 ifs->ifs_name[sdl->sdl_nlen] = '\0'; 164 } 165 } 166 if (ifs->ifs_name[0] == '\0') 167 continue; 168 } 169 UPDATE(ifc_ip, ifm_data.ifi_ipackets); 170 UPDATE(ifc_ib, ifm_data.ifi_ibytes); 171 UPDATE(ifc_ie, ifm_data.ifi_ierrors); 172 UPDATE(ifc_op, ifm_data.ifi_opackets); 173 UPDATE(ifc_ob, ifm_data.ifi_obytes); 174 UPDATE(ifc_oe, ifm_data.ifi_oerrors); 175 UPDATE(ifc_co, ifm_data.ifi_collisions); 176 ifs->ifs_cur.ifc_flags = ifm.ifm_flags; 177 ifs->ifs_cur.ifc_state = ifm.ifm_data.ifi_link_state; 178 } 179 free(buf); 180 } 181 182 #define INSET 0 183 184 void 185 labelifstat(void) 186 { 187 188 wmove(wnd, 0, 0); 189 wclrtobot(wnd); 190 191 mvwaddstr(wnd, 1, INSET, "Iface"); 192 mvwaddstr(wnd, 1, INSET+9, "State"); 193 mvwaddstr(wnd, 1, INSET+19, "Ibytes"); 194 mvwaddstr(wnd, 1, INSET+29, "Ipkts"); 195 mvwaddstr(wnd, 1, INSET+36, "Ierrs"); 196 mvwaddstr(wnd, 1, INSET+48, "Obytes"); 197 mvwaddstr(wnd, 1, INSET+58, "Opkts"); 198 mvwaddstr(wnd, 1, INSET+65, "Oerrs"); 199 mvwaddstr(wnd, 1, INSET+74, "Colls"); 200 } 201 202 #define FMT "%-8.8s %2s%2s %10lu %8lu %6lu %10lu %8lu %6lu %6lu " 203 204 const char * 205 showlinkstate(int state) 206 { 207 switch (state) { 208 case LINK_STATE_UP: 209 case LINK_STATE_HALF_DUPLEX: 210 case LINK_STATE_FULL_DUPLEX: 211 return (":U"); 212 case LINK_STATE_DOWN: 213 return (":D"); 214 case LINK_STATE_UNKNOWN: 215 return (""); 216 } 217 } 218 219 void 220 showifstat(void) 221 { 222 int row; 223 struct ifstat *ifs; 224 225 row = 2; 226 wmove(wnd, 0, 0); 227 wclrtoeol(wnd); 228 for (ifs = ifstats; ifs < ifstats + nifs; ifs++) { 229 if (ifs->ifs_name[0] == '\0') 230 continue; 231 mvwprintw(wnd, row++, INSET, FMT, 232 ifs->ifs_name, 233 ifs->ifs_cur.ifc_flags & IFF_UP ? "up" : "dn", 234 showlinkstate(ifs->ifs_cur.ifc_state), 235 ifs->ifs_cur.ifc_ib, 236 ifs->ifs_cur.ifc_ip, 237 ifs->ifs_cur.ifc_ie, 238 ifs->ifs_cur.ifc_ob, 239 ifs->ifs_cur.ifc_op, 240 ifs->ifs_cur.ifc_oe, 241 ifs->ifs_cur.ifc_co); 242 } 243 mvwprintw(wnd, row++, INSET, FMT, 244 "Totals", 245 "", "", 246 sum.ifc_ib, 247 sum.ifc_ip, 248 sum.ifc_ie, 249 sum.ifc_ob, 250 sum.ifc_op, 251 sum.ifc_oe, 252 sum.ifc_co); 253 } 254 255 int 256 cmdifstat(char *cmd, char *args) 257 { 258 struct ifstat *ifs; 259 260 if (prefix(cmd, "run")) { 261 if (state != RUN) 262 for (ifs = ifstats; ifs < ifstats + nifs; ifs++) 263 ifs->ifs_old = ifs->ifs_now; 264 state = RUN; 265 return (1); 266 } 267 if (prefix(cmd, "boot")) { 268 state = BOOT; 269 for (ifs = ifstats; ifs < ifstats + nifs; ifs++) 270 bzero(&ifs->ifs_old, sizeof(ifs->ifs_old)); 271 return (1); 272 } 273 if (prefix(cmd, "time")) { 274 state = TIME; 275 return (1); 276 } 277 if (prefix(cmd, "zero")) { 278 if (state == RUN) 279 for (ifs = ifstats; ifs < ifstats + nifs; ifs++) 280 ifs->ifs_old = ifs->ifs_now; 281 return (1); 282 } 283 return (1); 284 } 285