From 1163a1c3ce506bb1db1cfe842b9935f2972ace55 Mon Sep 17 00:00:00 2001 From: kieranm Date: Wed, 10 Sep 2003 17:14:27 +0000 Subject: [PATCH] Changes from Patch #1871 (more Raw IP functionality) --- src/api/api_lib.c | 28 ++++++---- src/api/api_msg.c | 95 ++++++++++++++++++++++++++++++++++ src/api/sockets.c | 8 +++ src/core/raw.c | 113 +++++++++++++++++++++++++++++++++-------- src/include/lwip/api.h | 8 ++- src/include/lwip/raw.h | 14 ++--- 6 files changed, 229 insertions(+), 37 deletions(-) diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 3dfd7043..44975c08 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -194,7 +194,8 @@ netbuf_fromport(struct netbuf *buf) } /*-----------------------------------------------------------------------------------*/ struct -netconn *netconn_new(enum netconn_type t) +netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u16_t proto, + void (*callback)(struct netconn *, enum netconn_evt, u16_t len)) { struct netconn *conn; struct api_msg *msg; @@ -217,7 +218,7 @@ netconn *netconn_new(enum netconn_type t) conn->sem = SYS_SEM_NULL; conn->state = NETCONN_NONE; conn->socket = 0; - conn->callback = 0; + conn->callback = callback; conn->recv_avail = 0; if((msg = memp_malloc(MEMP_API_MSG)) == NULL) { @@ -226,6 +227,7 @@ netconn *netconn_new(enum netconn_type t) } msg->type = API_MSG_NEWCONN; + msg->msg.msg.bc.port = proto; /* misusing the port field */ msg->msg.conn = conn; api_msg_post(msg); sys_mbox_fetch(conn->mbox, NULL); @@ -238,18 +240,19 @@ netconn *netconn_new(enum netconn_type t) return conn; } + +/*-----------------------------------------------------------------------------------*/ +struct +netconn *netconn_new(enum netconn_type t) +{ + return netconn_new_with_proto_and_callback(t,0,NULL); +} /*-----------------------------------------------------------------------------------*/ struct netconn *netconn_new_with_callback(enum netconn_type t, void (*callback)(struct netconn *, enum netconn_evt, u16_t len)) { - struct netconn *conn; - - /* get a netconn and then initialize callback pointer and socket */ - conn = netconn_new(t); - if (conn) - conn->callback = callback; - return conn; + return netconn_new_with_proto_and_callback(t,0,callback); } /*-----------------------------------------------------------------------------------*/ @@ -318,6 +321,9 @@ netconn_peer(struct netconn *conn, struct ip_addr *addr, u16_t *port) { switch (conn->type) { + case NETCONN_RAW: + /* return an error as connecting is only a helper for upper layers */ + return ERR_CONN; case NETCONN_UDPLITE: case NETCONN_UDPNOCHKSUM: case NETCONN_UDP: @@ -342,6 +348,10 @@ netconn_addr(struct netconn *conn, struct ip_addr **addr, u16_t *port) { switch (conn->type) { + case NETCONN_RAW: + *addr = &(conn->pcb.raw->local_ip); + *port = conn->pcb.raw->protocol; + break; case NETCONN_UDPLITE: case NETCONN_UDPNOCHKSUM: case NETCONN_UDP: diff --git a/src/api/api_msg.c b/src/api/api_msg.c index f52d44f4..69438e0c 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -37,6 +37,37 @@ #include "lwip/sys.h" #include "lwip/tcpip.h" +#if LWIP_RAW +static int +recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, + struct ip_addr *addr) +{ + struct netbuf *buf; + struct netconn *conn; + + conn = arg; + if (!conn) return 0; + + if (conn->recvmbox != SYS_MBOX_NULL) { + if (!(buf = memp_malloc(MEMP_NETBUF))) { + return 0; + } + pbuf_ref(p); + buf->p = p; + buf->ptr = p; + buf->fromaddr = addr; + buf->fromport = pcb->protocol; + + conn->recv_avail += p->tot_len; + /* Register event with callback */ + if (conn->callback) + (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, p->tot_len); + sys_mbox_post(conn->recvmbox, buf); + } + + return 0; /* do not eat the packet */ +} +#endif #if LWIP_UDP static void recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, @@ -250,6 +281,12 @@ do_newconn(struct api_msg_msg *msg) /* Allocate a PCB for this connection */ switch(msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field */ + raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: msg->conn->pcb.udp = udp_new(); @@ -300,6 +337,11 @@ do_delconn(struct api_msg_msg *msg) { if (msg->conn->pcb.tcp != NULL) { switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + raw_remove(msg->conn->pcb.raw); + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: /* FALLTHROUGH */ @@ -348,6 +390,12 @@ do_bind(struct api_msg_msg *msg) { if (msg->conn->pcb.tcp == NULL) { switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */ + raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: msg->conn->pcb.udp = udp_new(); @@ -374,6 +422,11 @@ do_bind(struct api_msg_msg *msg) } } switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + msg->conn->err = raw_bind(msg->conn->pcb.raw,msg->msg.bc.ipaddr); + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: /* FALLTHROUGH */ @@ -420,6 +473,12 @@ do_connect(struct api_msg_msg *msg) { if (msg->conn->pcb.tcp == NULL) { switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + msg->conn->pcb.raw = raw_new(msg->msg.bc.port); /* misusing the port field as protocol */ + raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: msg->conn->pcb.udp = udp_new(); @@ -465,6 +524,12 @@ do_connect(struct api_msg_msg *msg) } } switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); + sys_mbox_post(msg->conn->mbox, NULL); + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: /* FALLTHROUGH */ @@ -483,6 +548,7 @@ do_connect(struct api_msg_msg *msg) do_connected); /*tcp_output(msg->conn->pcb.tcp);*/ #endif + default: break; } @@ -493,6 +559,11 @@ do_disconnect(struct api_msg_msg *msg) { switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + /* Do nothing as connecting is only a helper for upper lwip layers */ + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: /* FALLTHROUGH */ @@ -514,6 +585,11 @@ do_listen(struct api_msg_msg *msg) { if (msg->conn->pcb.tcp != NULL) { switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: listen RAW: cannot listen for RAW.\n")); + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: /* FALLTHROUGH */ @@ -552,6 +628,11 @@ do_accept(struct api_msg_msg *msg) { if (msg->conn->pcb.tcp != NULL) { switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + LWIP_DEBUGF(API_MSG_DEBUG, ("api_msg: accept RAW: cannot accept for RAW.\n")); + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: /* FALLTHROUGH */ @@ -572,6 +653,11 @@ do_send(struct api_msg_msg *msg) { if (msg->conn->pcb.tcp != NULL) { switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + raw_send(msg->conn->pcb.raw, msg->msg.p); + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: /* FALLTHROUGH */ @@ -609,6 +695,11 @@ do_write(struct api_msg_msg *msg) #endif if (msg->conn->pcb.tcp != NULL) { switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + msg->conn->err = ERR_VAL; + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: /* FALLTHROUGH */ @@ -653,6 +744,10 @@ do_close(struct api_msg_msg *msg) if (msg->conn->pcb.tcp != NULL) { switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + break; +#endif #if LWIP_UDP case NETCONN_UDPLITE: /* FALLTHROUGH */ diff --git a/src/api/sockets.c b/src/api/sockets.c index 19381e3d..f18ad2a8 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -479,6 +479,7 @@ lwip_send(int s, void *data, int size, unsigned int flags) } switch (netconn_type(sock->conn)) { + case NETCONN_RAW: case NETCONN_UDP: case NETCONN_UDPLITE: case NETCONN_UDPNOCHKSUM: @@ -567,6 +568,10 @@ lwip_socket(int domain, int type, int protocol) /* create a netconn */ switch (type) { + case SOCK_RAW: + conn = netconn_new_with_proto_and_callback(NETCONN_RAW, protocol, event_callback); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + break; case SOCK_DGRAM: conn = netconn_new_with_callback(NETCONN_UDP, event_callback); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); @@ -1095,6 +1100,9 @@ int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *opt case SO_TYPE: switch (sock->conn->type) { + case NETCONN_RAW: + *(int*)optval = SOCK_RAW; + break; case NETCONN_TCP: *(int*)optval = SOCK_STREAM; break; diff --git a/src/core/raw.c b/src/core/raw.c index 598921c4..54d8486b 100644 --- a/src/core/raw.c +++ b/src/core/raw.c @@ -72,13 +72,14 @@ raw_init(void) * Determine if in incoming IP packet is covered by a RAW pcb and * and process it if possible * - * Given an incoming UDP datagram (as a chain of pbufs) this function - * finds a corresponding UDP PCB and + * Given an incoming IP datagram (as a chain of pbufs) this function + * finds a corresponding RAW PCB and * - * @param pbuf pbuf to be demultiplexed to a UDP PCB. + * @param pbuf pbuf to be demultiplexed to a RAW PCB. * @param netif network interface on which the datagram was received. - * @return 0 if packet cannot be handled (pbuf needs to be freed then) - * or 1 if the packet has been processed + * @return 0 if packet is not eated (pbuf needs to be freed then) + * or 1 if the packet has been eaten (pbuf needs not to be freed + * then) * */ int @@ -95,7 +96,8 @@ raw_input(struct pbuf *p, struct netif *inp) for(pcb = raw_pcbs; pcb != NULL; pcb = pcb->next) { if (pcb->protocol == proto) { if (pcb->recv) { - pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)); + if (!pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src))) + return 0; } pbuf_free(p); rc = 1; @@ -126,12 +128,38 @@ raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr) return ERR_OK; } -/*-----------------------------------------------------------------------------------*/ +/** + * Connect an RAW PCB. This function is required by upper layers + * of lwip. Using the raw api you could use raw_send_to() instead + * + * This will associate the RAW PCB with the remote address. + * + * @param pcb RAW PCB to be connected with remote address ipaddr and port. + * @param ipaddr remote IP address to connect with. + * + * @return lwIP error code + * + * @see raw_disconnect() and raw_send_to() + */ +err_t +raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr) +{ + ip_addr_set(&pcb->remote_ip, ipaddr); + return ERR_OK; +} + + +/** + * Set the callback function if a RAW packet with the pcb's protocol + * is received. If the callback function returns a value unequal 0 + * the raw packet is "eaten" and not forwarded to any other raw pcb + * including lwip itself + */ void raw_recv(struct raw_pcb *pcb, - void (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p, - struct ip_addr *addr), - void *recv_arg) + 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; @@ -151,19 +179,42 @@ raw_recv(struct raw_pcb *pcb, * */ err_t -raw_send_payload(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) +raw_send_to(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) { err_t err; struct netif *netif; struct ip_addr *src_ip; - - LWIP_DEBUGF(UDP_DEBUG | DBG_TRACE | 3, ("raw_send_payload\n")); - + struct pbuf *q; /* q will be sent down the stack */ + + LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 3, ("raw_send_to\n")); + + /* not enough space to add an IP header to first pbuf in given p chain? */ + if (pbuf_header(p, IP_HLEN)) { + /* allocate header in new pbuf */ + q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); + /* new header pbuf could not be allocated? */ + if (q == NULL) { + LWIP_DEBUGF(RAW_DEBUG | DBG_TRACE | 2, ("raw_send_to: could not allocate header\n")); + return ERR_MEM; + } + /* chain header q in front of given pbuf p */ + pbuf_chain(q, p); + /* { first pbuf q points to header pbuf } */ + LWIP_DEBUGF(RAW_DEBUG, ("raw_send_to: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); + } else { + /* first pbuf q equals given pbuf */ + q = p; + pbuf_header(q, -IP_HLEN); + } + if ((netif = ip_route(ipaddr)) == NULL) { - LWIP_DEBUGF(UDP_DEBUG | 1, ("raw_send_payload: No route to 0x%lx\n", ipaddr->addr)); + LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_send_to: No route to 0x%lx\n", ipaddr->addr)); #ifdef RAW_STATS -/* ++lwip_stats.raw.rterr;*/ -#endif /* UDP_STATS */ + /* ++lwip_stats.raw.rterr;*/ +#endif /* RAW_STATS */ + if (q != p) { + pbuf_free(q); + } return ERR_RTE; } @@ -171,13 +222,32 @@ raw_send_payload(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) /* use outgoing network interface IP address as source address */ src_ip = &(netif->ip_addr); } else { - /* use UDP PCB local IP address as source address */ + /* use RAW PCB local IP address as source address */ src_ip = &(pcb->local_ip); } - err = ip_output_if (p, src_ip, ipaddr, 64, pcb->tos, pcb->protocol, netif); + err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); - return ERR_OK; + /* did we chain a header earlier? */ + if (q != p) { + /* free the header */ + pbuf_free(q); + } + return err; +} + +/** + * Send the raw IP packet to the address given by raw_connect() + * + * @param pcb the raw pcb which to send + * @param p the ip payload to send + * @param ipaddr the destination address of the whole IP packet + * + */ +err_t +raw_send(struct raw_pcb *pcb, struct pbuf *p) +{ + return raw_send_to(pcb,p,&pcb->remote_ip); } /** @@ -198,7 +268,7 @@ raw_remove(struct raw_pcb *pcb) raw_pcbs = raw_pcbs->next; /* pcb not 1st in list */ } else for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { - /* find pcb in udp_pcbs list */ + /* find pcb in raw_pcbs list */ if (pcb2->next != NULL && pcb2->next == pcb) { /* remove pcb from list */ pcb2->next = pcb->next; @@ -229,6 +299,7 @@ raw_new(u16_t proto) { /* 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; } diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index a4b72ea7..6680d8d8 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -38,6 +38,7 @@ #include "lwip/ip.h" +#include "lwip/raw.h" #include "lwip/udp.h" #include "lwip/tcp.h" @@ -50,7 +51,8 @@ enum netconn_type { NETCONN_TCP, NETCONN_UDP, NETCONN_UDPLITE, - NETCONN_UDPNOCHKSUM + NETCONN_UDPNOCHKSUM, + NETCONN_RAW }; enum netconn_state { @@ -82,6 +84,7 @@ struct netconn { union { struct tcp_pcb *tcp; struct udp_pcb *udp; + struct raw_pcb *raw; } pcb; err_t err; sys_mbox_t mbox; @@ -121,6 +124,9 @@ struct netconn * netconn_new (enum netconn_type type); struct netconn *netconn_new_with_callback(enum netconn_type t, void (*callback)(struct netconn *, enum netconn_evt, u16_t len)); +struct +netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u16_t proto, + void (*callback)(struct netconn *, enum netconn_evt, u16_t len)); err_t netconn_delete (struct netconn *conn); enum netconn_type netconn_type (struct netconn *conn); err_t netconn_peer (struct netconn *conn, diff --git a/src/include/lwip/raw.h b/src/include/lwip/raw.h index 55a1c2b3..acad136b 100644 --- a/src/include/lwip/raw.h +++ b/src/include/lwip/raw.h @@ -46,7 +46,7 @@ struct raw_pcb { u16_t protocol; - void (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p, + int (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *addr); void *recv_arg; }; @@ -56,13 +56,15 @@ struct raw_pcb { struct raw_pcb * raw_new (u16_t proto); void raw_remove (struct raw_pcb *pcb); err_t raw_bind (struct raw_pcb *pcb, struct ip_addr *ipaddr); +err_t raw_connect (struct raw_pcb *pcb, struct ip_addr *ipaddr); void raw_recv (struct raw_pcb *pcb, - void (* recv)(void *arg, struct raw_pcb *pcb, - struct pbuf *p, - struct ip_addr *addr), - void *recv_arg); -err_t raw_send_payload (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr); + int (* recv)(void *arg, struct raw_pcb *pcb, + struct pbuf *p, + struct ip_addr *addr), + void *recv_arg); +err_t raw_send_to (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr); +err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); /* The following functions are the lower layer interface to RAW. */ int raw_input (struct pbuf *p, struct netif *inp);