Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

ip-cooked.c

Go to the documentation of this file.
00001 /*
00002  * ip-cooked.c
00003  *
00004  * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
00005  *
00006  * $Id: ip-cooked.c,v 1.17 2005/01/25 21:30:40 dugsong Exp $
00007  */
00008 
00009 #include "config.h"
00010 
00011 #ifndef _WIN32
00012 #include <netinet/in.h>
00013 #include <unistd.h>
00014 #endif
00015 #include <errno.h>
00016 #include <stdio.h>
00017 #include <stdlib.h>
00018 #include <string.h>
00019 
00020 #include "dnet.h"
00021 #include "queue.h"
00022 
00023 struct ip_intf {
00024         eth_t                   *eth;
00025         char                     name[INTF_NAME_LEN];
00026         struct addr              ha;
00027         struct addr              pa;
00028         int                      mtu;
00029         LIST_ENTRY(ip_intf)      next;
00030 };
00031 
00032 struct ip_handle {
00033         arp_t                   *arp;
00034         intf_t                  *intf;
00035         route_t                 *route;
00036         int                      fd;
00037         struct sockaddr_in       sin;
00038         
00039         LIST_HEAD(, ip_intf)     ip_intf_list;
00040 };
00041 
00042 static int
00043 _add_ip_intf(const struct intf_entry *entry, void *arg)
00044 {
00045         ip_t *ip = (ip_t *)arg;
00046         struct ip_intf *ipi;
00047 
00048         if (entry->intf_type == INTF_TYPE_ETH &&
00049             (entry->intf_flags & INTF_FLAG_UP) != 0 &&
00050             entry->intf_mtu >= ETH_LEN_MIN &&
00051             entry->intf_addr.addr_type == ADDR_TYPE_IP &&
00052             entry->intf_link_addr.addr_type == ADDR_TYPE_ETH) {
00053                 
00054                 if ((ipi = calloc(1, sizeof(*ipi))) == NULL)
00055                         return (-1);
00056                 
00057                 strlcpy(ipi->name, entry->intf_name, sizeof(ipi->name));
00058                 memcpy(&ipi->ha, &entry->intf_link_addr, sizeof(ipi->ha));
00059                 memcpy(&ipi->pa, &entry->intf_addr, sizeof(ipi->pa));
00060                 ipi->mtu = entry->intf_mtu;
00061 
00062                 LIST_INSERT_HEAD(&ip->ip_intf_list, ipi, next);
00063         }
00064         return (0);
00065 }
00066 
00067 ip_t *
00068 ip_open(void)
00069 {
00070         ip_t *ip;
00071 
00072         if ((ip = calloc(1, sizeof(*ip))) != NULL) {
00073                 ip->fd = -1;
00074                 
00075                 if ((ip->arp = arp_open()) == NULL ||
00076                     (ip->intf = intf_open()) == NULL ||
00077                     (ip->route = route_open()) == NULL)
00078                         return (ip_close(ip));
00079                 
00080                 if ((ip->fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
00081                         return (ip_close(ip));
00082 
00083                 memset(&ip->sin, 0, sizeof(ip->sin));
00084                 ip->sin.sin_family = AF_INET;
00085                 ip->sin.sin_port = htons(666);
00086                 
00087                 LIST_INIT(&ip->ip_intf_list);
00088 
00089                 if (intf_loop(ip->intf, _add_ip_intf, ip) != 0)
00090                         return (ip_close(ip));
00091         }
00092         return (ip);
00093 }
00094 
00095 static struct ip_intf *
00096 _lookup_ip_intf(ip_t *ip, ip_addr_t dst)
00097 {
00098         struct ip_intf *ipi;
00099         int n;
00100 
00101         ip->sin.sin_addr.s_addr = dst;
00102         n = sizeof(ip->sin);
00103         
00104         if (connect(ip->fd, (struct sockaddr *)&ip->sin, n) < 0)
00105                 return (NULL);
00106 
00107         if (getsockname(ip->fd, (struct sockaddr *)&ip->sin, &n) < 0)
00108                 return (NULL);
00109 
00110         LIST_FOREACH(ipi, &ip->ip_intf_list, next) {
00111                 if (ipi->pa.addr_ip == ip->sin.sin_addr.s_addr) {
00112                         if (ipi->eth == NULL) {
00113                                 if ((ipi->eth = eth_open(ipi->name)) == NULL)
00114                                         return (NULL);
00115                         }
00116                         if (ipi != LIST_FIRST(&ip->ip_intf_list)) {
00117                                 LIST_REMOVE(ipi, next);
00118                                 LIST_INSERT_HEAD(&ip->ip_intf_list, ipi, next);
00119                         }
00120                         return (ipi);
00121                 }
00122         }
00123         return (NULL);
00124 }
00125 
00126 static void
00127 _request_arp(struct ip_intf *ipi, struct addr *dst)
00128 {
00129         u_char frame[ETH_HDR_LEN + ARP_HDR_LEN + ARP_ETHIP_LEN];
00130 
00131         eth_pack_hdr(frame, ETH_ADDR_BROADCAST, ipi->ha.addr_eth,
00132             ETH_TYPE_ARP);
00133         arp_pack_hdr_ethip(frame + ETH_HDR_LEN, ARP_OP_REQUEST,
00134             ipi->ha.addr_eth, ipi->pa.addr_ip, ETH_ADDR_BROADCAST,
00135             dst->addr_ip);
00136 
00137         eth_send(ipi->eth, frame, sizeof(frame));
00138 }
00139 
00140 ssize_t
00141 ip_send(ip_t *ip, const void *buf, size_t len)
00142 {
00143         struct ip_hdr *iph;
00144         struct ip_intf *ipi;
00145         struct arp_entry arpent;
00146         struct route_entry rtent;
00147         u_char frame[ETH_LEN_MAX];
00148         int i, usec;
00149 
00150         iph = (struct ip_hdr *)buf;
00151         
00152         if ((ipi = _lookup_ip_intf(ip, iph->ip_dst)) == NULL) {
00153                 errno = EHOSTUNREACH;
00154                 return (-1);
00155         }
00156         arpent.arp_pa.addr_type = ADDR_TYPE_IP;
00157         arpent.arp_pa.addr_bits = IP_ADDR_BITS;
00158         arpent.arp_pa.addr_ip = iph->ip_dst;
00159         memcpy(&rtent.route_dst, &arpent.arp_pa, sizeof(rtent.route_dst));
00160 
00161         for (i = 0, usec = 10; i < 3; i++, usec *= 100) {
00162                 if (arp_get(ip->arp, &arpent) == 0)
00163                         break;
00164                 
00165                 if (route_get(ip->route, &rtent) == 0 &&
00166                     rtent.route_gw.addr_ip != ipi->pa.addr_ip) {
00167                         memcpy(&arpent.arp_pa, &rtent.route_gw,
00168                             sizeof(arpent.arp_pa));
00169                         if (arp_get(ip->arp, &arpent) == 0)
00170                                 break;
00171                 }
00172                 _request_arp(ipi, &arpent.arp_pa);
00173 
00174                 usleep(usec);
00175         }
00176         if (i == 3)
00177                 memset(&arpent.arp_ha.addr_eth, 0xff, ETH_ADDR_LEN);
00178         
00179         eth_pack_hdr(frame, arpent.arp_ha.addr_eth,
00180             ipi->ha.addr_eth, ETH_TYPE_IP);
00181 
00182         if (len > ipi->mtu) {
00183                 u_char *p, *start, *end, *ip_data;
00184                 int ip_hl, fraglen;
00185                 
00186                 ip_hl = iph->ip_hl << 2;
00187                 fraglen = ipi->mtu - ip_hl;
00188 
00189                 iph = (struct ip_hdr *)(frame + ETH_HDR_LEN);
00190                 memcpy(iph, buf, ip_hl);
00191                 ip_data = (u_char *)iph + ip_hl;
00192 
00193                 start = (u_char *)buf + ip_hl;
00194                 end = (u_char *)buf + len;
00195                 
00196                 for (p = start; p < end; ) {
00197                         memcpy(ip_data, p, fraglen);
00198                         
00199                         iph->ip_len = htons(ip_hl + fraglen);
00200                         iph->ip_off = htons(((p + fraglen < end) ? IP_MF : 0) |
00201                             ((p - start) >> 3));
00202 
00203                         ip_checksum(iph, ip_hl + fraglen);
00204 
00205                         i = ETH_HDR_LEN + ip_hl + fraglen;
00206                         if (eth_send(ipi->eth, frame, i) != i)
00207                                 return (-1);
00208                         p += fraglen;
00209                         if (end - p < fraglen)
00210                                 fraglen = end - p;
00211                 }
00212                 return (len);
00213         }
00214         memcpy(frame + ETH_HDR_LEN, buf, len);
00215         i = ETH_HDR_LEN + len;
00216         if (eth_send(ipi->eth, frame, i) != i)
00217                 return (-1);
00218         
00219         return (len);
00220 }
00221 
00222 ip_t *
00223 ip_close(ip_t *ip)
00224 {
00225         struct ip_intf *ipi, *nxt;
00226 
00227         if (ip != NULL) {
00228                 for (ipi = LIST_FIRST(&ip->ip_intf_list);
00229                     ipi != LIST_END(&ip->ip_intf_list); ipi = nxt) {
00230                         nxt = LIST_NEXT(ipi, next);
00231                         if (ipi->eth != NULL)
00232                                 eth_close(ipi->eth);
00233                         free(ipi);
00234                 }
00235                 if (ip->fd >= 0)
00236                         close(ip->fd);
00237                 if (ip->route != NULL)
00238                         route_close(ip->route);
00239                 if (ip->intf != NULL)
00240                         intf_close(ip->intf);
00241                 if (ip->arp != NULL)
00242                         arp_close(ip->arp);
00243                 free(ip);
00244         }
00245         return (NULL);
00246 }

Generated on Sun May 14 14:51:12 2006 by  doxygen 1.4.2