netdev: Do not modify the caller's buffer in netdev_send().
authorBen Pfaff <blp@nicira.com>
Mon, 14 Jul 2008 20:03:09 +0000 (13:03 -0700)
committerBen Pfaff <blp@nicira.com>
Fri, 18 Jul 2008 20:42:38 +0000 (13:42 -0700)
This makes it possible to use a buffer whose contents are stack-allocated.

include/netdev.h
lib/netdev.c

index b90d34b..06476e2 100644 (file)
@@ -57,7 +57,7 @@ int netdev_open(const char *name, struct netdev **);
 void netdev_close(struct netdev *);
 int netdev_recv(struct netdev *, struct buffer *);
 void netdev_recv_wait(struct netdev *);
-int netdev_send(struct netdev *, struct buffer *);
+int netdev_send(struct netdev *, const struct buffer *);
 const uint8_t *netdev_get_etheraddr(const struct netdev *);
 const char *netdev_get_name(const struct netdev *);
 int netdev_get_mtu(const struct netdev *);
index 7750826..4359239 100644 (file)
@@ -426,29 +426,30 @@ netdev_recv_wait(struct netdev *netdev)
 /* Sends 'buffer' on 'netdev'.  Returns 0 if successful, otherwise a positive
  * errno value.  Returns EAGAIN without blocking if the packet cannot be queued
  * immediately.  Returns EMSGSIZE if a partial packet was transmitted or if
- * the packet is too big to transmit on the device.
+ * the packet is too big or too small to transmit on the device.
+ *
+ * The caller retains ownership of 'buffer' in all cases.
  *
  * The kernel maintains a packet transmission queue, so the caller is not
  * expected to do additional queuing of packets. */
 int
-netdev_send(struct netdev *netdev, struct buffer *buffer)
+netdev_send(struct netdev *netdev, const struct buffer *buffer)
 {
     ssize_t n_bytes;
     const struct eth_header *eh;
     struct sockaddr_pkt spkt;
 
-    /* Ensure packet is long enough.  (Although all incoming packets are at
-     * least ETH_TOTAL_MIN bytes long, we could have trimmed some data off a
-     * minimum-size packet, e.g. by dropping a vlan header.)
-     *
-     * The kernel does not require this, but it ensures that we always access
-     * valid memory in grabbing the sockaddr below. */
-    pad_to_minimum_length(buffer);
+    /* Pull out the Ethernet header. */
+    if (buffer->size < ETH_HEADER_LEN) {
+        VLOG_WARN("cannot send %zu-byte frame on %s",
+                  buffer->size, netdev->name);
+        return EMSGSIZE;
+    }
+    eh = buffer_at_assert(buffer, 0, sizeof *eh);
 
     /* Construct packet sockaddr, which SOCK_PACKET requires. */
     spkt.spkt_family = AF_PACKET;
     strncpy((char *) spkt.spkt_device, netdev->name, sizeof spkt.spkt_device);
-    eh = buffer_at_assert(buffer, 0, sizeof *eh);
     spkt.spkt_protocol = eh->eth_type;
 
     do {