summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c')
-rw-r--r--usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c414
1 files changed, 67 insertions, 347 deletions
diff --git a/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c b/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c
index 0783ae509b..0099600ec3 100644
--- a/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c
+++ b/usr/src/cmd/cmd-inet/sbin/dhcpagent/dlpi_io.c
@@ -29,238 +29,85 @@
#include <sys/types.h>
#include <sys/pfmod.h>
#include <sys/socket.h>
-#include <net/if.h> /* IFNAMSIZ */
#include <netinet/in.h> /* in_addr (ip.h) */
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <stropts.h>
#include <string.h> /* strpbrk */
-#include <fcntl.h>
-#include <unistd.h>
#include <sys/uio.h>
-#include <sys/dlpi.h>
-#include <unistd.h>
#include <stdlib.h>
#include <dhcpmsg.h>
-#include <libinetutil.h>
-#include "dlprims.h"
#include "dlpi_io.h"
#include "v4_sum_impl.h"
+#include "common.h"
/*
- * dhcp_dlpi_open(): opens a DLPI stream to the given interface and returns
- * information purpose about that interface.
- *
- * input: const char *: the name of the interface to open
- * dl_info_ack_t *: a place to store information about the interface
- * size_t: the size of dl_info_ack_t
- * t_uscalar_t: the sap to bind to on this interface
- * output: int: the open file descriptor on success, -1 on failure
+ * timeout to wait for acknowledgement of packet filter, in seconds.
*/
-
-int
-dhcp_dlpi_open(const char *if_name, dl_info_ack_t *dlia, size_t dlia_size,
- t_uscalar_t dl_sap)
-{
- char device_name[sizeof ("/dev/") + IFNAMSIZ];
- int fd;
- ifspec_t ifsp;
- int is_style2 = 0;
-
- if (!ifparse_ifspec(if_name, &ifsp)) {
- dhcpmsg(MSG_ERROR, "dhcp_dlpi_open: invalid interface name");
- return (-1);
- }
-
- if (ifsp.ifsp_modcnt != 0) {
- dhcpmsg(MSG_ERROR, "dhcp_dlpi_open: modules cannot be "
- "specified with an interface name");
- return (-1);
- }
-
- /* try dlpi style1 interface first; if it fails, try style 2 */
- (void) snprintf(device_name, sizeof (device_name),
- "/dev/%s%d", ifsp.ifsp_devnm, ifsp.ifsp_ppa);
- if ((fd = open(device_name, O_RDWR)) == -1) {
- dhcpmsg(MSG_DEBUG, "dhcp_dlpi_open: open on `%s'", device_name);
-
- /* try style 2 interface */
- (void) snprintf(device_name, sizeof (device_name),
- "/dev/%s", ifsp.ifsp_devnm);
- fd = open(device_name, O_RDWR);
-
- /*
- * temporary hack: if the style-2 open of the /dev link fails,
- * try the corresponding /devices/pseudo path. this allows a
- * diskless boot to succeed without necessarily pre-creating the
- * /dev links, by taking advantage of devfs's ability to create
- * /devices nodes for h/w devices on demand. this is to avoid
- * the need to fiddle with packaging scripts to boot off a new
- * NIC device. when /dev links are created on demand, this
- * work-around may be removed.
- */
-
- {
- const char prefix[] = "/devices/pseudo/clone@0:";
- char path[sizeof (prefix) + IFNAMSIZ];
- if (fd == -1 && errno == ENOENT) {
- (void) snprintf(path, sizeof (path), "%s%s",
- prefix, ifsp.ifsp_devnm);
- fd = open(path, O_RDWR);
- }
- }
-
- if (fd == -1) {
- dhcpmsg(MSG_ERR, "dhcp_dlpi_open: open on `%s'",
- device_name);
- return (-1);
- }
- is_style2 = 1;
- }
-
- /*
- * okay, so we've got an open DLPI stream now. make sure that
- * it's DL_VERSION_2, DL_STYLE2, and that it's connectionless.
- * from there, attach to the appropriate ppa, bind to dl_sap,
- * and get ready to roll.
- */
-
- if (dlinforeq(fd, dlia, dlia_size) != 0) {
- dhcpmsg(MSG_ERR, "dhcp_dlpi_open: DL_INFO_REQ on %s (1)",
- device_name);
- (void) close(fd);
- return (-1);
- }
-
- if (dlia->dl_version != DL_VERSION_2) {
- dhcpmsg(MSG_ERROR, "dhcp_dlpi_open: %s is DLPI version %ld, "
- "not 2", device_name, dlia->dl_version);
- (void) close(fd);
- return (-1);
- }
-
- if (is_style2 && dlia->dl_provider_style != DL_STYLE2) {
- dhcpmsg(MSG_ERROR,
- "dhcp_dlpi_open: %s is DL_STYLE %lx, not DL_STYLE2",
- device_name, dlia->dl_provider_style);
- (void) close(fd);
- return (-1);
- }
-
- if ((dlia->dl_service_mode & DL_CLDLS) == 0) {
- dhcpmsg(MSG_ERROR, "dhcp_dlpi_open: %s is %#lx, not DL_CLDLS, "
- "which is not supported", device_name,
- dlia->dl_service_mode);
- (void) close(fd);
- return (-1);
- }
-
- if (is_style2 && dlattachreq(fd, ifsp.ifsp_ppa) == -1) {
- dhcpmsg(MSG_ERR, "dhcp_dlpi_open: DL_ATTACH_REQ on %s",
- device_name);
- (void) close(fd);
- return (-1);
- }
-
- if (dlbindreq(fd, dl_sap, 0, DL_CLDLS, 0) == -1) {
- dhcpmsg(MSG_ERR, "dhcp_dlpi_open: DL_BIND_REQ on %s",
- device_name);
- (void) close(fd);
- return (-1);
- }
-
- /*
- * we call this again since some of the information obtained
- * previously was not valid since we had not yet attached (in
- * particular, our MAC address) (but we needed to check the
- * STYLE before we did the attach)
- */
-
- if (dlinforeq(fd, dlia, dlia_size) != 0) {
- dhcpmsg(MSG_ERR, "dhcp_dlpi_open: DL_INFO_REQ on %s (2)",
- device_name);
- (void) close(fd);
- return (-1);
- }
-
- if (ioctl(fd, I_PUSH, "pfmod") == -1) {
- dhcpmsg(MSG_ERR, "dhcp_dlpi_open: cannot push pfmod on stream");
- (void) close(fd);
- return (-1);
- }
-
- (void) ioctl(fd, I_FLUSH, FLUSHR);
- return (fd);
-}
-
-/*
- * dhcp_dlpi_close(): closes a previously opened DLPI stream
- *
- * input: int: the file descriptor of the DLPI stream
- * output: int: 0 on success, -1 on failure
- */
-
-int
-dhcp_dlpi_close(int fd)
-{
- /* don't bother dismantling. it will happen automatically */
- return (close(fd));
-}
+#define FILTER_TIMEOUT 5
/*
* dlpi_recvfrom(): receives data on a DLPI stream
*
- * input: int: the socket to receive the data on
+ * input: dlpi_handle_t: dlpi handle to receive the data on
* void *: a buffer to store the data in
* size_t: the size of the buffer
* struct sockaddr_in *: if non-NULL, sender's IP address is filled in
* struct sockaddr_in *: if non-NULL, recipient's IP address
* output: ssize_t: the number of bytes read on success, -1 on failure
*/
-
ssize_t
-dlpi_recvfrom(int fd, void *buffer, size_t buf_len, struct sockaddr_in *from,
- struct sockaddr_in *to)
+dlpi_recvfrom(dlpi_handle_t dh, void *buf, size_t buflen,
+ struct sockaddr_in *from, struct sockaddr_in *to)
{
struct ip *ip;
struct udphdr *udphdr;
- void *data_buffer;
- ssize_t data_length;
+ void *msgbuf;
+ size_t msglen;
+ dlpi_recvinfo_t dlrecv;
+ int rc;
- data_length = buf_len + sizeof (struct ip) + sizeof (struct udphdr);
- data_buffer = malloc(data_length);
+ msglen = buflen + sizeof (struct ip) + sizeof (struct udphdr);
+ msgbuf = malloc(msglen);
- if (data_buffer == NULL) {
+ if (msgbuf == NULL) {
dhcpmsg(MSG_ERR, "dlpi_recvfrom: cannot allocate packet");
return (-1);
}
- data_length = dlpi_recv_link(fd, data_buffer, data_length, 0);
- if (data_length == -1)
+ rc = dlpi_recv(dh, NULL, NULL, msgbuf, &msglen, -1, &dlrecv);
+ if (rc != DLPI_SUCCESS) {
+ dhcpmsg(MSG_ERR, "dlpi_recvfrom: dlpi_recv failed: %s",
+ dlpi_strerror(rc));
+ free(msgbuf);
return (-1);
+ }
/*
* since we're just pulling data off the wire, what we have
* may look nothing like a DHCP packet. note that this
* shouldn't happen (pfmod should have tossed it already).
*/
-
- if (data_length < sizeof (struct ip) + sizeof (struct udphdr)) {
+ if (msglen < sizeof (struct ip) + sizeof (struct udphdr)) {
dhcpmsg(MSG_WARNING, "dlpi_recvfrom: dropped short packet");
- free(data_buffer);
+ free(msgbuf);
return (-1);
}
+ if (msglen < dlrecv.dri_totmsglen) {
+ dhcpmsg(MSG_WARNING, "dlpi_recvfrom: discarding stray "
+ "data on streamhead");
+ }
+
/*
* verify checksums
*/
-
- ip = (struct ip *)data_buffer;
+ ip = msgbuf;
if (ipv4cksum((uint16_t *)ip, ip->ip_hl << 2) != 0) {
dhcpmsg(MSG_WARNING, "dlpi_recvfrom: dropped packet with bad "
"ipv4 checksum");
- free(data_buffer);
+ free(msgbuf);
return (-1);
}
@@ -269,12 +116,12 @@ dlpi_recvfrom(int fd, void *buffer, size_t buf_len, struct sockaddr_in *from,
(udp_chksum(udphdr, &ip->ip_src, &ip->ip_dst, ip->ip_p) != 0)) {
dhcpmsg(MSG_WARNING, "dlpi_recvfrom: dropped packet with bad "
"UDP checksum");
- free(data_buffer);
+ free(msgbuf);
return (-1);
}
- data_length -= (sizeof (struct ip) + sizeof (struct udphdr));
- (void) memcpy(buffer, &udphdr[1], data_length);
+ msglen -= (sizeof (struct ip) + sizeof (struct udphdr));
+ (void) memcpy(buf, &udphdr[1], msglen);
if (from != NULL) {
from->sin_family = AF_INET;
@@ -288,62 +135,14 @@ dlpi_recvfrom(int fd, void *buffer, size_t buf_len, struct sockaddr_in *from,
to->sin_port = udphdr->uh_dport;
}
- free(data_buffer);
- return (data_length);
+ free(msgbuf);
+ return (msglen);
}
/*
- * dlpi_recv_link(): receives raw data on a DLPI stream
- *
- * input: int: the DLPI stream to receive the data on
- * void *: a buffer to store the data in
- * size_t: the size of the buffer
- * uint32_t: flags (see dlpi_io.h)
- * output: ssize_t: the number of bytes received on success, -1 on failure
- */
-
-ssize_t
-dlpi_recv_link(int fd, void *data_buffer, size_t data_length, uint32_t flags)
-{
- int getmsg_flags = 0;
- struct strbuf ctrl, data;
- char ctrlbuf[1024];
-
- ctrl.maxlen = sizeof (ctrlbuf);
- ctrl.buf = ctrlbuf;
-
- data.maxlen = data_length;
- data.buf = data_buffer;
-
- switch (getmsg(fd, &ctrl, &data, &getmsg_flags)) {
-
- case MORECTL:
- case MOREDATA:
- case MOREDATA|MORECTL:
-
- (void) ioctl(fd, I_FLUSH, FLUSHR);
-
- if ((flags & DLPI_RECV_SHORT) == 0)
- dhcpmsg(MSG_WARNING, "dlpi_recv_link: discarding stray "
- "data on streamhead");
- break;
-
- case -1:
- dhcpmsg(MSG_ERR, "dlpi_recv_link: getmsg");
- return (-1);
-
- default:
- break;
- }
-
- return (data.len);
-}
-
-
-/*
* dlpi_sendto(): sends UDP packets on a DLPI stream
*
- * input: int: the socket to send the packet on
+ * input: dlpi_handle_t: dlpi handle to send the packet on
* void *: a buffer to send
* size_t: the size of the buffer
* struct sockaddr_in *: the IP address to send the data to
@@ -351,16 +150,16 @@ dlpi_recv_link(int fd, void *data_buffer, size_t data_length, uint32_t flags)
* size_t: the size of the link-layer destination address
* output: ssize_t: the number of bytes sent on success, -1 on failure
*/
-
ssize_t
-dlpi_sendto(int fd, void *buffer, size_t buf_len, struct sockaddr_in *to,
- uchar_t *dl_to, size_t dl_to_len)
+dlpi_sendto(dlpi_handle_t dh, void *buf, size_t buflen,
+ struct sockaddr_in *to, uchar_t *dl_to, size_t dl_to_len)
{
struct ip *ip;
struct udphdr *udphdr;
- void *data_buffer;
- size_t data_length;
+ void *msgbuf;
+ size_t msglen;
static uint16_t ip_id = 0;
+ int rc;
/*
* TODO: someday we might want to support `to' not being
@@ -368,7 +167,6 @@ dlpi_sendto(int fd, void *buffer, size_t buf_len, struct sockaddr_in *to,
* right now, but it's annoying to have a general interface
* that only supports a specific function.
*/
-
if (to->sin_addr.s_addr != htonl(INADDR_BROADCAST)) {
dhcpmsg(MSG_ERROR, "dlpi_sendto: send to unicast address");
return (-1);
@@ -378,18 +176,17 @@ dlpi_sendto(int fd, void *buffer, size_t buf_len, struct sockaddr_in *to,
* we allocate one extra byte here in case the UDP checksum
* routine needs it to get the packet length to be even.
*/
-
- data_length = sizeof (struct ip) + sizeof (struct udphdr) + buf_len;
- data_buffer = calloc(1, data_length + 1);
- if (data_buffer == NULL) {
+ msglen = sizeof (struct ip) + sizeof (struct udphdr) + buflen;
+ msgbuf = calloc(1, msglen + 1);
+ if (msgbuf == NULL) {
dhcpmsg(MSG_ERR, "dlpi_sendto: cannot allocate packet");
return (-1);
}
- ip = (struct ip *)data_buffer;
+ ip = (struct ip *)msgbuf;
udphdr = (struct udphdr *)&ip[1];
- (void) memcpy(&udphdr[1], buffer, buf_len);
+ (void) memcpy(&udphdr[1], buf, buflen);
/*
* build the ipv4 header. assume that our source address is 0
@@ -414,97 +211,56 @@ dlpi_sendto(int fd, void *buffer, size_t buf_len, struct sockaddr_in *to,
ip->ip_id = htons(ip_id++);
ip->ip_off = htons(IP_DF);
ip->ip_p = IPPROTO_UDP;
- ip->ip_len = htons(data_length);
+ ip->ip_len = htons(msglen);
ip->ip_dst = to->sin_addr;
ip->ip_src.s_addr = htonl(INADDR_ANY);
ip->ip_sum = ipv4cksum((uint16_t *)ip, sizeof (struct ip));
- udphdr->uh_ulen = htons(sizeof (struct udphdr) + buf_len);
+ udphdr->uh_ulen = htons(sizeof (struct udphdr) + buflen);
udphdr->uh_sport = htons(IPPORT_BOOTPC);
udphdr->uh_dport = htons(IPPORT_BOOTPS);
udphdr->uh_sum = udp_chksum(udphdr, &ip->ip_src, &ip->ip_dst, ip->ip_p);
- if (dlpi_send_link(fd, data_buffer, data_length, dl_to, dl_to_len)
- == -1) {
- free(data_buffer);
- dhcpmsg(MSG_ERR, "dlpi_sendto: dlpi_send_link");
- return (-1);
- }
-
- free(data_buffer);
- return (buf_len);
-}
-
-/*
- * dlpi_send_link(): sends raw data down a DLPI stream
- *
- * input: int: the DLPI stream to send the data on
- * void *: the raw data to send
- * size_t: the size of the raw data
- * uchar_t *: the link-layer destination address
- * size_t: the size of the link-layer destination address
- * output: ssize_t: 0 on success, -1 on failure
- */
-
-ssize_t
-dlpi_send_link(int fd, void *data_buffer, size_t data_length,
- uchar_t *dest_addr, size_t dest_addr_length)
-{
- struct strbuf ctrl, data;
- ssize_t retval;
- dl_unitdata_req_t *dl_req;
-
- /*
- * allocate the control part of the message and fill it in.
- * all we really indicate is the destination address
- */
-
- dl_req = malloc(sizeof (dl_unitdata_req_t) + data_length);
- if (dl_req == NULL) {
- dhcpmsg(MSG_ERR, "dlpi_send_link: dl_unitdata_req allocation");
+ rc = dlpi_send(dh, dl_to, dl_to_len, msgbuf, msglen, NULL);
+ if (rc != DLPI_SUCCESS) {
+ free(msgbuf);
+ dhcpmsg(MSG_ERR, "dlpi_sendto: dlpi_send: %s",
+ dlpi_strerror(rc));
return (-1);
}
- ctrl.len = sizeof (dl_unitdata_req_t) + data_length;
- ctrl.buf = (caddr_t)dl_req;
-
- data.len = data_length;
- data.buf = data_buffer;
-
- dl_req->dl_primitive = DL_UNITDATA_REQ;
- dl_req->dl_priority.dl_min = 0;
- dl_req->dl_priority.dl_max = 0;
- dl_req->dl_dest_addr_offset = sizeof (dl_unitdata_req_t);
- dl_req->dl_dest_addr_length = dest_addr_length;
- (void) memcpy(&dl_req[1], dest_addr, dest_addr_length);
-
- retval = putmsg(fd, &ctrl, &data, 0);
- free(dl_req);
- return (retval);
+ free(msgbuf);
+ return (buflen);
}
/*
* set_packet_filter(): sets the current packet filter on a DLPI stream
*
- * input: int: the DLPI stream to set the packet filter on
+ * input: dlpi_handle_t: the DLPI handle to set the packet filter on
* filter_func_t *: the filter to use
* void *: an argument to pass to the filter function
* const char *: a text description of the filter's purpose
- * output: void
+ * output: boolean_t: B_TRUE on success, B_FALSE on failure.
*/
-
-void
-set_packet_filter(int fd, filter_func_t *filter, void *arg,
+boolean_t
+set_packet_filter(dlpi_handle_t dh, filter_func_t *filter, void *arg,
const char *filter_name)
{
struct strioctl sioc;
struct packetfilt pf;
ushort_t *pfp = pf.Pf_Filter;
+ int fd = dlpi_fd(dh);
+
+ if (ioctl(fd, I_PUSH, "pfmod") == -1) {
+ dhcpmsg(MSG_ERR,
+ "open_dlpi_pif: cannot push pfmod on stream");
+ return (B_FALSE);
+ }
pf.Pf_FilterLen = filter(pfp, arg) - pf.Pf_Filter;
sioc.ic_cmd = PFIOCSETF;
- sioc.ic_timout = DLPI_TIMEOUT;
+ sioc.ic_timout = FILTER_TIMEOUT;
sioc.ic_len = sizeof (struct packetfilt);
sioc.ic_dp = (caddr_t)&pf;
@@ -525,6 +281,8 @@ set_packet_filter(int fd, filter_func_t *filter, void *arg,
*/
(void) ioctl(fd, I_FLUSH, FLUSHR);
+
+ return (B_TRUE);
}
/*
@@ -583,41 +341,3 @@ dhcp_filter(ushort_t *pfp, void *arg)
return (pfp);
}
-
-/*
- * build_broadcast_dest(): builds a DLPI destination address for the broadcast
- * address for use in DL_UNITDATA_REQs
- *
- * input: dl_info_ack_t *: information about the interface
- * uchar_t *: set to the length of the returned address
- * output: uchar_t *: the broadcast address (dynamically allocated)
- */
-
-uchar_t *
-build_broadcast_dest(dl_info_ack_t *dlia, uchar_t *length)
-{
- uchar_t sap_len = abs(dlia->dl_sap_length);
- caddr_t dl_sap;
- uchar_t *dest_addr;
-
- *length = dlia->dl_brdcst_addr_length + sap_len;
- dest_addr = malloc(*length);
- if (dest_addr == NULL)
- return (NULL);
-
- if (dlia->dl_sap_length > 0) { /* sap before */
- dl_sap = (caddr_t)dlia + dlia->dl_addr_offset;
- (void) memcpy(dest_addr, dl_sap, sap_len);
- (void) memcpy(dest_addr + sap_len, (caddr_t)dlia +
- dlia->dl_brdcst_addr_offset, dlia->dl_brdcst_addr_length);
- } else {
- dl_sap = (caddr_t)dlia + dlia->dl_addr_offset +
- (dlia->dl_addr_length - sap_len);
- (void) memcpy(dest_addr, (caddr_t)dlia +
- dlia->dl_brdcst_addr_offset, dlia->dl_brdcst_addr_length);
- (void) memcpy(dest_addr + dlia->dl_brdcst_addr_length,
- dl_sap, sap_len);
- }
-
- return (dest_addr);
-}