Exemple #1
0
int dsr_hw_header_create(struct dsr_pkt *dp, struct sk_buff *skb)
{

	struct sockaddr broadcast =
	    { AF_UNSPEC, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} };
	struct neighbor_info neigh_info;

	if (dp->dst.s_addr == DSR_BROADCAST)
		memcpy(neigh_info.hw_addr.sa_data, broadcast.sa_data, ETH_ALEN);
	else {
		/* Get hardware destination address */
		if (neigh_tbl_query(dp->nxt_hop, &neigh_info) < 0) {
			DEBUG
			    ("Could not get hardware address for next hop %s\n",
			     print_ip(dp->nxt_hop));
			return -1;
		}
	}

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
	if (skb->dev->hard_header) {
		skb->dev->hard_header(skb, skb->dev, ETH_P_IP,
				      neigh_info.hw_addr.sa_data, 0, skb->len);
	} else {
		DEBUG("Missing hard_header\n");
		return -1;
	}
#else
	dev_hard_header(skb, skb->dev, ETH_P_IP,
			neigh_info.hw_addr.sa_data, 0, skb->len);	
#endif
	return 0;
}
/* DOWNSTACK: MASTER FUNCTION CALLED BY L3
 * analagous to ip_output and ip_finish_output{2}
 * they then call the equivalent of neigh_connected_output
 * A LOT of arp shit happens here too!
 * for reference: Figure 27.13
 */
int mhost_finish_output(struct sk_buff *skb, struct net_device *dev, const void *daddr)
{
    int err = 0;
    
    // printk(KERN_INFO "mhost_finish_output called\n");
    
    /* set device-specific header here... */
    skb->protocol = htons(ETH_P_MHOST);
    skb->dev = dev;
    err = dev_hard_header(skb, dev, ntohs(skb->protocol),
                          daddr, NULL, skb->len);
    
    /* ...and ship off to the device driver! */
    if (err >= 0) {
        err = dev_queue_xmit(skb);
        if (err < 0) {
            printk(KERN_INFO "error: dev_queue_xmit!\n");
        }
    }
    else {
        printk(KERN_INFO "error: dev_hard_header returned %d\n", err);
        err = -EINVAL;
        kfree_skb(skb);
    }
    return err;
}
Exemple #3
0
/**
 * tipc_l2_send_msg - send a TIPC packet out over an L2 interface
 * @buf: the packet to be sent
 * @b_ptr: the bearer through which the packet is to be sent
 * @dest: peer destination address
 */
int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
		     struct tipc_media_addr *dest)
{
	struct sk_buff *clone;
	struct net_device *dev;
	int delta;

	dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
	if (!dev)
		return 0;

	clone = skb_clone(buf, GFP_ATOMIC);
	if (!clone)
		return 0;

	delta = dev->hard_header_len - skb_headroom(buf);
	if ((delta > 0) &&
	    pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
		kfree_skb(clone);
		return 0;
	}

	skb_reset_network_header(clone);
	clone->dev = dev;
	clone->protocol = htons(ETH_P_TIPC);
	dev_hard_header(clone, dev, ETH_P_TIPC, dest->value,
			dev->dev_addr, clone->len);
	dev_queue_xmit(clone);
	return 0;
}
Exemple #4
0
/**
 * tipc_l2_send_msg - send a TIPC packet out over an L2 interface
 * @skb: the packet to be sent
 * @b: the bearer through which the packet is to be sent
 * @dest: peer destination address
 */
int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
		     struct tipc_bearer *b, struct tipc_media_addr *dest)
{
	struct net_device *dev;
	int delta;
	void *tipc_ptr;

	dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
	if (!dev)
		return 0;

	/* Send RESET message even if bearer is detached from device */
	tipc_ptr = rcu_dereference_rtnl(dev->tipc_ptr);
	if (unlikely(!tipc_ptr && !msg_is_reset(buf_msg(skb))))
		goto drop;

	delta = dev->hard_header_len - skb_headroom(skb);
	if ((delta > 0) &&
	    pskb_expand_head(skb, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC))
		goto drop;

	skb_reset_network_header(skb);
	skb->dev = dev;
	skb->protocol = htons(ETH_P_TIPC);
	dev_hard_header(skb, dev, ETH_P_TIPC, dest->value,
			dev->dev_addr, skb->len);
	dev_queue_xmit(skb);
	return 0;
drop:
	kfree_skb(skb);
	return 0;
}
Exemple #5
0
/**
 * send_msg - send a TIPC message out over an InfiniBand interface
 */
static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
                    struct tipc_media_addr *dest)
{
    struct sk_buff *clone;
    struct net_device *dev;
    int delta;

    clone = skb_clone(buf, GFP_ATOMIC);
    if (!clone)
        return 0;

    dev = ((struct ib_bearer *)(tb_ptr->usr_handle))->dev;
    delta = dev->hard_header_len - skb_headroom(buf);

    if ((delta > 0) &&
            pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
        kfree_skb(clone);
        return 0;
    }

    skb_reset_network_header(clone);
    clone->dev = dev;
    clone->protocol = htons(ETH_P_TIPC);
    dev_hard_header(clone, dev, ETH_P_TIPC, dest->value,
                    dev->dev_addr, clone->len);
    dev_queue_xmit(clone);
    return 0;
}
Exemple #6
0
static int p8023_request(struct datalink_proto *dl,
			 struct sk_buff *skb, unsigned char *dest_node)
{
	struct net_device *dev = skb->dev;

	dev_hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len);
	return dev_queue_xmit(skb);
}
/*
 * Prepends an ISI header and sends a datagram.
 */
static int pn_send(struct sk_buff *skb, struct net_device *dev,
                   u16 dst, u16 src, u8 res, u8 irq)
{
    struct phonethdr *ph;
    int err;

    if (skb->len + 2 > 0xffff /* Phonet length field limit */ ||
            skb->len + sizeof(struct phonethdr) > dev->mtu) {
        err = -EMSGSIZE;
        goto drop;
    }

    /* Broadcast sending is not implemented */
    if (pn_addr(dst) == PNADDR_BROADCAST) {
        err = -EOPNOTSUPP;
        goto drop;
    }

    skb_reset_transport_header(skb);
    WARN_ON(skb_headroom(skb) & 1); /* HW assumes word alignment */
    skb_push(skb, sizeof(struct phonethdr));
    skb_reset_network_header(skb);
    ph = pn_hdr(skb);
    ph->pn_rdev = pn_dev(dst);
    ph->pn_sdev = pn_dev(src);
    ph->pn_res = res;
    ph->pn_length = __cpu_to_be16(skb->len + 2 - sizeof(*ph));
    ph->pn_robj = pn_obj(dst);
    ph->pn_sobj = pn_obj(src);

    skb->protocol = htons(ETH_P_PHONET);
    skb->priority = 0;
    skb->dev = dev;

    if (pn_addr(src) == pn_addr(dst)) {
        skb_reset_mac_header(skb);
        skb->pkt_type = PACKET_LOOPBACK;
        skb_orphan(skb);
        if (irq)
            netif_rx(skb);
        else
            netif_rx_ni(skb);
        err = 0;
    } else {
        err = dev_hard_header(skb, dev, ntohs(skb->protocol),
                              NULL, NULL, skb->len);
        if (err < 0) {
            err = -EHOSTUNREACH;
            goto drop;
        }
        err = dev_queue_xmit(skb);
    }

    return err;
drop:
    kfree_skb(skb);
    return err;
}
Exemple #8
0
static int pEII_request(struct datalink_proto *dl,
			struct sk_buff *skb, unsigned char *dest_node)
{
	struct net_device *dev = skb->dev;

	skb->protocol = htons(ETH_P_IPX);
	dev_hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len);
	return dev_queue_xmit(skb);
}
Exemple #9
0
static void send_hsr_supervision_frame(struct net_device *hsr_dev, u8 type)
{
	struct hsr_priv *hsr_priv;
	struct sk_buff *skb;
	int hlen, tlen;
	struct hsr_sup_tag *hsr_stag;
	struct hsr_sup_payload *hsr_sp;
	unsigned long irqflags;

	hlen = LL_RESERVED_SPACE(hsr_dev);
	tlen = hsr_dev->needed_tailroom;
	skb = alloc_skb(hsr_pad(sizeof(struct hsr_sup_payload)) + hlen + tlen,
			GFP_ATOMIC);

	if (skb == NULL)
		return;

	hsr_priv = netdev_priv(hsr_dev);

	skb_reserve(skb, hlen);

	skb->dev = hsr_dev;
	skb->protocol = htons(ETH_P_PRP);
	skb->priority = TC_PRIO_CONTROL;

	if (dev_hard_header(skb, skb->dev, ETH_P_PRP,
			    hsr_priv->sup_multicast_addr,
			    skb->dev->dev_addr, skb->len) < 0)
		goto out;

	skb_pull(skb, sizeof(struct ethhdr));
	hsr_stag = (typeof(hsr_stag)) skb->data;

	set_hsr_stag_path(hsr_stag, 0xf);
	set_hsr_stag_HSR_Ver(hsr_stag, 0);

	spin_lock_irqsave(&hsr_priv->seqnr_lock, irqflags);
	hsr_stag->sequence_nr = htons(hsr_priv->sequence_nr);
	hsr_priv->sequence_nr++;
	spin_unlock_irqrestore(&hsr_priv->seqnr_lock, irqflags);

	hsr_stag->HSR_TLV_Type = type;
	hsr_stag->HSR_TLV_Length = 12;

	skb_push(skb, sizeof(struct ethhdr));

	/* Payload: MacAddressA */
	hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(*hsr_sp));
	ether_addr_copy(hsr_sp->MacAddressA, hsr_dev->dev_addr);

	dev_queue_xmit(skb);
	return;

out:
	kfree_skb(skb);
}
Exemple #10
0
int virt_send_ack(struct virt_priv *virt, struct device_node *slave, 
        struct remote_link *link)
{
    struct sk_buff *skb;
    struct net_device *dev = slave->dev;
    struct tunhdr *tunhdr;
    struct pathinfo *path;
    __be16 sport;

    unsigned alloc_size = sizeof(struct tunhdr) + sizeof(struct udphdr) +
        sizeof(struct iphdr) + LL_RESERVED_SPACE(dev);

    path = lookup_pathinfo(&virt->network, slave, link);
    if(!path)
        return -EINVAL;

    skb = alloc_skb(alloc_size, GFP_ATOMIC);
    if(!skb) {
        virt_path_put(path);
        return -ENOMEM;
    }

    skb_reserve(skb, alloc_size);

    tunhdr = virt_build_tunhdr(skb, NULL, NULL);
    virt_finish_tunhdr(tunhdr, path, NULL, link->node);

    /* TODO: We may want to split traffic among different ports, which
     * may change how we send ACKs.  For now, everything uses the same
     * source port. */
    sport = htons(virt_tunnel_source_port());
    virt_build_udp_header(skb, sport, link->rif.data_port);
    virt_build_ip_header(skb, slave->lif.ip4, link->rif.ip4);

    skb->dev = dev;
    skb->protocol = htons(ETH_P_IP);

    dev_hard_header(skb, dev, ETH_P_IP, slave->next_hop_addr, dev->dev_addr, skb->len);
    skb_reset_mac_header(skb);

    /* Update link statistics -- these may not be accurate if the packet gets
     * dropped after dev_queue_xmit. */
    slave->stats.tx_packets++;
    slave->stats.tx_bytes += skb->len;

    /* Update device statistics. */
    virt->stats.tx_packets++;
    virt->stats.tx_bytes += skb->len;

    /* Decrement refcnt. */
    virt_path_put(path);

    dev_queue_xmit(skb);

    return 0;
}
static int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev,
				     unsigned short type,
				     const void *daddr, const void *saddr,
				     unsigned int len)
{
	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
	struct net_device *real_dev = vlan->real_dev;

	return dev_hard_header(skb, real_dev, type, daddr, saddr, len);
}
Exemple #12
0
static void netpoll_wrapper_send_arp_reply(struct netpoll_wrapper *pWrapper, struct queued_arp_reply *reply)
{
	int hlen, tlen;
	struct arphdr *arp;
	struct sk_buff *send_skb;
	unsigned char *arp_ptr;
	int size = arp_hdr_len(pWrapper->pDeviceWithHandler);
	hlen = LL_RESERVED_SPACE(pWrapper->pDeviceWithHandler);
	tlen = pWrapper->pDeviceWithHandler->needed_tailroom;
	send_skb = alloc_skb(size + hlen + tlen, GFP_ATOMIC);

	if (!send_skb)
		return;

	skb_reserve(send_skb, hlen);
	skb_reset_network_header(send_skb);
	arp = (struct arphdr *) skb_put(send_skb, size);
	send_skb->dev = pWrapper->pDeviceWithHandler;
	send_skb->protocol = htons(ETH_P_ARP);

	/* Fill the device header for the ARP frame */
	if (dev_hard_header(send_skb, pWrapper->pDeviceWithHandler, ETH_P_ARP,
		reply->remote_mac, pWrapper->pDeviceWithHandler->dev_addr,
		send_skb->len) < 0) 
	{
		kfree_skb(send_skb);
		return;
	}

	/*
	* Fill out the arp protocol part.
	*
	* we only support ethernet device type,
	* which (according to RFC 1390) should
	* always equal 1 (Ethernet).
	*/

	arp->ar_hrd = htons(pWrapper->pDeviceWithHandler->type);
	arp->ar_pro = htons(ETH_P_IP);
	arp->ar_hln = pWrapper->pDeviceWithHandler->addr_len;
	arp->ar_pln = 4;
	arp->ar_op = htons(ARPOP_REPLY);

	arp_ptr = (unsigned char *)(arp + 1);
	memcpy(arp_ptr, pWrapper->pDeviceWithHandler->dev_addr, pWrapper->pDeviceWithHandler->addr_len);
	arp_ptr += pWrapper->pDeviceWithHandler->addr_len;
	memcpy(arp_ptr, &reply->local_ip, 4);
	arp_ptr += 4;
	memcpy(arp_ptr, reply->remote_mac, pWrapper->pDeviceWithHandler->addr_len);
	arp_ptr += pWrapper->pDeviceWithHandler->addr_len;
	memcpy(arp_ptr, &reply->remote_ip, 4);

	netpoll_send_skb(&pWrapper->netpoll_obj, send_skb);
}
Exemple #13
0
static int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev,
				     unsigned short type,
				     const void *daddr, const void *saddr,
				     unsigned int len)
{
	struct net_device *real_dev = vlan_dev_info(dev)->real_dev;

	if (saddr == NULL)
		saddr = dev->dev_addr;

	return dev_hard_header(skb, real_dev, type, daddr, saddr, len);
}
static int ztdeth_transmit(void *pvt, unsigned char *msg, int msglen)
{
	struct ztdeth *z;
	struct sk_buff *skb;
	struct ztdeth_header *zh;
	unsigned long flags;
	struct net_device *dev;
	unsigned char addr[ETH_ALEN];
	unsigned short subaddr; /* Network byte order */

	spin_lock_irqsave(&zlock, flags);
	z = pvt;
	if (z->dev) {
		/* Copy fields to local variables to remove spinlock ASAP */
		dev = z->dev;
		memcpy(addr, z->addr, sizeof(z->addr));
		subaddr = z->subaddr;
		spin_unlock_irqrestore(&zlock, flags);
		skb = dev_alloc_skb(msglen + dev->hard_header_len + sizeof(struct ztdeth_header) + 32);
		if (skb) {
			/* Reserve header space */
			skb_reserve(skb, dev->hard_header_len + sizeof(struct ztdeth_header));

			/* Copy message body */
			memcpy(skb_put(skb, msglen), msg, msglen);

			/* Throw on header */
			zh = (struct ztdeth_header *)skb_push(skb, sizeof(struct ztdeth_header));
			zh->subaddr = subaddr;

			/* Setup protocol and such */
			skb->protocol = __constant_htons(ETH_P_DAHDI_DETH);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
			skb_set_network_header(skb, 0);
#else
			skb->nh.raw = skb->data;
#endif
			skb->dev = dev;
#if  LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
			dev_hard_header(skb, dev, ETH_P_DAHDI_DETH, addr, dev->dev_addr, skb->len);
#else
			if (dev->hard_header)
				dev->hard_header(skb, dev, ETH_P_DAHDI_DETH, addr, dev->dev_addr, skb->len);
#endif
			skb_queue_tail(&skbs, skb);
		}
	}
	else
		spin_unlock_irqrestore(&zlock, flags);
	return 0;
}
Exemple #15
0
int goose_trans_skb(struct net_device *dev, unsigned char *daddr,
					struct sk_buff *__skb, int reliablity)
{
	struct sk_buff *skb = __skb;
	unsigned int skb_pull_len = NLMSG_LENGTH(0) + sizeof(struct nl_data_header);

	if (unlikely((dev == NULL) || (!tran_active)))
		goto goose_trans_skb_fail;
	
	/* We use existing skb to form a new one:
	 *
	 * skb:
	 * old skb->data                      new skb->data
	 *   |                                  |
	 * -----------------------------------------------------------
	 *   | NLMSG_LENGTH(0) | nl_data_header | goose header | APDU
	 * -----------------------------------------------------------
	 *   | <==      skb_pull_len        ==> |
	 * 
	 */		
	skb_pull(skb, skb_pull_len);
	skb_reset_network_header(skb);

	/* But after pulling, if we have still no enough space for link-layer header,
	   we have to reconstruct a new skb */
	if ((skb->head - skb->network_header) < LL_RESERVED_SPACE(dev)) {
		skb = skb_copy_expand(__skb, LL_RESERVED_SPACE(dev), 16, GFP_ATOMIC);
		kfree_skb(__skb);
	}

	/* Specify protocol type and frame information */
	skb->dev = dev;
	skb->protocol = ETH_P_GOOSE;
	skb->pkt_type = PACKET_OUTGOING;
	skb->csum = 0;
	skb->ip_summed = 0;

	/* Set the highest priority */
	skb->priority = 0;
	
	if (unlikely(dev_hard_header(skb, dev, ETH_P_GOOSE, daddr, dev->dev_addr, skb->len) < 0))
		goto goose_trans_skb_fail;

	/* If the message should be transmitted by GOOSE Enhanced Retransmission Mechanism,
	   call goose_enhan_retrans, otherwise transmit it directly.*/
	return reliablity ? goose_enhan_retrans(skb):dev_queue_xmit(skb);
	
goose_trans_skb_fail:
	kfree_skb(skb);
	return -1;
}
/*
 *	Create the VLAN header for an arbitrary protocol layer
 *
 *	saddr=NULL	means use device source address
 *	daddr=NULL	means leave destination address (eg unresolved arp)
 *
 *  This is called when the SKB is moving down the stack towards the
 *  physical devices.
 */
static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
				unsigned short type,
				const void *daddr, const void *saddr,
				unsigned int len)
{
	struct vlan_hdr *vhdr;
	unsigned int vhdrlen = 0;
	u16 vlan_tci = 0;
	int rc;

	if (WARN_ON(skb_headroom(skb) < dev->hard_header_len))
		return -ENOSPC;

	if (!(vlan_dev_info(dev)->flags & VLAN_FLAG_REORDER_HDR)) {
		vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN);

		vlan_tci = vlan_dev_info(dev)->vlan_id;
		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
		vhdr->h_vlan_TCI = htons(vlan_tci);

		/*
		 *  Set the protocol type. For a packet of type ETH_P_802_3 we
		 *  put the length in here instead. It is up to the 802.2
		 *  layer to carry protocol information.
		 */
		if (type != ETH_P_802_3)
			vhdr->h_vlan_encapsulated_proto = htons(type);
		else
			vhdr->h_vlan_encapsulated_proto = htons(len);

		skb->protocol = htons(ETH_P_8021Q);
		type = ETH_P_8021Q;
		vhdrlen = VLAN_HLEN;
	}

	/* Before delegating work to the lower layer, enter our MAC-address */
	if (saddr == NULL)
		saddr = dev->dev_addr;

	/* Now make the underlying real hard header */
	dev = vlan_dev_info(dev)->real_dev;
	rc = dev_hard_header(skb, dev, type, daddr, saddr, len + vhdrlen);
	if (rc > 0)
		rc += vhdrlen;
	return rc;
}
Exemple #17
0
static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, 
		    struct tipc_media_addr *dest)
{
	struct sk_buff *clone;
	struct net_device *dev;

	clone = skb_clone(buf, GFP_ATOMIC);
	if (clone) {
		clone->nh.raw = clone->data;
		dev = ((struct eth_bearer *)(tb_ptr->usr_handle))->dev;
		clone->dev = dev;
		dev_hard_header(clone, dev, ETH_P_TIPC,
				 &dest->dev_addr.eth_addr,
				 dev->dev_addr, clone->len);
		dev_queue_xmit(clone);
	}
	return TIPC_OK;
}
/**
 *	llc_mac_hdr_init - fills MAC header fields
 *	@skb: Address of the frame to initialize its MAC header
 *	@sa: The MAC source address
 *	@da: The MAC destination address
 *
 *	Fills MAC header fields, depending on MAC type. Returns 0, If MAC type
 *	is a valid type and initialization completes correctly 1, otherwise.
 */
int llc_mac_hdr_init(struct sk_buff *skb,
		     unsigned char *sa, unsigned char *da)
{
	int rc = -EINVAL;

	switch (skb->dev->type) {
	case ARPHRD_ETHER:
	case ARPHRD_LOOPBACK:
		rc = dev_hard_header(skb, skb->dev, ETH_P_802_2, da, sa,
				     skb->len);
		if (rc > 0)
			rc = 0;
		break;
	default:
		WARN(1, "device type not supported: %d\n", skb->dev->type);
	}
	return rc;
}
Exemple #19
0
/**
 *	llc_mac_hdr_init - fills MAC header fields
 *	@skb: Address of the frame to initialize its MAC header
 *	@sa: The MAC source address
 *	@da: The MAC destination address
 *
 *	Fills MAC header fields, depending on MAC type. Returns 0, If MAC type
 *	is a valid type and initialization completes correctly 1, otherwise.
 */
int llc_mac_hdr_init(struct sk_buff *skb,
		     const unsigned char *sa, const unsigned char *da)
{
	int rc = -EINVAL;

	switch (skb->dev->type) {
	case ARPHRD_IEEE802_TR:
	case ARPHRD_ETHER:
	case ARPHRD_LOOPBACK:
		rc = dev_hard_header(skb, skb->dev, ETH_P_802_2, da, sa,
				     skb->len);
		if (rc > 0)
			rc = 0;
		break;
	default:
		break;
	}
	return rc;
}
Exemple #20
0
/*
 *	Create the VLAN header for an arbitrary protocol layer
 *
 *	saddr=NULL	means use device source address
 *	daddr=NULL	means leave destination address (eg unresolved arp)
 *
 *  This is called when the SKB is moving down the stack towards the
 *  physical devices.
 */
static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
				unsigned short type,
				const void *daddr, const void *saddr,
				unsigned int len)
{
	struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
	struct vlan_hdr *vhdr;
	unsigned int vhdrlen = 0;
	u16 vlan_tci = 0;
	int rc;

	if (!(vlan->flags & VLAN_FLAG_REORDER_HDR)) {
		vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN);

		vlan_tci = vlan->vlan_id;
		vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb->priority);
		vhdr->h_vlan_TCI = htons(vlan_tci);

		/*
		 *  Set the protocol type. For a packet of type ETH_P_802_3/2 we
		 *  put the length in here instead.
		 */
		if (type != ETH_P_802_3 && type != ETH_P_802_2)
			vhdr->h_vlan_encapsulated_proto = htons(type);
		else
			vhdr->h_vlan_encapsulated_proto = htons(len);

		skb->protocol = vlan->vlan_proto;
		type = ntohs(vlan->vlan_proto);
		vhdrlen = VLAN_HLEN;
	}

	/* Before delegating work to the lower layer, enter our MAC-address */
	if (saddr == NULL)
		saddr = dev->dev_addr;

	/* Now make the underlying real hard header */
	dev = vlan->real_dev;
	rc = dev_hard_header(skb, dev, type, daddr, saddr, len + vhdrlen);
	if (rc > 0)
		rc += vhdrlen;
	return rc;
}
Exemple #21
0
/**
 * tipc_l2_send_msg - send a TIPC packet out over an L2 interface
 * @skb: the packet to be sent
 * @b: the bearer through which the packet is to be sent
 * @dest: peer destination address
 */
int tipc_l2_send_msg(struct net *net, struct sk_buff *skb,
		     struct tipc_bearer *b, struct tipc_media_addr *dest)
{
	struct net_device *dev;
	int delta;

	dev = (struct net_device *)rcu_dereference_rtnl(b->media_ptr);
	if (!dev)
		return 0;

	delta = SKB_DATA_ALIGN(dev->hard_header_len - skb_headroom(skb));
	if ((delta > 0) && pskb_expand_head(skb, delta, 0, GFP_ATOMIC)) {
		kfree_skb(skb);
		return 0;
	}
	skb_reset_network_header(skb);
	skb->dev = dev;
	skb->protocol = htons(ETH_P_TIPC);
	dev_hard_header(skb, dev, ETH_P_TIPC, dest->value,
			dev->dev_addr, skb->len);
	dev_queue_xmit(skb);
	return 0;
}
Exemple #22
0
static int
__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
	       struct net_device *dev, struct netdev_queue *txq,
	       struct neighbour *mn)
{
	struct teql_sched_data *q = qdisc_priv(txq->qdisc);
	struct neighbour *n = q->ncache;

	if (mn->tbl == NULL)
		return -EINVAL;
	if (n && n->tbl == mn->tbl &&
	    memcmp(n->primary_key, mn->primary_key, mn->tbl->key_len) == 0) {
		atomic_inc(&n->refcnt);
	} else {
		n = __neigh_lookup_errno(mn->tbl, mn->primary_key, dev);
		if (IS_ERR(n))
			return PTR_ERR(n);
	}
	if (neigh_event_send(n, skb_res) == 0) {
		int err;
		char haddr[MAX_ADDR_LEN];

		neigh_ha_snapshot(haddr, n, dev);
		err = dev_hard_header(skb, dev, ntohs(skb->protocol), haddr,
				      NULL, skb->len);

		if (err < 0) {
			neigh_release(n);
			return -EINVAL;
		}
		teql_neigh_release(xchg(&q->ncache, n));
		return 0;
	}
	neigh_release(n);
	return (skb_res == NULL) ? -EAGAIN : 1;
}
Exemple #23
0
/* Send RST reply */
void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
{
	struct sk_buff *nskb;
	struct iphdr *niph;
	const struct tcphdr *oth;
	struct tcphdr _oth;

	oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook);
	if (!oth)
		return;

	if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
		return;

	nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
			 LL_MAX_HEADER, GFP_ATOMIC);
	if (!nskb)
		return;

	/* ip_route_me_harder expects skb->dst to be set */
	skb_dst_set_noref(nskb, skb_dst(oldskb));

	nskb->mark = IP4_REPLY_MARK(net, oldskb->mark);

	skb_reserve(nskb, LL_MAX_HEADER);
	niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
				   ip4_dst_hoplimit(skb_dst(nskb)));
	nf_reject_ip_tcphdr_put(nskb, oldskb, oth);

	if (ip_route_me_harder(net, nskb, RTN_UNSPEC))
		goto free_nskb;

	niph = ip_hdr(nskb);

	/* "Never happens" */
	if (nskb->len > dst_mtu(skb_dst(nskb)))
		goto free_nskb;

	nf_ct_attach(nskb, oldskb);

#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
	/* If we use ip_local_out for bridged traffic, the MAC source on
	 * the RST will be ours, instead of the destination's.  This confuses
	 * some routers/firewalls, and they drop the packet.  So we need to
	 * build the eth header using the original destination's MAC as the
	 * source, and send the RST packet directly.
	 */
	if (oldskb->nf_bridge) {
		struct ethhdr *oeth = eth_hdr(oldskb);

		nskb->dev = nf_bridge_get_physindev(oldskb);
		niph->tot_len = htons(nskb->len);
		ip_send_check(niph);
		if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
				    oeth->h_source, oeth->h_dest, nskb->len) < 0)
			goto free_nskb;
		dev_queue_xmit(nskb);
	} else
#endif
		ip_local_out(net, nskb->sk, nskb);

	return;

 free_nskb:
	kfree_skb(nskb);
}
Exemple #24
0
/*
 *    Create an arp packet. If (dest_hw == NULL), we create a broadcast
 *    message.
 */
struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
               struct net_device *dev, __be32 src_ip,
               const unsigned char *dest_hw,
               const unsigned char *src_hw,
               const unsigned char *target_hw)
{
    struct sk_buff *skb;
    struct arphdr *arp;
    unsigned char *arp_ptr;

    /*
     *    Allocate a buffer
     */

    skb = alloc_skb(arp_hdr_len(dev) + LL_ALLOCATED_SPACE(dev), GFP_ATOMIC);
    if (skb == NULL)
        return NULL;

    skb_reserve(skb, LL_RESERVED_SPACE(dev));
    skb_reset_network_header(skb);
    arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev));
    skb->dev = dev;
    skb->protocol = htons(ETH_P_ARP);
    if (src_hw == NULL)
        src_hw = dev->dev_addr;
    if (dest_hw == NULL)
        dest_hw = dev->broadcast;

    /*
     *    Fill the device header for the ARP frame
     */
    if (dev_hard_header(skb, dev, ptype, dest_hw, src_hw, skb->len) < 0)
        goto out;

    /*
     * Fill out the arp protocol part.
     *
     * The arp hardware type should match the device type, except for FDDI,
     * which (according to RFC 1390) should always equal 1 (Ethernet).
     */
    /*
     *    Exceptions everywhere. AX.25 uses the AX.25 PID value not the
     *    DIX code for the protocol. Make these device structure fields.
     */
    switch (dev->type) {
    default:
        arp->ar_hrd = htons(dev->type);
        arp->ar_pro = htons(ETH_P_IP);
        break;

#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
    case ARPHRD_AX25:
        arp->ar_hrd = htons(ARPHRD_AX25);
        arp->ar_pro = htons(AX25_P_IP);
        break;

#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
    case ARPHRD_NETROM:
        arp->ar_hrd = htons(ARPHRD_NETROM);
        arp->ar_pro = htons(AX25_P_IP);
        break;
#endif
#endif

#ifdef CONFIG_FDDI
    case ARPHRD_FDDI:
        arp->ar_hrd = htons(ARPHRD_ETHER);
        arp->ar_pro = htons(ETH_P_IP);
        break;
#endif
#ifdef CONFIG_TR
    case ARPHRD_IEEE802_TR:
        arp->ar_hrd = htons(ARPHRD_IEEE802);
        arp->ar_pro = htons(ETH_P_IP);
        break;
#endif
    }

    arp->ar_hln = dev->addr_len;
    arp->ar_pln = 4;
    arp->ar_op = htons(type);

    arp_ptr=(unsigned char *)(arp+1);

    memcpy(arp_ptr, src_hw, dev->addr_len);
    arp_ptr+=dev->addr_len;
    memcpy(arp_ptr, &src_ip,4);
    arp_ptr+=4;
    if (target_hw != NULL)
        memcpy(arp_ptr, target_hw, dev->addr_len);
    else
        memset(arp_ptr, 0, dev->addr_len);
    arp_ptr+=dev->addr_len;
    memcpy(arp_ptr, &dest_ip, 4);

    return skb;

out:
    kfree_skb(skb);
    return NULL;
}
/*
 * Stuff received packets to associated sockets.
 * On error, returns non-zero and releases the skb.
 */
static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
			struct packet_type *pkttype,
			struct net_device *orig_dev)
{
	struct net *net = dev_net(dev);
	struct phonethdr *ph;
	struct sockaddr_pn sa;
	u16 len;
	int i;

	/* check we have at least a full Phonet header */
	if (!pskb_pull(skb, sizeof(struct phonethdr)))
		goto out;

	/* check that the advertised length is correct */
	ph = pn_hdr(skb);
	len = get_unaligned_be16(&ph->pn_length);
	if (len < 2)
		goto out;
	len -= 2;
	if ((len > skb->len) || pskb_trim(skb, len))
		goto out;
	skb_reset_transport_header(skb);

	pn_skb_get_dst_sockaddr(skb, &sa);

	PN_PRINTK("PN rcv: hdr rdev %x sdev %x res %x robj %x sobj %x dev=%s\n",
		ph->pn_rdev, ph->pn_sdev, ph->pn_res,
		ph->pn_robj, ph->pn_sobj, dev->name);
	PN_DATA_PRINTK("PHONET : skb  data = %d\nPHONET :", skb->len);
	for (i = 1; i <= skb->len; i++) {
		PN_DATA_PRINTK(" %02x", skb->data[i-1]);
		if ((i%8) == 0)
			PN_DATA_PRINTK("\n");
	}

	/* check if this is multicasted */
	if (pn_sockaddr_get_object(&sa) == PNOBJECT_MULTICAST) {
		pn_deliver_sock_broadcast(net, skb);
		goto out;
	}

	/* check if this is broadcasted */
	if (pn_sockaddr_get_addr(&sa) == PNADDR_BROADCAST) {
		pn_deliver_sock_broadcast(net, skb);
		goto out;
	}

	/* resource routing */
	if (pn_sockaddr_get_object(&sa) == 0) {
		struct sock *sk = pn_find_sock_by_res(net, sa.spn_resource);
		if (sk) {
			printk(KERN_DEBUG "phonet new resource routing!\n");
			return sk_receive_skb(sk, skb, 0);
		}
	}

	/* check if we are the destination */
	if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) {
		/* Phonet packet input */
/*!*/		struct sock *sk = pn_find_sock_by_sa_and_skb(net, &sa, skb);
		/*struct sock *sk = pn_find_sock_by_sa(net, &sa);*/

		if (sk)
			return sk_receive_skb(sk, skb, 0);

		if (can_respond(skb)) {
			send_obj_unreachable(skb);
			send_reset_indications(skb);
		}
	} else if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
		goto out; /* Race between address deletion and loopback */
	else {
		/* Phonet packet routing */
		struct net_device *out_dev;

		out_dev = phonet_route_output(net, pn_sockaddr_get_addr(&sa));
		if (!out_dev) {
			LIMIT_NETDEBUG(KERN_WARNING"No Phonet route to %02X\n",
					pn_sockaddr_get_addr(&sa));
			goto out;
		}

		__skb_push(skb, sizeof(struct phonethdr));
		skb->dev = out_dev;
		if (out_dev == dev) {
			LIMIT_NETDEBUG(KERN_ERR"Phonet loop to %02X on %s\n",
					pn_sockaddr_get_addr(&sa), dev->name);
			goto out_dev;
		}
		/* Some drivers (e.g. TUN) do not allocate HW header space */
		if (skb_cow_head(skb, out_dev->hard_header_len))
			goto out_dev;

		if (dev_hard_header(skb, out_dev, ETH_P_PHONET, NULL, NULL,
					skb->len) < 0)
			goto out_dev;
		dev_queue_xmit(skb);
		dev_put(out_dev);
		return NET_RX_SUCCESS;
out_dev:
		dev_put(out_dev);
	}

out:
	kfree_skb(skb);
	printk(KERN_DEBUG "phonet_rcv Drop message!\n");
	return NET_RX_DROP;
}
Exemple #26
0
struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
			   struct net_device *dev, __be32 src_ip,
			   const unsigned char *dest_hw,
			   const unsigned char *src_hw,
			   const unsigned char *target_hw)
{
	struct sk_buff *skb;
	struct arphdr *arp;
	unsigned char *arp_ptr;
	int hlen = LL_RESERVED_SPACE(dev);
	int tlen = dev->needed_tailroom;


	skb = alloc_skb(arp_hdr_len(dev) + hlen + tlen, GFP_ATOMIC);
	if (skb == NULL)
		return NULL;

	skb_reserve(skb, hlen);
	skb_reset_network_header(skb);
	arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev));
	skb->dev = dev;
	skb->protocol = htons(ETH_P_ARP);
	if (src_hw == NULL)
		src_hw = dev->dev_addr;
	if (dest_hw == NULL)
		dest_hw = dev->broadcast;

	if (dev_hard_header(skb, dev, ptype, dest_hw, src_hw, skb->len) < 0)
		goto out;

	switch (dev->type) {
	default:
		arp->ar_hrd = htons(dev->type);
		arp->ar_pro = htons(ETH_P_IP);
		break;

#if IS_ENABLED(CONFIG_AX25)
	case ARPHRD_AX25:
		arp->ar_hrd = htons(ARPHRD_AX25);
		arp->ar_pro = htons(AX25_P_IP);
		break;

#if IS_ENABLED(CONFIG_NETROM)
	case ARPHRD_NETROM:
		arp->ar_hrd = htons(ARPHRD_NETROM);
		arp->ar_pro = htons(AX25_P_IP);
		break;
#endif
#endif

#if IS_ENABLED(CONFIG_FDDI)
	case ARPHRD_FDDI:
		arp->ar_hrd = htons(ARPHRD_ETHER);
		arp->ar_pro = htons(ETH_P_IP);
		break;
#endif
#if IS_ENABLED(CONFIG_TR)
	case ARPHRD_IEEE802_TR:
		arp->ar_hrd = htons(ARPHRD_IEEE802);
		arp->ar_pro = htons(ETH_P_IP);
		break;
#endif
	}

	arp->ar_hln = dev->addr_len;
	arp->ar_pln = 4;
	arp->ar_op = htons(type);

	arp_ptr = (unsigned char *)(arp + 1);

	memcpy(arp_ptr, src_hw, dev->addr_len);
	arp_ptr += dev->addr_len;
	memcpy(arp_ptr, &src_ip, 4);
	arp_ptr += 4;
	if (target_hw != NULL)
		memcpy(arp_ptr, target_hw, dev->addr_len);
	else
		memset(arp_ptr, 0, dev->addr_len);
	arp_ptr += dev->addr_len;
	memcpy(arp_ptr, &dest_ip, 4);

	return skb;

out:
	kfree_skb(skb);
	return NULL;
}
static void send_hsr_supervision_frame(struct hsr_port *master,
		u8 type, u8 hsrVer)
{
	struct sk_buff *skb;
	int hlen, tlen;
	struct hsr_tag *hsr_tag;
	struct hsr_sup_tag *hsr_stag;
	struct hsr_sup_payload *hsr_sp;
	unsigned long irqflags;

	hlen = LL_RESERVED_SPACE(master->dev);
	tlen = master->dev->needed_tailroom;
	skb = dev_alloc_skb(
			sizeof(struct hsr_tag) +
			sizeof(struct hsr_sup_tag) +
			sizeof(struct hsr_sup_payload) + hlen + tlen);

	if (skb == NULL)
		return;

	skb_reserve(skb, hlen);

	skb->dev = master->dev;
	skb->protocol = htons(hsrVer ? ETH_P_HSR : ETH_P_PRP);
	skb->priority = TC_PRIO_CONTROL;

	if (dev_hard_header(skb, skb->dev, (hsrVer ? ETH_P_HSR : ETH_P_PRP),
			    master->hsr->sup_multicast_addr,
			    skb->dev->dev_addr, skb->len) <= 0)
		goto out;
	skb_reset_mac_header(skb);

	if (hsrVer > 0) {
		hsr_tag = (typeof(hsr_tag)) skb_put(skb, sizeof(struct hsr_tag));
		hsr_tag->encap_proto = htons(ETH_P_PRP);
		set_hsr_tag_LSDU_size(hsr_tag, HSR_V1_SUP_LSDUSIZE);
	}

	hsr_stag = (typeof(hsr_stag)) skb_put(skb, sizeof(struct hsr_sup_tag));
	set_hsr_stag_path(hsr_stag, (hsrVer ? 0x0 : 0xf));
	set_hsr_stag_HSR_Ver(hsr_stag, hsrVer);

	/* From HSRv1 on we have separate supervision sequence numbers. */
	spin_lock_irqsave(&master->hsr->seqnr_lock, irqflags);
	if (hsrVer > 0) {
		hsr_stag->sequence_nr = htons(master->hsr->sup_sequence_nr);
		hsr_tag->sequence_nr = htons(master->hsr->sequence_nr);
		master->hsr->sup_sequence_nr++;
		master->hsr->sequence_nr++;
	} else {
		hsr_stag->sequence_nr = htons(master->hsr->sequence_nr);
		master->hsr->sequence_nr++;
	}
	spin_unlock_irqrestore(&master->hsr->seqnr_lock, irqflags);

	hsr_stag->HSR_TLV_Type = type;
	/* TODO: Why 12 in HSRv0? */
	hsr_stag->HSR_TLV_Length = hsrVer ? sizeof(struct hsr_sup_payload) : 12;

	/* Payload: MacAddressA */
	hsr_sp = (typeof(hsr_sp)) skb_put(skb, sizeof(struct hsr_sup_payload));
	ether_addr_copy(hsr_sp->MacAddressA, master->dev->dev_addr);

	skb_put_padto(skb, ETH_ZLEN + HSR_HLEN);

	hsr_forward_skb(skb, master);
	return;

out:
	WARN_ONCE(1, "HSR: Could not send supervision frame\n");
	kfree_skb(skb);
}
/*
 * Stuff received packets to associated sockets.
 * On error, returns non-zero and releases the skb.
 */
static int phonet_rcv(struct sk_buff *skb, struct net_device *dev,
			struct packet_type *pkttype,
			struct net_device *orig_dev)
{
	struct net *net = dev_net(dev);
	struct phonethdr *ph;
	struct sockaddr_pn sa;
	u16 len;

	/* check we have at least a full Phonet header */
	if (!pskb_pull(skb, sizeof(struct phonethdr)))
		goto out;

	/* check that the advertised length is correct */
	ph = pn_hdr(skb);
	len = get_unaligned_be16(&ph->pn_length);
	if (len < 2)
		goto out;
	len -= 2;
	if ((len > skb->len) || pskb_trim(skb, len))
		goto out;
	skb_reset_transport_header(skb);

	pn_skb_get_dst_sockaddr(skb, &sa);

	/* check if this is broadcasted */
	if (pn_sockaddr_get_addr(&sa) == PNADDR_BROADCAST) {
		pn_deliver_sock_broadcast(net, skb);
		goto out;
	}

	/* check if we are the destination */
	if (phonet_address_lookup(net, pn_sockaddr_get_addr(&sa)) == 0) {
		/* Phonet packet input */
		struct sock *sk = pn_find_sock_by_sa(net, &sa);

		if (sk)
			return sk_receive_skb(sk, skb, 0);

		if (can_respond(skb)) {
			send_obj_unreachable(skb);
			send_reset_indications(skb);
		}
	} else if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
		goto out; /* Race between address deletion and loopback */
	else {
		/* Phonet packet routing */
		struct net_device *out_dev;

		out_dev = phonet_route_output(net, pn_sockaddr_get_addr(&sa));
		if (!out_dev) {
			LIMIT_NETDEBUG(KERN_WARNING"No Phonet route to %02X\n",
					pn_sockaddr_get_addr(&sa));
			goto out;
		}

		__skb_push(skb, sizeof(struct phonethdr));
		skb->dev = out_dev;
		if (out_dev == dev) {
			LIMIT_NETDEBUG(KERN_ERR"Phonet loop to %02X on %s\n",
					pn_sockaddr_get_addr(&sa), dev->name);
			goto out_dev;
		}
		/* Some drivers (e.g. TUN) do not allocate HW header space */
		if (skb_cow_head(skb, out_dev->hard_header_len))
			goto out_dev;

		if (dev_hard_header(skb, out_dev, ETH_P_PHONET, NULL, NULL,
					skb->len) < 0)
			goto out_dev;
		dev_queue_xmit(skb);
		dev_put(out_dev);
		return NET_RX_SUCCESS;
out_dev:
		dev_put(out_dev);
	}

out:
	kfree_skb(skb);
	return NET_RX_DROP;
}
/*
 * Prepends an ISI header and sends a datagram.
 */
static int pn_send(struct sk_buff *skb, struct net_device *dev,
			u16 dst, u16 src, u8 res, u8 irq)
{
	struct phonethdr *ph;
	int err, i;

	if (skb->len + 2 > 0xffff /* Phonet length field limit */ ||
	    skb->len + sizeof(struct phonethdr) > dev->mtu) {
		err = -EMSGSIZE;
		goto drop;
	}

	/* Broadcast sending is not implemented */
	if (pn_addr(dst) == PNADDR_BROADCAST) {
		err = -EOPNOTSUPP;
		goto drop;
	}

	skb_reset_transport_header(skb);
	WARN_ON(skb_headroom(skb) & 1); /* HW assumes word alignment */
	skb_push(skb, sizeof(struct phonethdr));
	skb_reset_network_header(skb);
	ph = pn_hdr(skb);
	ph->pn_rdev = pn_dev(dst);
	ph->pn_sdev = pn_dev(src);
	ph->pn_res = res;
	ph->pn_length = __cpu_to_be16(skb->len + 2 - sizeof(*ph));
	ph->pn_robj = pn_obj(dst);
	ph->pn_sobj = pn_obj(src);

	skb->protocol = htons(ETH_P_PHONET);
	skb->priority = 0;
	skb->dev = dev;

	PN_PRINTK("pn_send rdev %x sdev %x res %x robj %x sobj %x netdev=%s\n",
		ph->pn_rdev, ph->pn_sdev, ph->pn_res,
		ph->pn_robj, ph->pn_sobj, dev->name);
	PN_DATA_PRINTK("PHONET : skb  data = %d\nPHONET :", skb->len);
	for (i = 1; i <= skb->len; i++) {
		PN_DATA_PRINTK(" %02x", skb->data[i-1]);
		if ((i%8) == 0)
			PN_DATA_PRINTK("\n");
	}

	if (skb->pkt_type == PACKET_LOOPBACK) {
		skb_reset_mac_header(skb);
		skb_orphan(skb);
		err = (irq ? netif_rx(skb) : netif_rx_ni(skb)) ? -ENOBUFS : 0;
	} else {
		err = dev_hard_header(skb, dev, ntohs(skb->protocol),
					NULL, NULL, skb->len);
		if (err < 0) {
			err = -EHOSTUNREACH;
			goto drop;
		}
		err = dev_queue_xmit(skb);
		if (unlikely(err > 0))
			err = net_xmit_errno(err);
	}

	return err;
drop:
	printk(KERN_DEBUG "pn_send DROP\n");
	kfree_skb(skb);
	return err;
}
Exemple #30
0
/* Handle linearized sk_buff post_routing */
static unsigned int post_routing_process(const struct nf_hook_ops *ops,
        struct sk_buff *skb,
        const struct net_device *in,
        const struct net_device *out)
{
    char* ip_pkt;
    char* nip_pkt;
    int ip_pkt_len, nip_pkt_len;
    int eth_vlan_hdr_len, full_pkt_len, ip_hdr_len;
    int err;
    struct sk_buff *nskb;
    struct ethhdr *eth_hdr;
    struct flow_keys flow_key;
    struct iphdr *ip_hdr;
    struct iphdr *nip_hdr;
    struct stack stk;
    void *saddr;
    void *daddr;
    __be16 proto;
    u32 hash;
    __wsum nskb_csum = 0;
    unsigned char dst[] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};

    /*
    if(skb_is_nonlinear(skb)){
        pr_debug("Non-linear skb.. linearizing...\n");
        if(skb_linearize(skb)){
            pr_debug("Failed to serialize!\n");
        }
    }
    */

    if (skb_is_nonlinear(skb)){
        pr_debug("Proces_pkt: Still non-linear skb.\n");
        return NF_ACCEPT;
    }

    proto = ntohs(skb->protocol);
    pr_debug("Proto: %04x\n", proto);
    switch (proto) {
        case ETH_P_IP:
            eth_hdr = (struct ethhdr *) skb_mac_header(skb); // need to set
            ip_hdr = (struct iphdr *) skb_network_header(skb);
            ip_hdr_len = ip_hdrlen(skb);
            ip_pkt = (char *) ip_hdr;
            ip_pkt_len = ntohs(ip_hdr->tot_len);

            pr_debug("IP pkt_len = %d  IP hdr len = %d \n", ip_pkt_len,
                    ip_hdr_len);

            if(skb_flow_dissect(skb, &flow_key)){
                print_ip(flow_key.src);
                print_ip(flow_key.dst);
                pr_debug("Ports %d %d\n", ntohs(flow_key.port16[0]),
                        ntohs(flow_key.port16[1]));
                hash = flow_keys_hash(flow_key);
                pr_debug("Hash: %x\n", hash);
            }
            else{
                pr_debug("Failed to dissect flow\n");
                return NF_ACCEPT;
            }

            //stats_entry_inc(be32_to_cpu(flow_key.dst), ip_pkt_len);
            pr_debug("Proto: IP pkt\nGetting stk from flow_table for %u\n",
                    be32_to_cpu(flow_key.dst));
	    stk = flow_table_get(flow_table, flow_key, routing_table, be32_to_cpu(flow_key.dst));

	    if(stk.num_tags == -1) { // no_stack
                pr_debug("flow_table miss! consulting rt_table\n");
                stk = get_random_stack_for_dst(be32_to_cpu(flow_key.dst), routing_table);
                flow_table_set(flow_table, flow_key, stk);
            }

            if(stk.num_tags < 0) {
                stk.num_tags=0;
            }

            eth_vlan_hdr_len = ETH_HLEN + stk.num_tags * sizeof(vlan_label);
            full_pkt_len = eth_vlan_hdr_len + ip_pkt_len;
            pr_debug("Full length: %d", full_pkt_len);

            // Allocate new skb
            nskb = alloc_skb(full_pkt_len, GFP_ATOMIC);
            if (nskb == NULL) {
                return NF_ACCEPT;
            }
            if (skb->sk != NULL) {
                skb_set_owner_w(nskb, skb->sk);
            }
            else {
                kfree_skb(nskb);
                return NF_ACCEPT;
            }
            pr_debug("mod_vlan: nskb - Reserving header\n");

            // Reserve space for eth and vlan headers
            skb_reserve(nskb, eth_vlan_hdr_len);

            // Copy IP packet
            pr_debug("mod_vlan: copying IP pkt.\n");
            if (!(nip_pkt = skb_put(nskb, ip_pkt_len))) {
                pr_debug("skb_put failed!\n");
                kfree_skb(nskb);
                return NF_ACCEPT;
            }
            skb_reset_network_header(nskb);
            memcpy(nip_pkt, ip_pkt, ip_pkt_len);
            nip_hdr = (struct iphdr *) nip_pkt;
            nip_pkt_len = ntohs(nip_hdr->tot_len);

            nskb_csum = fix_csum(nip_hdr);

            // Set VLAN stack
            if (set_vlan_stack(nskb, &stk)) {
                proto = ETH_P_8021Q;
            }

            // Get outgoing interface
            nskb->dev = dev_get_by_name(&init_net, out->name);
            if (!nskb->dev) {
                pr_debug("mod_vlan dev_get_by_name (%s) FAILED.", out->name);
                kfree_skb(nskb);
                return NF_ACCEPT;
            }
/*
            // Reduce MTU, if needed
            if (nskb->dev->mtu > 1500 - (4 * stk.num_tags)) {
                pr_debug("Setting MTU: (%s) %u", out->name,
                        1500 - (4 * stk.num_tags));
                nskb->dev->mtu = 1500 - (4 * stk.num_tags);
            }
            pr_debug("mod_vlan dev_get_by_name success, nskb->dev->name='%s'",
                    nskb->dev->name);
*/
            saddr = nskb->dev->dev_addr;
            daddr = dst;

            // ARP Lookup
            if (get_dst_haddr(daddr, flow_key.dst, nskb->dev) != 0){
                pr_debug("ARP lookup - FAILED!\n");
                kfree_skb(nskb);
                return NF_ACCEPT;
            }

            // Set DL header
            print_mac(saddr);
            print_mac(daddr);

            pr_debug("calling dev_hard_header\n");
            if (!dev_hard_header(nskb, nskb->dev, proto,
                        daddr, saddr, nskb->dev->addr_len)) {
                pr_debug("mod_vlan dev_hard_header FAILED.\n");
                kfree_skb(nskb);
                return NF_ACCEPT;
            }

            skb_reset_mac_header(nskb);

            // Set skb checksum
            nskb->csum = nskb_csum;

            // Send out packet - dev_queue_xmit will consume nskb
            pr_debug("mod_vlan: sending nskb....\n");
            if ((err = dev_queue_xmit(nskb)) != NET_XMIT_SUCCESS) {
                pr_debug("mod_vlan dev_queue_xmit failed. %d\n", err);
                return NF_ACCEPT;
            }

            // Consume original skb
            consume_skb(skb);
            pr_debug("------ success - returning ------\n");
            return NF_STOLEN;
            break;
        default:
            pr_debug("Proto: Non-IP pkt\n");
            break;
    }
    // default: if we didn't send a new skb, then accept the original
    return NF_ACCEPT;
}