URI:
       tLinux.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tLinux.c (5339B)
       ---
            1 #include <u.h>
            2 #include <sys/ioctl.h>
            3 #include <sys/socket.h>
            4 #include <netinet/in.h>
            5 #include <arpa/inet.h>
            6 #include <asm/types.h>
            7 #include <net/if_arp.h>
            8 #include <linux/netlink.h>
            9 #include <linux/rtnetlink.h>
           10 #include <net/if.h>
           11 #include <libc.h>
           12 #include <ip.h>
           13 
           14 /*
           15  * Use netlink sockets to find interfaces.
           16  * Thanks to Erik Quanstrom.
           17  */
           18 static int
           19 netlinkrequest(int fd, int type, int (*fn)(struct nlmsghdr *h, Ipifc**, int),
           20         Ipifc **ifc, int index)
           21 {
           22         char buf[1024];
           23         int n;
           24         struct sockaddr_nl nl;
           25         struct {
           26                 struct nlmsghdr nlh;
           27                 struct rtgenmsg g;
           28         } req;
           29         struct nlmsghdr *h;
           30 
           31         memset(&nl, 0, sizeof nl);
           32         nl.nl_family = AF_NETLINK;
           33 
           34         memset(&req, 0, sizeof req);
           35         req.nlh.nlmsg_len = sizeof req;
           36         req.nlh.nlmsg_type = type;
           37         req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
           38         req.nlh.nlmsg_pid = 0;
           39         req.nlh.nlmsg_seq = 1;
           40         req.g.rtgen_family = AF_NETLINK;
           41 
           42         if(sendto(fd, (void*)&req, sizeof req, 0, (struct sockaddr*)&nl, sizeof nl) < 0)
           43                 return -1;
           44 
           45         while((n=read(fd, buf, sizeof buf)) > 0){
           46                 for(h=(struct nlmsghdr*)buf; NLMSG_OK(h, n); h = NLMSG_NEXT(h, n)){
           47                         if(h->nlmsg_type == NLMSG_DONE)
           48                                 return 0;
           49                         if(h->nlmsg_type == NLMSG_ERROR){
           50                                 werrstr("netlink error");
           51                                 return -1;
           52                         }
           53                         if(fn(h, ifc, index) < 0)
           54                                 return -1;
           55                 }
           56         }
           57         werrstr("netlink error");
           58         return -1;
           59 }
           60 
           61 static int
           62 devsocket(void)
           63 {
           64         /* we couldn't care less which one; just want to talk to the kernel! */
           65         static int dumb[3] = { AF_INET, AF_PACKET, AF_INET6 };
           66         int i, fd;
           67 
           68         for(i=0; i<nelem(dumb); i++)
           69                 if((fd = socket(dumb[i], SOCK_DGRAM, 0)) >= 0)
           70                         return fd;
           71         return -1;
           72 }
           73 
           74 static int
           75 parsertattr(struct rtattr **dst, int ndst, struct nlmsghdr *h, int type, int skip)
           76 {
           77         struct rtattr *src;
           78         int len;
           79 
           80         len = h->nlmsg_len - NLMSG_LENGTH(skip);
           81         if(len < 0 || h->nlmsg_type != type){
           82                 werrstr("attrs too short");
           83                 return -1;
           84         }
           85         src = (struct rtattr*)((char*)NLMSG_DATA(h) + NLMSG_ALIGN(skip));
           86 
           87         memset(dst, 0, ndst*sizeof dst[0]);
           88         for(; RTA_OK(src, len); src = RTA_NEXT(src, len))
           89                 if(src->rta_type < ndst)
           90                         dst[src->rta_type] = src;
           91         return 0;
           92 }
           93 
           94 static void
           95 rta2ip(int af, uchar *ip, struct rtattr *rta)
           96 {
           97         memset(ip, 0, IPaddrlen);
           98 
           99         switch(af){
          100         case AF_INET:
          101                 memmove(ip, v4prefix, IPv4off);
          102                 memmove(ip+IPv4off, RTA_DATA(rta), IPv4addrlen);
          103                 break;
          104         case AF_INET6:
          105                 memmove(ip, RTA_DATA(rta), IPaddrlen);
          106                 break;
          107         }
          108 }
          109 
          110 static int
          111 getlink(struct nlmsghdr *h, Ipifc **ipifclist, int index)
          112 {
          113         char *p;
          114         int fd;
          115         struct rtattr *attr[IFLA_MAX+1];
          116         struct ifinfomsg *ifi;
          117         Ipifc *ifc;
          118 
          119         ifi = (struct ifinfomsg*)NLMSG_DATA(h);
          120         if(index >= 0 && ifi->ifi_index != index)
          121                 return 0;
          122 
          123         ifc = mallocz(sizeof *ifc, 1);
          124         if(ifc == nil)
          125                 return -1;
          126         ifc->index = ifi->ifi_index;
          127 
          128         while(*ipifclist)
          129                 ipifclist = &(*ipifclist)->next;
          130         *ipifclist = ifc;
          131 
          132         if(parsertattr(attr, nelem(attr), h, RTM_NEWLINK, sizeof(struct ifinfomsg)) < 0)
          133                 return -1;
          134 
          135         if(attr[IFLA_IFNAME])
          136                 p = (char*)RTA_DATA(attr[IFLA_IFNAME]);
          137         else
          138                 p = "nil";
          139         strecpy(ifc->dev, ifc->dev+sizeof ifc->dev, p);
          140 
          141         if(attr[IFLA_MTU])
          142                 ifc->mtu = *(int*)RTA_DATA(attr[IFLA_MTU]);
          143 
          144         /*
          145          * Does not work on old Linux systems,
          146          * and not really necessary for my purposes.
          147          * Uncomment if you want it bad.
          148          *
          149         if(attr[IFLA_STATS]){
          150                 struct rtnl_link_stats *s;
          151 
          152                 s = RTA_DATA(attr[IFLA_STATS]);
          153                 ifc->pktin = s->rx_packets;
          154                 ifc->pktout = s->tx_packets;
          155                 ifc->errin = s->rx_errors;
          156                 ifc->errout = s->tx_errors;
          157         }
          158          *
          159          */
          160 
          161         if((fd = devsocket()) > 0){
          162                 struct ifreq ifr;
          163 
          164                 memset(&ifr, 0, sizeof ifr);
          165                 strncpy(ifr.ifr_name, p, IFNAMSIZ);
          166                 ifr.ifr_mtu = 0;
          167                 if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0)
          168                         ifc->rp.linkmtu = ifr.ifr_mtu;
          169 
          170                 memset(&ifr, 0, sizeof ifr);
          171                 strncpy(ifr.ifr_name, p, IFNAMSIZ);
          172                 if(ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0
          173                 && ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER)
          174                         memmove(ifc->ether, ifr.ifr_hwaddr.sa_data, 6);
          175 
          176                 close(fd);
          177         }
          178         return 0;
          179 }
          180 
          181 static int
          182 getaddr(struct nlmsghdr *h, Ipifc **ipifclist, int index)
          183 {
          184         int mask;
          185         Ipifc *ifc;
          186         Iplifc *lifc, **l;
          187         struct ifaddrmsg *ifa;
          188         struct rtattr *attr[IFA_MAX+1];
          189 
          190         USED(index);
          191 
          192         ifa = (struct ifaddrmsg*)NLMSG_DATA(h);
          193         for(ifc=*ipifclist; ifc; ifc=ifc->next)
          194                 if(ifc->index == ifa->ifa_index)
          195                         break;
          196         if(ifc == nil)
          197                 return 0;
          198         if(parsertattr(attr, nelem(attr), h, RTM_NEWADDR, sizeof(struct ifaddrmsg)) < 0)
          199                 return -1;
          200 
          201         lifc = mallocz(sizeof *lifc, 1);
          202         if(lifc == nil)
          203                 return -1;
          204         for(l=&ifc->lifc; *l; l=&(*l)->next)
          205                 ;
          206         *l = lifc;
          207 
          208         if(attr[IFA_ADDRESS] == nil)
          209                 attr[IFA_ADDRESS] = attr[IFA_LOCAL];
          210         if(attr[IFA_ADDRESS] == nil)
          211                 return 0;
          212 
          213         rta2ip(ifa->ifa_family, lifc->ip, attr[IFA_ADDRESS]);
          214 
          215         mask = ifa->ifa_prefixlen/8;
          216         if(ifa->ifa_family == AF_INET)
          217                 mask += IPv4off;
          218         memset(lifc->mask, 0xFF, mask);
          219         memmove(lifc->net, lifc->ip, mask);
          220 
          221         if(attr[IFA_CACHEINFO]){
          222                 struct ifa_cacheinfo *ci;
          223 
          224                 ci = RTA_DATA(attr[IFA_CACHEINFO]);
          225                 lifc->preflt = ci->ifa_prefered;
          226                 lifc->validlt = ci->ifa_valid;
          227         }
          228         return 0;
          229 }
          230 
          231 Ipifc*
          232 readipifc(char *net, Ipifc *ifc, int index)
          233 {
          234         int fd;
          235 
          236         USED(net);
          237         freeipifc(ifc);
          238         ifc = nil;
          239 
          240         fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
          241         if(fd < 0)
          242                 return nil;
          243         ifc = nil;
          244         if(netlinkrequest(fd, RTM_GETLINK, getlink, &ifc, index) < 0
          245         || netlinkrequest(fd, RTM_GETADDR, getaddr, &ifc, index) < 0){
          246                 close(fd);
          247                 freeipifc(ifc);
          248                 return nil;
          249         }
          250         close(fd);
          251         return ifc;
          252 }