diff options
author | delphij <delphij@FreeBSD.org> | 2010-01-27 00:30:07 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2010-01-27 00:30:07 +0000 |
commit | d9a0cd0982402f9faf826972323ba7e2c92d4da2 (patch) | |
tree | ff676986c0098bc03f0b66a25fb89a62e45f8b53 /sys/net/if.c | |
parent | f58131e1e486131bc5b10b4db8adfbfb58a6db5f (diff) | |
download | FreeBSD-src-d9a0cd0982402f9faf826972323ba7e2c92d4da2.zip FreeBSD-src-d9a0cd0982402f9faf826972323ba7e2c92d4da2.tar.gz |
Revised revision 199201 (add interface description capability as inspired
by OpenBSD), based on comments from many, including rwatson, jhb, brooks
and others.
Sponsored by: iXsystems, Inc.
MFC after: 1 month
Diffstat (limited to 'sys/net/if.c')
-rw-r--r-- | sys/net/if.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index 565913d..ba5b73f 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -106,6 +106,18 @@ SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW, &log_link_state_change, 0, "log interface link state change events"); +/* Interface description */ +static unsigned int ifdescr_maxlen = 1024; +SYSCTL_UINT(_net, OID_AUTO, ifdescr_maxlen, CTLFLAG_RW, + &ifdescr_maxlen, 0, + "administrative maximum length for interface description"); + +MALLOC_DEFINE(M_IFDESCR, "ifdescr", "ifnet descriptions"); + +/* global sx for non-critical path ifdescr */ +static struct sx ifdescr_sx; +SX_SYSINIT(ifdescr_sx, &ifdescr_sx, "ifnet descr"); + void (*bstp_linkstate_p)(struct ifnet *ifp, int state); void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); void (*lagg_linkstate_p)(struct ifnet *ifp, int state); @@ -442,6 +454,8 @@ if_free_internal(struct ifnet *ifp) #ifdef MAC mac_ifnet_destroy(ifp); #endif /* MAC */ + if (ifp->if_description != NULL) + free(ifp->if_description, M_IFDESCR); IF_AFDATA_DESTROY(ifp); IF_ADDR_LOCK_DESTROY(ifp); ifq_delete(&ifp->if_snd); @@ -1979,6 +1993,8 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) int error = 0; int new_flags, temp_flags; size_t namelen, onamelen; + size_t descrlen; + char *descrbuf, *odescrbuf; char new_name[IFNAMSIZ]; struct ifaddr *ifa; struct sockaddr_dl *sdl; @@ -2018,6 +2034,60 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) ifr->ifr_phys = ifp->if_physical; break; + case SIOCGIFDESCR: + error = 0; + sx_slock(&ifdescr_sx); + if (ifp->if_description == NULL) { + ifr->ifr_buffer.length = 0; + error = ENOMSG; + } else { + /* space for terminating nul */ + descrlen = strlen(ifp->if_description) + 1; + if (ifr->ifr_buffer.length < descrlen) + error = ENAMETOOLONG; + else + error = copyout(ifp->if_description, + ifr->ifr_buffer.buffer, descrlen); + ifr->ifr_buffer.length = descrlen; + } + sx_sunlock(&ifdescr_sx); + break; + + case SIOCSIFDESCR: + error = priv_check(td, PRIV_NET_SETIFDESCR); + if (error) + return (error); + + /* + * Copy only (length-1) bytes to make sure that + * if_description is always nul terminated. The + * length parameter is supposed to count the + * terminating nul in. + */ + if (ifr->ifr_buffer.length > ifdescr_maxlen) + return (ENAMETOOLONG); + else if (ifr->ifr_buffer.length == 0) + descrbuf = NULL; + else { + descrbuf = malloc(ifr->ifr_buffer.length, M_IFDESCR, + M_WAITOK | M_ZERO); + error = copyin(ifr->ifr_buffer.buffer, descrbuf, + ifr->ifr_buffer.length - 1); + if (error) { + free(descrbuf, M_IFDESCR); + break; + } + } + + sx_xlock(&ifdescr_sx); + odescrbuf = ifp->if_description; + ifp->if_description = descrbuf; + sx_xunlock(&ifdescr_sx); + + getmicrotime(&ifp->if_lastchange); + free(odescrbuf, M_IFDESCR); + break; + case SIOCSIFFLAGS: error = priv_check(td, PRIV_NET_SETIFFLAGS); if (error) |