diff --git a/CHANGELOG b/CHANGELOG index 987bf244..c1b0a5f3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,6 +23,13 @@ HISTORY ++ New features: + 2007-03-11 Frédéric Bernon, Mace Gael, Steve Reynolds + * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, igmp.h, igmp.c, + ip.c, netif.h, tcpip.c, opt.h: + New configuration option LWIP_IGMP to enable IGMP processing. Based on only one + filter per all network interfaces. Declare a new function in netif to enable to + control the MAC filter (to reduce lwIP traffic processing). + 2007-03-11 Frédéric Bernon * tcp.h, tcp.c, sockets.c, tcp_out.c, tcp_in.c, opt.h: Keepalive values can be configured at run time with LWIP_TCP_KEEPALIVE, but don't change this diff --git a/src/api/api_lib.c b/src/api/api_lib.c index 6e5a7ab9..d784306d 100644 --- a/src/api/api_lib.c +++ b/src/api/api_lib.c @@ -682,6 +682,37 @@ netconn_close(struct netconn *conn) return conn->err; } +#if LWIP_IGMP +err_t +netconn_join_leave_group (struct netconn *conn, + struct ip_addr *multiaddr, + struct ip_addr *interface, + u16_t join_or_leave) +{ + struct api_msg msg; + struct ip_addr *ipaddr[2]; + + if (conn == NULL) { + return ERR_VAL; + } + + if (conn->err != ERR_OK) { + return conn->err; + } + + msg.type = API_MSG_JOIN_LEAVE; + msg.msg.conn = conn; + ipaddr[0] = multiaddr; + ipaddr[1] = interface; + msg.msg.msg.bc.ipaddr = (struct ip_addr *)ipaddr; + msg.msg.msg.bc.port = join_or_leave; + api_msg_post(&msg); + + sys_mbox_fetch(conn->mbox, NULL); + return conn->err; +} +#endif /* LWIP_IGMP */ + err_t netconn_err(struct netconn *conn) { diff --git a/src/api/api_msg.c b/src/api/api_msg.c index 325bc683..d62e1259 100644 --- a/src/api/api_msg.c +++ b/src/api/api_msg.c @@ -36,6 +36,7 @@ #include "lwip/memp.h" #include "lwip/sys.h" #include "lwip/tcpip.h" +#include "lwip/igmp.h" #if LWIP_RAW static u8_t @@ -788,6 +789,41 @@ do_close(struct api_msg_msg *msg) } sys_mbox_post(msg->conn->mbox, NULL); } + +#if LWIP_IGMP +static void +do_join_leave_group(struct api_msg_msg *msg) +{ + err_t err = ERR_OK; + + if (msg->conn->pcb.tcp != NULL) { + switch (msg->conn->type) { +#if LWIP_RAW + case NETCONN_RAW: + break; +#endif +#if LWIP_UDP + case NETCONN_UDPLITE: + case NETCONN_UDPNOCHKSUM: + case NETCONN_UDP: + switch(msg->msg.bc.port){ + case NETCONN_JOIN: err = igmp_joingroup (netif_default, ((struct ip_addr**)(msg->msg.bc.ipaddr))[0]); break; + case NETCONN_LEAVE: err = igmp_leavegroup(netif_default, ((struct ip_addr**)(msg->msg.bc.ipaddr))[0]); break; + } + break; +#endif /* LWIP_UDP */ +#if LWIP_TCP + case NETCONN_TCP: + break; +#endif + default: + break; + } + } + msg->conn->err = err; + sys_mbox_post(msg->conn->mbox, NULL); +} +#endif /* LWIP_IGMP */ typedef void (* api_msg_decode)(struct api_msg_msg *msg); static api_msg_decode decode[API_MSG_MAX] = { @@ -801,7 +837,10 @@ static api_msg_decode decode[API_MSG_MAX] = { do_send, do_recv, do_write, - do_close + do_close, +#if LWIP_IGMP + do_join_leave_group +#endif /* LWIP_IGMP */ }; void api_msg_input(struct api_msg *msg) diff --git a/src/api/sockets.c b/src/api/sockets.c index ce5ebfcb..5043b767 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -39,7 +39,7 @@ #include "lwip/api.h" #include "lwip/arch.h" #include "lwip/sys.h" - +#include "lwip/igmp.h" #include "lwip/sockets.h" #define NUM_SOCKETS MEMP_NUM_NETCONN @@ -1237,6 +1237,21 @@ int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_ err = EINVAL; } break; + #if LWIP_IGMP + case IP_MULTICAST_TTL: + { if(( optlen != sizeof(char) ) && ( optlen != sizeof(int) )) //NOTE, some BSD implementation use "int", some others "char" + { err = EINVAL; + } + break; + } + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + { if( optlen < sizeof(struct ip_mreq) ) + { err = EINVAL; + } + break; + } + #endif /* LWIP_IGMP */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; @@ -1328,6 +1343,27 @@ int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_ sock->conn->pcb.tcp->tos = (u8_t)(*(int*)optval); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", s, sock->conn->pcb.tcp->tos)); break; + #if LWIP_IGMP + case IP_MULTICAST_TTL: + { if (optlen==sizeof(int)) sock->conn->pcb.tcp->ttl = (u8_t)(*(int*) optval); + if (optlen==sizeof(u8_t)) sock->conn->pcb.tcp->ttl = (u8_t)(*(u8_t*)optval); + break; + } + case IP_ADD_MEMBERSHIP: + case IP_DROP_MEMBERSHIP: + { /* If this is a TCP or a RAW socket, ignore these options. */ + if ((sock->conn->type == NETCONN_TCP) || (sock->conn->type == NETCONN_RAW)) + { err = EAFNOSUPPORT; + } + else + { struct ip_mreq *imr = (struct ip_mreq *)optval; + if (netconn_join_leave_group( sock->conn, (struct ip_addr *)&(imr->imr_multiaddr.s_addr), (struct ip_addr *)&(imr->imr_interface.s_addr), ((optname==IP_ADD_MEMBERSHIP)?NETCONN_JOIN:NETCONN_LEAVE)) < 0) + { err = EADDRNOTAVAIL; + } + } + break; + } + #endif /* LWIP_IGMP */ } /* switch */ break; diff --git a/src/api/tcpip.c b/src/api/tcpip.c index cc55756c..0660d5be 100644 --- a/src/api/tcpip.c +++ b/src/api/tcpip.c @@ -45,6 +45,7 @@ #include "lwip/tcp.h" #include "lwip/tcpip.h" +#include "lwip/igmp.h" static void (* tcpip_init_done)(void *arg) = NULL; static void *tcpip_init_done_arg; @@ -168,6 +169,9 @@ tcpip_thread(void *arg) sys_timeout(DHCP_COARSE_TIMER_SECS*1000, dhcp_timer_coarse, NULL); sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); #endif +#if LWIP_IGMP + igmp_init(); +#endif if (tcpip_init_done != NULL) { tcpip_init_done(tcpip_init_done_arg); diff --git a/src/core/ipv4/ip.c b/src/core/ipv4/ip.c index 9d655f8b..5fa56fce 100644 --- a/src/core/ipv4/ip.c +++ b/src/core/ipv4/ip.c @@ -59,6 +59,9 @@ # include "lwip/dhcp.h" #endif /* LWIP_DHCP */ +#if LWIP_IGMP +# include "lwip/igmp.h" +#endif /* LWIP_IGMP */ /** * Initializes the IP layer. @@ -227,28 +230,44 @@ ip_input(struct pbuf *p, struct netif *inp) { pbuf_realloc(p, ntohs(IPH_LEN(iphdr))); /* match packet against an interface, i.e. is this packet for us? */ - for (netif = netif_list; netif != NULL; netif = netif->next) { - - LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", - iphdr->dest.addr, netif->ip_addr.addr, - iphdr->dest.addr & netif->netmask.addr, - netif->ip_addr.addr & netif->netmask.addr, - iphdr->dest.addr & ~(netif->netmask.addr))); - - /* interface is up and configured? */ - if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) - { - /* unicast to this interface address? */ - if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) || - /* or broadcast on this interface network address? */ - ip_addr_isbroadcast(&(iphdr->dest), netif)) { - LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", - netif->name[0], netif->name[1])); - /* break out of for loop */ - break; +#if LWIP_IGMP + if (ip_addr_ismulticast(&(iphdr->dest))) + { if (lookfor_group( inp, &(iphdr->dest))) + { netif = inp; } - } - } + else + { netif = NULL; + } + } + else + { +#endif + for (netif = netif_list; netif != NULL; netif = netif->next) { + + LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", + iphdr->dest.addr, netif->ip_addr.addr, + iphdr->dest.addr & netif->netmask.addr, + netif->ip_addr.addr & netif->netmask.addr, + iphdr->dest.addr & ~(netif->netmask.addr))); + + /* interface is up and configured? */ + if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) + { + /* unicast to this interface address? */ + if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) || + /* or broadcast on this interface network address? */ + ip_addr_isbroadcast(&(iphdr->dest), netif)) { + LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + /* break out of for loop */ + break; + } + } + } + #if LWIP_IGMP + } + #endif + #if LWIP_DHCP /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. @@ -310,7 +329,13 @@ ip_input(struct pbuf *p, struct netif *inp) { } #if IP_OPTIONS == 0 /* no support for IP options in the IP header? */ + +#if LWIP_IGMP + /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */ + if((iphdrlen > IP_HLEN && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { +#else if (iphdrlen > IP_HLEN) { +#endif LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS == 0).\n")); pbuf_free(p); IP_STATS_INC(ip.opterr); @@ -349,6 +374,11 @@ ip_input(struct pbuf *p, struct netif *inp) { snmp_inc_ipindelivers(); icmp_input(p, inp); break; +#if LWIP_IGMP + case IP_PROTO_IGMP: + igmp_input(p,inp,&(iphdr->dest)); + break; +#endif default: /* send ICMP destination protocol unreachable unless is was a broadcast */ if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && diff --git a/src/include/lwip/api.h b/src/include/lwip/api.h index 905afbb5..5472307e 100644 --- a/src/include/lwip/api.h +++ b/src/include/lwip/api.h @@ -71,6 +71,13 @@ enum netconn_evt { NETCONN_EVT_SENDMINUS }; +#if LWIP_IGMP +enum netconn_igmp { + NETCONN_JOIN, + NETCONN_LEAVE +}; +#endif /* LWIP_IGMP */ + struct netbuf { struct pbuf *p, *ptr; struct ip_addr *fromaddr; @@ -155,6 +162,13 @@ err_t netconn_write (struct netconn *conn, u8_t copy); err_t netconn_close (struct netconn *conn); +#if LWIP_IGMP +err_t netconn_join_leave_group (struct netconn *conn, + struct ip_addr *multiaddr, + struct ip_addr *interface, + u16_t join_or_leave); +#endif /* LWIP_IGMP */ + err_t netconn_err (struct netconn *conn); #endif /* __LWIP_API_H__ */ diff --git a/src/include/lwip/api_msg.h b/src/include/lwip/api_msg.h index e15ea388..b274cd2b 100644 --- a/src/include/lwip/api_msg.h +++ b/src/include/lwip/api_msg.h @@ -59,7 +59,11 @@ enum api_msg_type { API_MSG_WRITE, API_MSG_CLOSE, - + +#if LWIP_IGMP + API_MSG_JOIN_LEAVE, +#endif /* LWIP_IGMP */ + API_MSG_MAX }; diff --git a/src/include/lwip/netif.h b/src/include/lwip/netif.h index b7737699..4e58e734 100644 --- a/src/include/lwip/netif.h +++ b/src/include/lwip/netif.h @@ -126,6 +126,10 @@ struct netif { u32_t ifoutnucastpkts; u32_t ifoutdiscards; #endif +#if LWIP_IGMP + /* This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/ + err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action); +#endif }; /** The list of network interfaces. */ diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 269434c1..375f287f 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -52,6 +52,7 @@ #ifndef NO_SYS #define NO_SYS 0 #endif + /* ---------- Memory options ---------- */ #ifndef MEM_LIBC_MALLOC #define MEM_LIBC_MALLOC 0 @@ -162,10 +163,7 @@ a lot of data that needs to be copied, this should be set high. */ #define PBUF_LINK_HLEN 14 #endif - - /* ---------- ARP options ---------- */ - /** Number of active hardware address, IP address pairs cached */ #ifndef ARP_TABLE_SIZE #define ARP_TABLE_SIZE 10 @@ -270,13 +268,11 @@ a lot of data that needs to be copied, this should be set high. */ #endif /* ---------- ICMP options ---------- */ - #ifndef ICMP_TTL #define ICMP_TTL (IP_DEFAULT_TTL) #endif -/* ---------- RAW options ---------- */ - +/* ---------- RAW options ----------- */ #ifndef LWIP_RAW #define LWIP_RAW 1 #endif @@ -286,7 +282,6 @@ a lot of data that needs to be copied, this should be set high. */ #endif /* ---------- DHCP options ---------- */ - #ifndef LWIP_DHCP #define LWIP_DHCP 0 #endif @@ -317,6 +312,11 @@ a lot of data that needs to be copied, this should be set high. */ #define SNMP_PRIVATE_MIB 0 #endif +/* ---------- IGMP options ---------- */ +#ifndef LWIP_IGMP +#define LWIP_IGMP 0 +#endif + /* ---------- UDP options ---------- */ #ifndef LWIP_UDP #define LWIP_UDP 1 @@ -516,7 +516,6 @@ a lot of data that needs to be copied, this should be set high. */ #endif /* LWIP_STATS */ /* ---------- PPP options ---------- */ - #ifndef PPP_SUPPORT #define PPP_SUPPORT 0 /* Set for PPP */ #endif @@ -764,5 +763,3 @@ a lot of data that needs to be copied, this should be set high. */ #endif /* __LWIP_OPT_H__ */ - - diff --git a/src/include/lwip/sockets.h b/src/include/lwip/sockets.h index 16af3832..bdcd724c 100644 --- a/src/include/lwip/sockets.h +++ b/src/include/lwip/sockets.h @@ -123,10 +123,26 @@ struct linger { /* * Options for level IPPROTO_IP */ -#define IP_TOS 1 -#define IP_TTL 2 +#define IP_TOS 1 +#define IP_TTL 2 +#ifdef LWIP_IGMP +/* + * Options and types for UDP multicast traffic handling + */ +#define IP_ADD_MEMBERSHIP 3 +#define IP_DROP_MEMBERSHIP 4 +#define IP_MULTICAST_TTL 5 +#define IP_MULTICAST_IF 6 +#define IP_MULTICAST_LOOP 7 + +typedef struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +} ip_mreq; +#endif /* LWIP_IGMP */ + #define IPTOS_TOS_MASK 0x1E #define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) #define IPTOS_LOWDELAY 0x10