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 | |
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')
-rw-r--r-- | sys/net/if.c | 70 | ||||
-rw-r--r-- | sys/net/if.h | 10 | ||||
-rw-r--r-- | sys/net/if_var.h | 3 |
3 files changed, 82 insertions, 1 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) diff --git a/sys/net/if.h b/sys/net/if.h index f94b54a..aff0d76 100644 --- a/sys/net/if.h +++ b/sys/net/if.h @@ -284,6 +284,14 @@ struct if_announcemsghdr { #define IFAN_DEPARTURE 1 /* interface departure */ /* + * Buffer with length to be used in SIOCGIFDESCR/SIOCSIFDESCR requests + */ +struct ifreq_buffer { + size_t length; + void *buffer; +}; + +/* * Interface request structure used for socket * ioctl's. All interface ioctl's must have parameter * definitions which begin with ifr_name. The @@ -295,6 +303,7 @@ struct ifreq { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; + struct ifreq_buffer ifru_buffer; short ifru_flags[2]; short ifru_index; int ifru_jid; @@ -308,6 +317,7 @@ struct ifreq { #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */ #define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_buffer ifr_ifru.ifru_buffer /* user supplied buffer with its length */ #define ifr_flags ifr_ifru.ifru_flags[0] /* flags (low 16 bits) */ #define ifr_flagshigh ifr_ifru.ifru_flags[1] /* flags (high 16 bits) */ #define ifr_jid ifr_ifru.ifru_jid /* jail/vnet */ diff --git a/sys/net/if_var.h b/sys/net/if_var.h index 9ea533b..37ebea5 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -203,7 +203,8 @@ struct ifnet { * be used with care where binary compatibility is required. */ char if_cspare[3]; - void *if_pspare[8]; + char *if_description; /* interface description */ + void *if_pspare[7]; int if_ispare[4]; }; |