1 /* $OpenBSD: if.c,v 1.13 2009/04/03 20:29:21 deraadt 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 #include <sys/sockio.h> 25 26 #include <stdlib.h> 27 #include <string.h> 28 29 #include "systat.h" 30 31 static enum state { BOOT, TIME, RUN } state = TIME; 32 33 struct ifcount { 34 u_int64_t ifc_ib; /* input bytes */ 35 u_int64_t ifc_ip; /* input packets */ 36 u_int64_t ifc_ie; /* input errors */ 37 u_int64_t ifc_ob; /* output bytes */ 38 u_int64_t ifc_op; /* output packets */ 39 u_int64_t ifc_oe; /* output errors */ 40 u_int64_t 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 char ifs_description[IFDESCRSIZE]; 48 struct ifcount ifs_cur; 49 struct ifcount ifs_old; 50 struct ifcount ifs_now; 51 } *ifstats; 52 53 static int nifs = 0; 54 static int num_ifs = 0; 55 56 void print_if(void); 57 int read_if(void); 58 int select_if(void); 59 int if_keyboard_callback(int); 60 61 static void fetchifstat(void); 62 static void showifstat(struct ifstat *); 63 static void showtotal(void); 64 65 66 /* Define fields */ 67 field_def fields_if[] = { 68 {"IFACE", 8, 16, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 69 {"STATE", 4, 6, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 70 {"IPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 71 {"IBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 72 {"IERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 73 {"OPKTS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 74 {"OBYTES", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 75 {"OERRS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 76 {"COLLS", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, 77 {"DESC", 14, 64, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, 78 }; 79 80 81 #define FIELD_ADDR(x) (&fields_if[x]) 82 83 #define FLD_IF_IFACE FIELD_ADDR(0) 84 #define FLD_IF_STATE FIELD_ADDR(1) 85 #define FLD_IF_IPKTS FIELD_ADDR(2) 86 #define FLD_IF_IBYTES FIELD_ADDR(3) 87 #define FLD_IF_IERRS FIELD_ADDR(4) 88 #define FLD_IF_OPKTS FIELD_ADDR(5) 89 #define FLD_IF_OBYTES FIELD_ADDR(6) 90 #define FLD_IF_OERRS FIELD_ADDR(7) 91 #define FLD_IF_COLLS FIELD_ADDR(8) 92 #define FLD_IF_DESC FIELD_ADDR(9) 93 94 95 /* Define views */ 96 field_def *view_if_0[] = { 97 FLD_IF_IFACE, FLD_IF_STATE, FLD_IF_DESC, FLD_IF_IPKTS, 98 FLD_IF_IBYTES, FLD_IF_IERRS, FLD_IF_OPKTS, FLD_IF_OBYTES, 99 FLD_IF_OERRS, FLD_IF_COLLS, NULL 100 }; 101 102 /* Define view managers */ 103 104 struct view_manager ifstat_mgr = { 105 "Ifstat", select_if, read_if, NULL, print_header, 106 print_if, if_keyboard_callback, NULL, NULL 107 }; 108 109 field_view views_if[] = { 110 {view_if_0, "ifstat", '1', &ifstat_mgr}, 111 {NULL, NULL, 0, NULL} 112 }; 113 114 115 int 116 initifstat(void) 117 { 118 field_view *v; 119 read_if(); 120 for (v = views_if; v->name != NULL; v++) 121 add_view(v); 122 123 return(1); 124 } 125 126 #define UPDATE(x, y) do { \ 127 ifs->ifs_now.x = ifm.y; \ 128 ifs->ifs_cur.x = ifs->ifs_now.x - ifs->ifs_old.x; \ 129 if (state == TIME) {\ 130 ifs->ifs_old.x = ifs->ifs_now.x; \ 131 ifs->ifs_cur.x /= naptime; \ 132 } \ 133 sum.x += ifs->ifs_cur.x; \ 134 } while(0) 135 136 137 void 138 rt_getaddrinfo(struct sockaddr *sa, int addrs, struct sockaddr **info) 139 { 140 int i; 141 142 for (i = 0; i < RTAX_MAX; i++) { 143 if (addrs & (1 << i)) { 144 info[i] = sa; 145 sa = (struct sockaddr *) ((char *)(sa) + 146 roundup(sa->sa_len, sizeof(long))); 147 } else 148 info[i] = NULL; 149 } 150 } 151 152 153 154 int 155 select_if(void) 156 { 157 num_disp = num_ifs + 1; 158 return (0); 159 } 160 161 int 162 read_if(void) 163 { 164 fetchifstat(); 165 num_disp = num_ifs + 1; 166 167 return 0; 168 } 169 170 void 171 print_if(void) 172 { 173 int n, i, count = 0; 174 175 for (n = 0, i = 0; n < nifs; n++) { 176 if (ifstats[n].ifs_name[0] == '\0') 177 continue; 178 if (i++ < dispstart) 179 continue; 180 if (i == num_disp) 181 break; 182 showifstat(ifstats + n); 183 if (maxprint > 0 && ++count >= maxprint) 184 return; 185 } 186 showtotal(); 187 } 188 189 190 static void 191 fetchifstat(void) 192 { 193 struct ifstat *newstats, *ifs; 194 struct if_msghdr ifm; 195 struct sockaddr *info[RTAX_MAX]; 196 struct sockaddr_dl *sdl; 197 char *buf, *next, *lim; 198 static int s = -1; 199 int mib[6]; 200 size_t need; 201 202 mib[0] = CTL_NET; 203 mib[1] = AF_ROUTE; 204 mib[2] = 0; 205 mib[3] = 0; 206 mib[4] = NET_RT_IFLIST; 207 mib[5] = 0; 208 209 if (sysctl(mib, 6, NULL, &need, NULL, 0) == -1) 210 return; 211 if ((buf = malloc(need)) == NULL) 212 return; 213 if (sysctl(mib, 6, buf, &need, NULL, 0) == -1) { 214 free(buf); 215 return; 216 } 217 218 bzero(&sum, sizeof(sum)); 219 num_ifs = 0; 220 221 lim = buf + need; 222 for (next = buf; next < lim; next += ifm.ifm_msglen) { 223 bcopy(next, &ifm, sizeof ifm); 224 if (ifm.ifm_type != RTM_IFINFO || 225 !(ifm.ifm_addrs & RTA_IFP)) 226 continue; 227 if (ifm.ifm_index >= nifs) { 228 if ((newstats = realloc(ifstats, (ifm.ifm_index + 4) 229 * sizeof(struct ifstat))) == NULL) 230 continue; 231 ifstats = newstats; 232 for (; nifs < ifm.ifm_index + 4; nifs++) 233 bzero(&ifstats[nifs], sizeof(*ifstats)); 234 } 235 ifs = &ifstats[ifm.ifm_index]; 236 if (ifs->ifs_name[0] == '\0') { 237 bzero(&info, sizeof(info)); 238 rt_getaddrinfo( 239 (struct sockaddr *)((struct if_msghdr *)next + 1), 240 ifm.ifm_addrs, info); 241 sdl = (struct sockaddr_dl *)info[RTAX_IFP]; 242 243 if (sdl && sdl->sdl_family == AF_LINK && 244 sdl->sdl_nlen > 0) { 245 struct ifreq ifrdesc; 246 char ifdescr[IFDESCRSIZE]; 247 int s; 248 249 bcopy(sdl->sdl_data, ifs->ifs_name, 250 sdl->sdl_nlen); 251 ifs->ifs_name[sdl->sdl_nlen] = '\0'; 252 253 /* Get the interface description */ 254 memset(&ifrdesc, 0, sizeof(ifrdesc)); 255 strlcpy(ifrdesc.ifr_name, ifs->ifs_name, 256 sizeof(ifrdesc.ifr_name)); 257 ifrdesc.ifr_data = (caddr_t)&ifdescr; 258 259 s = socket(AF_INET, SOCK_DGRAM, 0); 260 if (s != -1) { 261 if (ioctl(s, SIOCGIFDESCR, &ifrdesc) == 0) 262 strlcpy(ifs->ifs_description, 263 ifrdesc.ifr_data, 264 sizeof(ifs->ifs_description)); 265 close(s); 266 } 267 } 268 if (ifs->ifs_name[0] == '\0') 269 continue; 270 } 271 num_ifs++; 272 UPDATE(ifc_ip, ifm_data.ifi_ipackets); 273 UPDATE(ifc_ib, ifm_data.ifi_ibytes); 274 UPDATE(ifc_ie, ifm_data.ifi_ierrors); 275 UPDATE(ifc_op, ifm_data.ifi_opackets); 276 UPDATE(ifc_ob, ifm_data.ifi_obytes); 277 UPDATE(ifc_oe, ifm_data.ifi_oerrors); 278 UPDATE(ifc_co, ifm_data.ifi_collisions); 279 ifs->ifs_cur.ifc_flags = ifm.ifm_flags; 280 ifs->ifs_cur.ifc_state = ifm.ifm_data.ifi_link_state; 281 } 282 free(buf); 283 } 284 285 286 static void 287 showifstat(struct ifstat *ifs) 288 { 289 print_fld_str(FLD_IF_IFACE, ifs->ifs_name); 290 291 tb_start(); 292 tbprintf("%s", ifs->ifs_cur.ifc_flags & IFF_UP ? 293 "up" : "dn"); 294 295 switch (ifs->ifs_cur.ifc_state) { 296 case LINK_STATE_UP: 297 case LINK_STATE_HALF_DUPLEX: 298 case LINK_STATE_FULL_DUPLEX: 299 tbprintf(":U"); 300 break; 301 case LINK_STATE_DOWN: 302 tbprintf (":D"); 303 break; 304 } 305 306 print_fld_tb(FLD_IF_STATE); 307 308 print_fld_str(FLD_IF_DESC, ifs->ifs_description); 309 310 print_fld_size(FLD_IF_IBYTES, ifs->ifs_cur.ifc_ib); 311 print_fld_size(FLD_IF_IPKTS, ifs->ifs_cur.ifc_ip); 312 print_fld_size(FLD_IF_IERRS, ifs->ifs_cur.ifc_ie); 313 314 print_fld_size(FLD_IF_OBYTES, ifs->ifs_cur.ifc_ob); 315 print_fld_size(FLD_IF_OPKTS, ifs->ifs_cur.ifc_op); 316 print_fld_size(FLD_IF_OERRS, ifs->ifs_cur.ifc_oe); 317 318 print_fld_size(FLD_IF_COLLS, ifs->ifs_cur.ifc_co); 319 320 end_line(); 321 } 322 323 static void 324 showtotal(void) 325 { 326 print_fld_str(FLD_IF_IFACE, "Totals"); 327 328 print_fld_size(FLD_IF_IBYTES, sum.ifc_ib); 329 print_fld_size(FLD_IF_IPKTS, sum.ifc_ip); 330 print_fld_size(FLD_IF_IERRS, sum.ifc_ie); 331 332 print_fld_size(FLD_IF_OBYTES, sum.ifc_ob); 333 print_fld_size(FLD_IF_OPKTS, sum.ifc_op); 334 print_fld_size(FLD_IF_OERRS, sum.ifc_oe); 335 336 print_fld_size(FLD_IF_COLLS, sum.ifc_co); 337 338 end_line(); 339 340 } 341 342 int 343 if_keyboard_callback(int ch) 344 { 345 struct ifstat *ifs; 346 347 switch (ch) { 348 case 'r': 349 for (ifs = ifstats; ifs < ifstats + nifs; ifs++) 350 ifs->ifs_old = ifs->ifs_now; 351 state = RUN; 352 gotsig_alarm = 1; 353 354 break; 355 case 'b': 356 state = BOOT; 357 for (ifs = ifstats; ifs < ifstats + nifs; ifs++) 358 bzero(&ifs->ifs_old, sizeof(ifs->ifs_old)); 359 gotsig_alarm = 1; 360 break; 361 case 't': 362 state = TIME; 363 gotsig_alarm = 1; 364 break; 365 default: 366 return keyboard_callback(ch); 367 }; 368 369 return 1; 370 } 371 372