Goto sanos source index
//
// raw.c
//
// Raw network protocol interface
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
// Portions Copyright (C) 2001, Swedish Institute of Computer Science.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include <net/net.h>
static struct raw_pcb *raw_pcbs = NULL;
//
// rawstat_proc
//
static int rawstat_proc(struct proc_file *pf, void *arg) {
struct raw_pcb *pcb;
pprintf(pf, "protocol local ip remote ip\n");
pprintf(pf, "----------- --------------- ---------------\n");
for (pcb = raw_pcbs; pcb != NULL; pcb = pcb->next) {
pprintf(pf, "%8d %-15a %-15a\n", pcb->protocol, &pcb->local_ip, &pcb->remote_ip);
}
return 0;
}
//
// raw_init
//
void raw_init() {
raw_pcbs = NULL;
register_proc_inode("rawstat", rawstat_proc, NULL);
}
//
// Determine if in incoming IP packet is covered by a RAW PCB
// and if so, pass it to a user-provided receive callback function.
//
// Given an incoming IP datagram (as a chain of pbufs) this function
// finds a corresponding RAW PCB and calls the corresponding receive
// callback function.
//
err_t raw_input(struct pbuf *p, struct netif *inp) {
struct raw_pcb *pcb;
struct ip_hdr *iphdr;
int proto;
int rc;
int eaten = 0;
iphdr = p->payload;
proto = IPH_PROTO(iphdr);
// Loop through all raw pcbs until the packet is eaten by one
// This allows multiple pcbs to match against the packet by design
pcb = raw_pcbs;
while (!eaten && pcb != NULL) {
if (pcb->protocol == proto)
{
// Receive callback function available?
if (pcb->recv != NULL) {
// The receive callback function did not eat the packet?
rc = pcb->recv(pcb->recv_arg, pcb, p, &iphdr->src);
if (rc < 0) return rc;
if (rc > 0) {
// Receive function ate the packet
stats.raw.recv++;
p = NULL;
eaten = 1;
}
}
}
pcb = pcb->next;
}
return eaten;
}
//
// Bind a RAW PCB.
//
err_t raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr) {
ip_addr_set(&pcb->local_ip, ipaddr);
return 0;
}
//
// Connect an RAW PCB. This will associate the RAW PCB with the remote address.
//
err_t raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr) {
ip_addr_set(&pcb->remote_ip, ipaddr);
return 0;
}
//
// Set the callback function for received packets that match the
// raw PCB's protocol and binding.
//
// The callback function MUST either
// - eat the packet by calling pbuf_free() and returning non-zero. The
// packet will not be passed to other raw PCBs or other protocol layers.
// - not free the packet, and return zero. The packet will be matched
// against further PCBs and/or forwarded to another protocol layers.
//
err_t raw_recv(struct raw_pcb *pcb,
int (*recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p, struct ip_addr *addr),
void *recv_arg) {
// Remember recv() callback and user data
pcb->recv = recv;
pcb->recv_arg = recv_arg;
return 0;
}
//
// Send the raw IP packet to the given address. Note that actually you cannot
// modify the IP headers (this is inconsistent with the receive callback where
// you actually get the IP headers), you can only specify the IP payload here.
//
err_t raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) {
struct netif *netif;
struct ip_addr *src_ip;
if ((netif = ip_route(ipaddr)) == NULL) {
stats.raw.rterr++;
return -EROUTE;
}
if (ip_addr_isany(&pcb->local_ip)) {
// Use outgoing network interface IP address as source address
src_ip = &netif->ipaddr;
} else {
// use RAW PCB local IP address as source address
src_ip = &pcb->local_ip;
}
stats.raw.xmit++;
return ip_output_if(p, src_ip, ipaddr, pcb->ttl, pcb->protocol, netif);
}
//
// Send the raw IP packet to the address given by raw_connect()
//
err_t raw_send(struct raw_pcb *pcb, struct pbuf *p) {
return raw_sendto(pcb, p, &pcb->remote_ip);
}
//
// Remove an RAW PCB.
//
void raw_remove(struct raw_pcb *pcb) {
struct raw_pcb *pcb2;
if (raw_pcbs == pcb) {
raw_pcbs = raw_pcbs->next;
} else {
for (pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
if (pcb2->next != NULL && pcb2->next == pcb) {
pcb2->next = pcb->next;
}
}
}
kfree(pcb);
}
//
// Create a RAW PCB.
//
struct raw_pcb *raw_new(unsigned short proto) {
struct raw_pcb *pcb;
pcb = (struct raw_pcb *) kmalloc(sizeof(struct raw_pcb));
if (!pcb) return NULL;
// Initialize PCB to all zeroes
memset(pcb, 0, sizeof(struct raw_pcb));
pcb->protocol = proto;
pcb->ttl = RAW_TTL;
pcb->next = raw_pcbs;
raw_pcbs = pcb;
return pcb;
}