summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/uts/common/inet/sockmods/netpacket/packet.h11
-rw-r--r--usr/src/uts/common/inet/sockmods/sockmod_pfp.c118
-rw-r--r--usr/src/uts/common/sys/time.h2
3 files changed, 95 insertions, 36 deletions
diff --git a/usr/src/uts/common/inet/sockmods/netpacket/packet.h b/usr/src/uts/common/inet/sockmods/netpacket/packet.h
index 1ac16dd02e..bcfecc39df 100644
--- a/usr/src/uts/common/inet/sockmods/netpacket/packet.h
+++ b/usr/src/uts/common/inet/sockmods/netpacket/packet.h
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent, Inc. All rights reserved.
*/
#ifndef _PACKET_H
@@ -39,10 +40,11 @@
#define PACKET_MULTICAST LINUX_SLL_MULTICAST
#define PACKET_OTHERHOST LINUX_SLL_OTHERHOST
-#define PACKET_STATISTICS 1
+#define PACKET_STATISTICS_SHORT 1
#define PACKET_ADD_MEMBERSHIP 2
#define PACKET_DROP_MEMBERSHIP 3
#define PACKET_AUXDATA 4
+#define PACKET_STATISTICS 5
struct packet_mreq {
@@ -95,6 +97,11 @@ struct tpacket2_hdr { /* tp_macoff/tp_netoff ?? */
};
struct tpacket_stats {
+ uint32_t tp_packets;
+ uint32_t tp_drops;
+};
+
+struct tpacket_stats_short {
uint16_t tp_packets;
uint16_t tp_drops;
};
@@ -183,6 +190,8 @@ typedef struct pfpsock {
kmutex_t ps_lock;
boolean_t ps_flow_ctrld;
ulong_t ps_flow_ctrl_drops;
+ timespec_t ps_timestamp;
+ size_t ps_rcvbuf;
} pfpsock_t;
typedef struct pfp_kstats_s {
diff --git a/usr/src/uts/common/inet/sockmods/sockmod_pfp.c b/usr/src/uts/common/inet/sockmods/sockmod_pfp.c
index ed2a8ff5b1..b821eec1a7 100644
--- a/usr/src/uts/common/inet/sockmods/sockmod_pfp.c
+++ b/usr/src/uts/common/inet/sockmods/sockmod_pfp.c
@@ -21,6 +21,7 @@
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent, Inc. All rights reserved.
*/
#include <sys/types.h>
@@ -57,8 +58,9 @@ static void pfp_close(mac_handle_t, mac_client_handle_t);
static int pfp_dl_to_arphrd(int);
static int pfp_getpacket_sockopt(sock_lower_handle_t, int, void *,
socklen_t *);
-static int pfp_ifreq_getlinkid(intptr_t, struct ifreq *, datalink_id_t *);
-static int pfp_lifreq_getlinkid(intptr_t, struct lifreq *, datalink_id_t *);
+static int pfp_ifreq_getlinkid(intptr_t, struct ifreq *, datalink_id_t *, int);
+static int pfp_lifreq_getlinkid(intptr_t, struct lifreq *, datalink_id_t *,
+ int);
static int pfp_open_index(int, mac_handle_t *, mac_client_handle_t *,
cred_t *);
static void pfp_packet(void *, mac_resource_handle_t, mblk_t *, boolean_t);
@@ -161,6 +163,14 @@ static int accepted_protos[3][2] = {
};
/*
+ * This sets an upper bound on the size of the receive buffer for a PF_PACKET
+ * socket. More properly, this should be controlled through ipadm, ala TCP, UDP,
+ * SCTP, etc. Until that's done, this provides a hard cap of 4 MB and allows an
+ * opportunity for it to be changed, should it be needed.
+ */
+int sockmod_pfp_rcvbuf_max = 1024 * 1024 * 4;
+
+/*
* Module linkage information for the kernel.
*/
static struct modlsockmod modlsockmod = {
@@ -539,6 +549,8 @@ pfp_packet(void *arg, mac_resource_handle_t mrh, mblk_t *mp, boolean_t flag)
linkb(mp0, mp);
+ (void) gethrestime(&ps->ps_timestamp);
+
ps->ps_upcalls->su_recv(ps->ps_upper, mp0, hdr.mhi_pktsize, 0,
&error, NULL);
@@ -644,18 +656,33 @@ static int
sdpfp_getsockopt(sock_lower_handle_t handle, int level, int option_name,
void *optval, socklen_t *optlenp, struct cred *cred)
{
+ struct pfpsock *ps;
int error = 0;
+ ps = (struct pfpsock *)handle;
+
switch (level) {
case SOL_PACKET :
error = pfp_getpacket_sockopt(handle, option_name, optval,
optlenp);
break;
+
+ case SOL_SOCKET :
+ if (option_name == SO_RCVBUF) {
+ if (*optlenp < sizeof (int32_t))
+ return (EINVAL);
+ *((int32_t *)optval) = ps->ps_rcvbuf;
+ *optlenp = sizeof (int32_t);
+ } else {
+ error = ENOPROTOOPT;
+ }
+ break;
+
default :
/*
* If sockfs code receives this error in return from the
* getsockopt downcall it handles the option locally, if
- * it can. This implements SO_RCVBUF, etc.
+ * it can.
*/
error = ENOPROTOOPT;
break;
@@ -870,11 +897,7 @@ static int
sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod,
int32_t *rval, struct cred *cr)
{
-#if defined(_SYSCALL32)
- struct timeval32 tival;
-#else
struct timeval tival;
-#endif
mac_client_promisc_type_t mtype;
struct sockaddr_dl *sock;
datalink_id_t linkid;
@@ -882,9 +905,10 @@ sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod,
struct ifreq ifreq;
struct pfpsock *ps;
mac_handle_t mh;
- timespec_t tv;
int error;
+ ps = (struct pfpsock *)handle;
+
switch (cmd) {
/*
* ioctls that work on "struct lifreq"
@@ -894,7 +918,7 @@ sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod,
case SIOCGLIFFLAGS :
case SIOCGLIFMTU :
case SIOCGLIFHWADDR :
- error = pfp_lifreq_getlinkid(arg, &lifreq, &linkid);
+ error = pfp_lifreq_getlinkid(arg, &lifreq, &linkid, mod);
if (error != 0)
return (error);
break;
@@ -910,18 +934,33 @@ sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod,
case SIOCGIFFLAGS :
case SIOCGIFMTU :
case SIOCGIFHWADDR :
- error = pfp_ifreq_getlinkid(arg, &ifreq, &linkid);
+ error = pfp_ifreq_getlinkid(arg, &ifreq, &linkid, mod);
if (error != 0)
return (error);
break;
+
+ case SIOCGSTAMP :
+ tival.tv_sec = (time_t)ps->ps_timestamp.tv_sec;
+ tival.tv_usec = ps->ps_timestamp.tv_nsec / 1000;
+ if (get_udatamodel() == DATAMODEL_NATIVE) {
+ error = ddi_copyout(&tival, (void *)arg,
+ sizeof (tival), mod);
+ }
+#ifdef _SYSCALL32_IMPL
+ else {
+ struct timeval32 tv32;
+ TIMEVAL_TO_TIMEVAL32(&tv32, &tival);
+ error = ddi_copyout(&tv32, (void *)arg,
+ sizeof (tv32), mod);
+ }
+#endif
+ return (error);
}
error = mac_open_by_linkid(linkid, &mh);
if (error != 0)
return (error);
- ps = (struct pfpsock *)handle;
-
switch (cmd) {
case SIOCGLIFINDEX :
lifreq.lifr_index = linkid;
@@ -1026,13 +1065,6 @@ sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod,
}
break;
- case SIOCGSTAMP :
- (void) gethrestime(&tv);
- tival.tv_sec = (time_t)tv.tv_sec;
- tival.tv_usec = tv.tv_nsec / 1000;
- error = ddi_copyout(&tival, (void *)arg, sizeof (tival), 0);
- break;
-
default :
break;
}
@@ -1049,7 +1081,7 @@ sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod,
case SIOCGLIFMTU :
case SIOCGLIFHWADDR :
error = ddi_copyout(&lifreq, (void *)arg,
- sizeof (lifreq), 0);
+ sizeof (lifreq), mod);
break;
case SIOCGIFINDEX :
@@ -1057,7 +1089,7 @@ sdpfp_ioctl(sock_lower_handle_t handle, int cmd, intptr_t arg, int mod,
case SIOCGIFMTU :
case SIOCGIFHWADDR :
error = ddi_copyout(&ifreq, (void *)arg,
- sizeof (ifreq), 0);
+ sizeof (ifreq), mod);
break;
default :
break;
@@ -1107,12 +1139,12 @@ sdpfp_close(sock_lower_handle_t handle, int flag, struct cred *cr)
*/
static int
pfp_ifreq_getlinkid(intptr_t arg, struct ifreq *ifreqp,
- datalink_id_t *linkidp)
+ datalink_id_t *linkidp, int mode)
{
char name[IFNAMSIZ + 1];
int error;
- if (ddi_copyin((void *)arg, ifreqp, sizeof (*ifreqp), 0) != 0)
+ if (ddi_copyin((void *)arg, ifreqp, sizeof (*ifreqp), mode) != 0)
return (EFAULT);
(void) strlcpy(name, ifreqp->ifr_name, sizeof (name));
@@ -1132,12 +1164,12 @@ pfp_ifreq_getlinkid(intptr_t arg, struct ifreq *ifreqp,
*/
static int
pfp_lifreq_getlinkid(intptr_t arg, struct lifreq *lifreqp,
- datalink_id_t *linkidp)
+ datalink_id_t *linkidp, int mode)
{
char name[LIFNAMSIZ + 1];
int error;
- if (ddi_copyin((void *)arg, lifreqp, sizeof (*lifreqp), 0) != 0)
+ if (ddi_copyin((void *)arg, lifreqp, sizeof (*lifreqp), mode) != 0)
return (EFAULT);
(void) strlcpy(name, lifreqp->lifr_name, sizeof (name));
@@ -1162,6 +1194,7 @@ pfp_getpacket_sockopt(sock_lower_handle_t handle, int option_name,
void *optval, socklen_t *optlenp)
{
struct pfpsock *ps;
+ struct tpacket_stats_short tpss;
int error = 0;
ps = (struct pfpsock *)handle;
@@ -1175,6 +1208,16 @@ pfp_getpacket_sockopt(sock_lower_handle_t handle, int option_name,
*optlenp = sizeof (ps->ps_stats);
bcopy(&ps->ps_stats, optval, sizeof (ps->ps_stats));
break;
+ case PACKET_STATISTICS_SHORT :
+ if (*optlenp < sizeof (tpss)) {
+ error = EINVAL;
+ break;
+ }
+ *optlenp = sizeof (tpss);
+ tpss.tp_packets = ps->ps_stats.tp_packets;
+ tpss.tp_drops = ps->ps_stats.tp_drops;
+ bcopy(&tpss, optval, sizeof (tpss));
+ break;
default :
error = EINVAL;
break;
@@ -1282,9 +1325,7 @@ pfp_setpacket_sockopt(sock_lower_handle_t handle, int option_name,
/*
* There are only two special setsockopt's for SOL_SOCKET with PF_PACKET:
- * SO_ATTACH_FILTER and SO_DETACH_FILTER. All other setsockopt requests
- * that are for SOL_SOCKET are passed back to the socket layer for its
- * generic implementation.
+ * SO_ATTACH_FILTER and SO_DETACH_FILTER.
*
* Both of these setsockopt values are candidates for being handled by the
* socket layer itself in future, however this requires understanding how
@@ -1297,6 +1338,7 @@ pfp_setsocket_sockopt(sock_lower_handle_t handle, int option_name,
struct bpf_program prog;
struct bpf_insn *fcode;
struct pfpsock *ps;
+ struct sock_proto_props sopp;
int error = 0;
int size;
@@ -1318,6 +1360,8 @@ pfp_setsocket_sockopt(sock_lower_handle_t handle, int option_name,
} else if (optlen != sizeof (struct bpf_program)) {
return (EINVAL);
}
+ if (prog.bf_len > BPF_MAXINSNS)
+ return (EINVAL);
size = prog.bf_len * sizeof (*prog.bf_insns);
fcode = kmem_alloc(size, KM_SLEEP);
@@ -1342,12 +1386,18 @@ pfp_setsocket_sockopt(sock_lower_handle_t handle, int option_name,
case SO_DETACH_FILTER :
pfp_release_bpf(ps);
break;
+
+ case SO_RCVBUF :
+ size = *(int32_t *)optval;
+ if (size > sockmod_pfp_rcvbuf_max || size < 0)
+ return (ENOBUFS);
+ sopp.sopp_flags = SOCKOPT_RCVHIWAT;
+ sopp.sopp_rxhiwat = size;
+ ps->ps_upcalls->su_set_proto_props(ps->ps_upper, &sopp);
+ ps->ps_rcvbuf = size;
+ break;
+
default :
- /*
- * If sockfs code receives this error in return from the
- * getsockopt downcall it handles the option locally, if
- * it can. This implements SO_RCVBUF, etc.
- */
error = ENOPROTOOPT;
break;
}
@@ -1391,7 +1441,7 @@ pfp_open_index(int index, mac_handle_t *mhp, mac_client_handle_t *mcip,
mac_perim_handle_t perim;
mac_perim_enter_by_mh(mh, &perim);
- error = dls_link_getzid(mac_client_name(mch), &ifzoneid);
+ error = dls_link_getzid(mac_name(mh), &ifzoneid);
mac_perim_exit(perim);
if (error != 0)
goto bad_open;
diff --git a/usr/src/uts/common/sys/time.h b/usr/src/uts/common/sys/time.h
index c110707171..bdf1c02ea4 100644
--- a/usr/src/uts/common/sys/time.h
+++ b/usr/src/uts/common/sys/time.h
@@ -59,7 +59,7 @@ struct timeval {
#define TIMEVAL_TO_TIMEVAL32(tv32, tv) { \
(tv32)->tv_sec = (time32_t)(tv)->tv_sec; \
- (tv32)->tv_usec = (tv)->tv_usec; \
+ (tv32)->tv_usec = (int32_t)(tv)->tv_usec; \
}
#define TIME32_MAX INT32_MAX