Fri Jan 31 00:49:18 2020 UTC ()
- Use kmem(9) instead of malloc(9).
- When handling SIOCGIFMEDIA, don't traverse the media list directly;
  refactor that out into a ifmedia_getwords() function.


(thorpej)
diff -r1.49 -r1.50 src/sys/net/if_media.c

cvs diff -r1.49 -r1.50 src/sys/net/if_media.c (expand / switch to unified diff)

--- src/sys/net/if_media.c 2020/01/20 19:35:39 1.49
+++ src/sys/net/if_media.c 2020/01/31 00:49:18 1.50
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: if_media.c,v 1.49 2020/01/20 19:35:39 thorpej Exp $ */ 1/* $NetBSD: if_media.c,v 1.50 2020/01/31 00:49:18 thorpej Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center. 9 * NASA Ames Research Center.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -66,58 +66,56 @@ @@ -66,58 +66,56 @@
66 66
67/* 67/*
68 * BSD/OS-compatible network interface media selection. 68 * BSD/OS-compatible network interface media selection.
69 * 69 *
70 * Where it is safe to do so, this code strays slightly from the BSD/OS 70 * Where it is safe to do so, this code strays slightly from the BSD/OS
71 * design. Software which uses the API (device drivers, basically) 71 * design. Software which uses the API (device drivers, basically)
72 * shouldn't notice any difference. 72 * shouldn't notice any difference.
73 * 73 *
74 * Many thanks to Matt Thomas for providing the information necessary 74 * Many thanks to Matt Thomas for providing the information necessary
75 * to implement this interface. 75 * to implement this interface.
76 */ 76 */
77 77
78#include <sys/cdefs.h> 78#include <sys/cdefs.h>
79__KERNEL_RCSID(0, "$NetBSD: if_media.c,v 1.49 2020/01/20 19:35:39 thorpej Exp $"); 79__KERNEL_RCSID(0, "$NetBSD: if_media.c,v 1.50 2020/01/31 00:49:18 thorpej Exp $");
80 80
81#include <sys/param.h> 81#include <sys/param.h>
82#include <sys/systm.h> 82#include <sys/systm.h>
83#include <sys/errno.h> 83#include <sys/errno.h>
84#include <sys/ioctl.h> 84#include <sys/ioctl.h>
85#include <sys/socket.h> 85#include <sys/socket.h>
86#include <sys/malloc.h> 86#include <sys/kmem.h>
87 87
88#include <net/if.h> 88#include <net/if.h>
89#include <net/if_media.h> 89#include <net/if_media.h>
90#include <net/netisr.h> 90#include <net/netisr.h>
91 91
92static void ifmedia_status(struct ifmedia *, struct ifnet *, 92static void ifmedia_status(struct ifmedia *, struct ifnet *,
93 struct ifmediareq *); 93 struct ifmediareq *);
94static int ifmedia_ioctl_locked(struct ifnet *, struct ifreq *, 94static int ifmedia_ioctl_locked(struct ifnet *, struct ifreq *,
95 struct ifmedia *, u_long); 95 struct ifmedia *, u_long);
96 96
97/* 97/*
98 * Compile-time options: 98 * Compile-time options:
99 * IFMEDIA_DEBUG: 99 * IFMEDIA_DEBUG:
100 * Turn on implementation-level debug printfs. 100 * Turn on implementation-level debug printfs.
101 * Useful for debugging newly-ported drivers. 101 * Useful for debugging newly-ported drivers.
102 */ 102 */
103 103
104#ifdef IFMEDIA_DEBUG 104#ifdef IFMEDIA_DEBUG
105int ifmedia_debug = 0; 105int ifmedia_debug = 0;
106static void ifmedia_printword(int); 106static void ifmedia_printword(int);
107#endif 107#endif
108 108
109MALLOC_DEFINE(M_IFMEDIA, "ifmedia", "interface media state"); 
110 
111/* 109/*
112 * Initialize if_media struct for a specific interface instance. 110 * Initialize if_media struct for a specific interface instance.
113 */ 111 */
114void 112void
115ifmedia_init(struct ifmedia *ifm, int dontcare_mask, 113ifmedia_init(struct ifmedia *ifm, int dontcare_mask,
116 ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback) 114 ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback)
117{ 115{
118 116
119 TAILQ_INIT(&ifm->ifm_list); 117 TAILQ_INIT(&ifm->ifm_list);
120 ifm->ifm_cur = NULL; 118 ifm->ifm_cur = NULL;
121 ifm->ifm_media = IFM_NONE; 119 ifm->ifm_media = IFM_NONE;
122 ifm->ifm_mask = dontcare_mask; /* IF don't-care bits */ 120 ifm->ifm_mask = dontcare_mask; /* IF don't-care bits */
123 ifm->ifm_change = change_callback; 121 ifm->ifm_change = change_callback;
@@ -152,27 +150,27 @@ ifmedia_add(struct ifmedia *ifm, int mwo @@ -152,27 +150,27 @@ ifmedia_add(struct ifmedia *ifm, int mwo
152 struct ifmedia_entry *entry; 150 struct ifmedia_entry *entry;
153 151
154#ifdef IFMEDIA_DEBUG 152#ifdef IFMEDIA_DEBUG
155 if (ifmedia_debug) { 153 if (ifmedia_debug) {
156 if (ifm == NULL) { 154 if (ifm == NULL) {
157 printf("ifmedia_add: null ifm\n"); 155 printf("ifmedia_add: null ifm\n");
158 return; 156 return;
159 } 157 }
160 printf("Adding entry for "); 158 printf("Adding entry for ");
161 ifmedia_printword(mword); 159 ifmedia_printword(mword);
162 } 160 }
163#endif 161#endif
164 162
165 entry = malloc(sizeof(*entry), M_IFMEDIA, M_WAITOK); 163 entry = kmem_zalloc(sizeof(*entry), KM_SLEEP);
166 entry->ifm_media = mword; 164 entry->ifm_media = mword;
167 entry->ifm_data = data; 165 entry->ifm_data = data;
168 entry->ifm_aux = aux; 166 entry->ifm_aux = aux;
169 TAILQ_INSERT_TAIL(&ifm->ifm_list, entry, ifm_list); 167 TAILQ_INSERT_TAIL(&ifm->ifm_list, entry, ifm_list);
170} 168}
171 169
172/* 170/*
173 * Add an array of media configurations to the list of 171 * Add an array of media configurations to the list of
174 * supported media for a specific interface instance. 172 * supported media for a specific interface instance.
175 */ 173 */
176void 174void
177ifmedia_list_add(struct ifmedia *ifm, struct ifmedia_entry *lp, int count) 175ifmedia_list_add(struct ifmedia *ifm, struct ifmedia_entry *lp, int count)
178{ 176{
@@ -225,26 +223,42 @@ ifmedia_set(struct ifmedia *ifm, int tar @@ -225,26 +223,42 @@ ifmedia_set(struct ifmedia *ifm, int tar
225 } 223 }
226 ifm->ifm_cur = match; 224 ifm->ifm_cur = match;
227 225
228#ifdef IFMEDIA_DEBUG 226#ifdef IFMEDIA_DEBUG
229 if (ifmedia_debug) { 227 if (ifmedia_debug) {
230 printf("ifmedia_set: target "); 228 printf("ifmedia_set: target ");
231 ifmedia_printword(target); 229 ifmedia_printword(target);
232 printf("ifmedia_set: setting to "); 230 printf("ifmedia_set: setting to ");
233 ifmedia_printword(ifm->ifm_cur->ifm_media); 231 ifmedia_printword(ifm->ifm_cur->ifm_media);
234 } 232 }
235#endif 233#endif
236} 234}
237 235
 236static int
 237ifmedia_getwords(struct ifmedia * const ifm, int *words, int maxwords)
 238{
 239 struct ifmedia_entry *ep;
 240 int nwords = 0;
 241
 242 TAILQ_FOREACH(ep, &ifm->ifm_list, ifm_list) {
 243 if (words != NULL && nwords < maxwords) {
 244 words[nwords] = ep->ifm_media;
 245 }
 246 nwords++;
 247 }
 248
 249 return nwords;
 250}
 251
238/* 252/*
239 * Device-independent media ioctl support function. 253 * Device-independent media ioctl support function.
240 */ 254 */
241static int 255static int
242ifmedia_ioctl_locked(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm, 256ifmedia_ioctl_locked(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm,
243 u_long cmd) 257 u_long cmd)
244{ 258{
245 struct ifmedia_entry *match; 259 struct ifmedia_entry *match;
246 struct ifmediareq *ifmr = (struct ifmediareq *)ifr; 260 struct ifmediareq *ifmr = (struct ifmediareq *)ifr;
247 int error = 0; 261 int error = 0;
248 262
249 if (ifp == NULL || ifr == NULL || ifm == NULL) 263 if (ifp == NULL || ifr == NULL || ifm == NULL)
250 return EINVAL; 264 return EINVAL;
@@ -294,67 +308,57 @@ ifmedia_ioctl_locked(struct ifnet *ifp,  @@ -294,67 +308,57 @@ ifmedia_ioctl_locked(struct ifnet *ifp,
294 ifm->ifm_cur = match; 308 ifm->ifm_cur = match;
295 ifm->ifm_media = newmedia; 309 ifm->ifm_media = newmedia;
296 error = ifmedia_change(ifm, ifp); 310 error = ifmedia_change(ifm, ifp);
297 if (error) { 311 if (error) {
298 ifm->ifm_cur = oldentry; 312 ifm->ifm_cur = oldentry;
299 ifm->ifm_media = oldmedia; 313 ifm->ifm_media = oldmedia;
300 } 314 }
301 break; 315 break;
302 } 316 }
303 317
304 /* Get list of available media and current media on interface. */ 318 /* Get list of available media and current media on interface. */
305 case SIOCGIFMEDIA: 319 case SIOCGIFMEDIA:
306 { 320 {
307 struct ifmedia_entry *ep; 321 int nwords1, nwords2;
308 size_t nwords; 
309 322
310 if (ifmr->ifm_count < 0) 323 if (ifmr->ifm_count < 0)
311 return EINVAL; 324 return EINVAL;
312 325
313 ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ? 326 ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ?
314 ifm->ifm_cur->ifm_media : IFM_NONE; 327 ifm->ifm_cur->ifm_media : IFM_NONE;
315 ifmr->ifm_mask = ifm->ifm_mask; 328 ifmr->ifm_mask = ifm->ifm_mask;
316 ifmr->ifm_status = 0; 329 ifmr->ifm_status = 0;
317 ifmedia_status(ifm, ifp, ifmr); 330 ifmedia_status(ifm, ifp, ifmr);
318 331
319 /* 332 /*
320 * Count them so we know a-priori how much is the max we'll 333 * Count them so we know a-priori how much is the max we'll
321 * need. 334 * need.
322 */ 335 */
323 ep = TAILQ_FIRST(&ifm->ifm_list); 336 nwords1 = nwords2 = ifmedia_getwords(ifm, NULL, 0);
324 for (nwords = 0; ep != NULL; ep = TAILQ_NEXT(ep, ifm_list)) 
325 nwords++; 
326 337
327 if (ifmr->ifm_count != 0) { 338 if (ifmr->ifm_count != 0) {
328 size_t count; 339 int maxwords = MIN(nwords1, ifmr->ifm_count);
329 size_t minwords = nwords > (size_t)ifmr->ifm_count 340 int *kptr = kmem_zalloc(maxwords * sizeof(int),
330 ? (size_t)ifmr->ifm_count : nwords; 341 KM_SLEEP);
331 int *kptr = malloc(minwords * sizeof(int), M_TEMP, 
332 M_WAITOK); 
333 
334 /* Get the media words from the interface's list. */ 
335 ep = TAILQ_FIRST(&ifm->ifm_list); 
336 for (count = 0; ep != NULL && count < minwords; 
337 ep = TAILQ_NEXT(ep, ifm_list), count++) 
338 kptr[count] = ep->ifm_media; 
339 342
 343 nwords2 = ifmedia_getwords(ifm, kptr, maxwords);
340 error = copyout(kptr, ifmr->ifm_ulist, 344 error = copyout(kptr, ifmr->ifm_ulist,
341 minwords * sizeof(int)); 345 maxwords * sizeof(int));
342 if (error == 0 && ep != NULL) 346 if (error == 0 && nwords2 > nwords1)
343 error = E2BIG; /* oops! */ 347 error = E2BIG; /* oops! */
344 free(kptr, M_TEMP); 348 kmem_free(kptr, maxwords * sizeof(int));
345 } 349 }
346 /* Update with the real number */ 350 /* Update with the real number */
347 ifmr->ifm_count = nwords; 351 ifmr->ifm_count = nwords2;
348 break; 352 break;
349 } 353 }
350 354
351 default: 355 default:
352 return EINVAL; 356 return EINVAL;
353 } 357 }
354 358
355 return error; 359 return error;
356} 360}
357 361
358int 362int
359ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm, 363ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr, struct ifmedia *ifm,
360 u_long cmd) 364 u_long cmd)
@@ -410,27 +414,27 @@ ifmedia_match(struct ifmedia *ifm, u_int @@ -410,27 +414,27 @@ ifmedia_match(struct ifmedia *ifm, u_int
410 414
411/* 415/*
412 * Delete all media for a given instance. 416 * Delete all media for a given instance.
413 */ 417 */
414void 418void
415ifmedia_delete_instance(struct ifmedia *ifm, u_int inst) 419ifmedia_delete_instance(struct ifmedia *ifm, u_int inst)
416{ 420{
417 struct ifmedia_entry *ife, *nife; 421 struct ifmedia_entry *ife, *nife;
418 422
419 TAILQ_FOREACH_SAFE(ife, &ifm->ifm_list, ifm_list, nife) { 423 TAILQ_FOREACH_SAFE(ife, &ifm->ifm_list, ifm_list, nife) {
420 if (inst == IFM_INST_ANY || 424 if (inst == IFM_INST_ANY ||
421 inst == IFM_INST(ife->ifm_media)) { 425 inst == IFM_INST(ife->ifm_media)) {
422 TAILQ_REMOVE(&ifm->ifm_list, ife, ifm_list); 426 TAILQ_REMOVE(&ifm->ifm_list, ife, ifm_list);
423 free(ife, M_IFMEDIA); 427 kmem_free(ife, sizeof(*ife));
424 } 428 }
425 } 429 }
426 if (inst == IFM_INST_ANY) { 430 if (inst == IFM_INST_ANY) {
427 ifm->ifm_cur = NULL; 431 ifm->ifm_cur = NULL;
428 ifm->ifm_media = IFM_NONE; 432 ifm->ifm_media = IFM_NONE;
429 } 433 }
430} 434}
431 435
432void 436void
433ifmedia_removeall(struct ifmedia *ifm) 437ifmedia_removeall(struct ifmedia *ifm)
434{ 438{
435 439
436 ifmedia_delete_instance(ifm, IFM_INST_ANY); 440 ifmedia_delete_instance(ifm, IFM_INST_ANY);