1cfa1ca9dSYoshinobu Inoue /* 2cfa1ca9dSYoshinobu Inoue * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3cfa1ca9dSYoshinobu Inoue * All rights reserved. 4cfa1ca9dSYoshinobu Inoue * 5cfa1ca9dSYoshinobu Inoue * Redistribution and use in source and binary forms, with or without 6cfa1ca9dSYoshinobu Inoue * modification, are permitted provided that the following conditions 7cfa1ca9dSYoshinobu Inoue * are met: 8cfa1ca9dSYoshinobu Inoue * 1. Redistributions of source code must retain the above copyright 9cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer. 10cfa1ca9dSYoshinobu Inoue * 2. Redistributions in binary form must reproduce the above copyright 11cfa1ca9dSYoshinobu Inoue * notice, this list of conditions and the following disclaimer in the 12cfa1ca9dSYoshinobu Inoue * documentation and/or other materials provided with the distribution. 13cfa1ca9dSYoshinobu Inoue * 3. Neither the name of the project nor the names of its contributors 14cfa1ca9dSYoshinobu Inoue * may be used to endorse or promote products derived from this software 15cfa1ca9dSYoshinobu Inoue * without specific prior written permission. 16cfa1ca9dSYoshinobu Inoue * 17cfa1ca9dSYoshinobu Inoue * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18cfa1ca9dSYoshinobu Inoue * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19cfa1ca9dSYoshinobu Inoue * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20cfa1ca9dSYoshinobu Inoue * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21cfa1ca9dSYoshinobu Inoue * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22cfa1ca9dSYoshinobu Inoue * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23cfa1ca9dSYoshinobu Inoue * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24cfa1ca9dSYoshinobu Inoue * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25cfa1ca9dSYoshinobu Inoue * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26cfa1ca9dSYoshinobu Inoue * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27cfa1ca9dSYoshinobu Inoue * SUCH DAMAGE. 28cfa1ca9dSYoshinobu Inoue * 29cfa1ca9dSYoshinobu Inoue * $FreeBSD$ 30cfa1ca9dSYoshinobu Inoue */ 31cfa1ca9dSYoshinobu Inoue 32cfa1ca9dSYoshinobu Inoue /* 33cfa1ca9dSYoshinobu Inoue * in_gif.c 34cfa1ca9dSYoshinobu Inoue */ 35cfa1ca9dSYoshinobu Inoue 36cfa1ca9dSYoshinobu Inoue #include "opt_mrouting.h" 37cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 38cfa1ca9dSYoshinobu Inoue 39cfa1ca9dSYoshinobu Inoue #include <sys/param.h> 40cfa1ca9dSYoshinobu Inoue #include <sys/systm.h> 41cfa1ca9dSYoshinobu Inoue #include <sys/socket.h> 42cfa1ca9dSYoshinobu Inoue #include <sys/sockio.h> 43cfa1ca9dSYoshinobu Inoue #include <sys/mbuf.h> 44cfa1ca9dSYoshinobu Inoue #include <sys/errno.h> 45cfa1ca9dSYoshinobu Inoue #include <sys/kernel.h> 46cfa1ca9dSYoshinobu Inoue #include <sys/sysctl.h> 47cfa1ca9dSYoshinobu Inoue #include <sys/protosw.h> 48cfa1ca9dSYoshinobu Inoue 49cfa1ca9dSYoshinobu Inoue #include <net/if.h> 50cfa1ca9dSYoshinobu Inoue #include <net/route.h> 51cfa1ca9dSYoshinobu Inoue 52cfa1ca9dSYoshinobu Inoue #include <netinet/in.h> 53cfa1ca9dSYoshinobu Inoue #include <netinet/in_systm.h> 54cfa1ca9dSYoshinobu Inoue #include <netinet/ip.h> 55cfa1ca9dSYoshinobu Inoue #ifdef INET6 56cfa1ca9dSYoshinobu Inoue #include <netinet/ip6.h> 57cfa1ca9dSYoshinobu Inoue #endif 586a800098SYoshinobu Inoue #include <netinet/ip_var.h> 596a800098SYoshinobu Inoue #include <netinet/in_gif.h> 606a800098SYoshinobu Inoue #include <netinet/ip_ecn.h> 616a800098SYoshinobu Inoue #ifdef INET6 626a800098SYoshinobu Inoue #include <netinet6/ip6_ecn.h> 636a800098SYoshinobu Inoue #endif 64cfa1ca9dSYoshinobu Inoue 65cfa1ca9dSYoshinobu Inoue #ifdef MROUTING 66cfa1ca9dSYoshinobu Inoue #include <netinet/ip_mroute.h> 67cfa1ca9dSYoshinobu Inoue #endif /* MROUTING */ 68cfa1ca9dSYoshinobu Inoue 69cfa1ca9dSYoshinobu Inoue #include <net/if_gif.h> 70cfa1ca9dSYoshinobu Inoue 71cfa1ca9dSYoshinobu Inoue #include "gif.h" 72cfa1ca9dSYoshinobu Inoue 73cfa1ca9dSYoshinobu Inoue #include <machine/stdarg.h> 74cfa1ca9dSYoshinobu Inoue 75cfa1ca9dSYoshinobu Inoue #include <net/net_osdep.h> 76cfa1ca9dSYoshinobu Inoue 77cfa1ca9dSYoshinobu Inoue #if NGIF > 0 78cfa1ca9dSYoshinobu Inoue int ip_gif_ttl = GIF_TTL; 79cfa1ca9dSYoshinobu Inoue #else 80cfa1ca9dSYoshinobu Inoue int ip_gif_ttl = 0; 81cfa1ca9dSYoshinobu Inoue #endif 82cfa1ca9dSYoshinobu Inoue 83cfa1ca9dSYoshinobu Inoue SYSCTL_DECL(_net_inet_ip); 84cfa1ca9dSYoshinobu Inoue SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_RW, 85cfa1ca9dSYoshinobu Inoue &ip_gif_ttl, 0, ""); 86cfa1ca9dSYoshinobu Inoue 87cfa1ca9dSYoshinobu Inoue int 88cfa1ca9dSYoshinobu Inoue in_gif_output(ifp, family, m, rt) 89cfa1ca9dSYoshinobu Inoue struct ifnet *ifp; 90cfa1ca9dSYoshinobu Inoue int family; 91cfa1ca9dSYoshinobu Inoue struct mbuf *m; 92cfa1ca9dSYoshinobu Inoue struct rtentry *rt; 93cfa1ca9dSYoshinobu Inoue { 94cfa1ca9dSYoshinobu Inoue register struct gif_softc *sc = (struct gif_softc*)ifp; 95cfa1ca9dSYoshinobu Inoue struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; 96cfa1ca9dSYoshinobu Inoue struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; 97cfa1ca9dSYoshinobu Inoue struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; 98cfa1ca9dSYoshinobu Inoue struct ip iphdr; /* capsule IP header, host byte ordered */ 99cfa1ca9dSYoshinobu Inoue int proto, error; 100cfa1ca9dSYoshinobu Inoue u_int8_t tos; 101cfa1ca9dSYoshinobu Inoue 102cfa1ca9dSYoshinobu Inoue if (sin_src == NULL || sin_dst == NULL || 103cfa1ca9dSYoshinobu Inoue sin_src->sin_family != AF_INET || 104cfa1ca9dSYoshinobu Inoue sin_dst->sin_family != AF_INET) { 105cfa1ca9dSYoshinobu Inoue m_freem(m); 106cfa1ca9dSYoshinobu Inoue return EAFNOSUPPORT; 107cfa1ca9dSYoshinobu Inoue } 108cfa1ca9dSYoshinobu Inoue 109cfa1ca9dSYoshinobu Inoue switch (family) { 110cfa1ca9dSYoshinobu Inoue case AF_INET: 111cfa1ca9dSYoshinobu Inoue { 112cfa1ca9dSYoshinobu Inoue struct ip *ip; 113cfa1ca9dSYoshinobu Inoue 114cfa1ca9dSYoshinobu Inoue proto = IPPROTO_IPV4; 115cfa1ca9dSYoshinobu Inoue if (m->m_len < sizeof(*ip)) { 116cfa1ca9dSYoshinobu Inoue m = m_pullup(m, sizeof(*ip)); 117cfa1ca9dSYoshinobu Inoue if (!m) 118cfa1ca9dSYoshinobu Inoue return ENOBUFS; 119cfa1ca9dSYoshinobu Inoue } 120cfa1ca9dSYoshinobu Inoue ip = mtod(m, struct ip *); 121cfa1ca9dSYoshinobu Inoue tos = ip->ip_tos; 122cfa1ca9dSYoshinobu Inoue break; 123cfa1ca9dSYoshinobu Inoue } 124cfa1ca9dSYoshinobu Inoue #ifdef INET6 125cfa1ca9dSYoshinobu Inoue case AF_INET6: 126cfa1ca9dSYoshinobu Inoue { 127cfa1ca9dSYoshinobu Inoue struct ip6_hdr *ip6; 128cfa1ca9dSYoshinobu Inoue proto = IPPROTO_IPV6; 129cfa1ca9dSYoshinobu Inoue if (m->m_len < sizeof(*ip6)) { 130cfa1ca9dSYoshinobu Inoue m = m_pullup(m, sizeof(*ip6)); 131cfa1ca9dSYoshinobu Inoue if (!m) 132cfa1ca9dSYoshinobu Inoue return ENOBUFS; 133cfa1ca9dSYoshinobu Inoue } 134cfa1ca9dSYoshinobu Inoue ip6 = mtod(m, struct ip6_hdr *); 135cfa1ca9dSYoshinobu Inoue tos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 136cfa1ca9dSYoshinobu Inoue break; 137cfa1ca9dSYoshinobu Inoue } 138cfa1ca9dSYoshinobu Inoue #endif /*INET6*/ 139cfa1ca9dSYoshinobu Inoue default: 140cfa1ca9dSYoshinobu Inoue #ifdef DIAGNOSTIC 141cfa1ca9dSYoshinobu Inoue printf("in_gif_output: warning: unknown family %d passed\n", 142cfa1ca9dSYoshinobu Inoue family); 143cfa1ca9dSYoshinobu Inoue #endif 144cfa1ca9dSYoshinobu Inoue m_freem(m); 145cfa1ca9dSYoshinobu Inoue return EAFNOSUPPORT; 146cfa1ca9dSYoshinobu Inoue } 147cfa1ca9dSYoshinobu Inoue 148cfa1ca9dSYoshinobu Inoue bzero(&iphdr, sizeof(iphdr)); 149cfa1ca9dSYoshinobu Inoue iphdr.ip_src = sin_src->sin_addr; 150cfa1ca9dSYoshinobu Inoue if (ifp->if_flags & IFF_LINK0) { 151cfa1ca9dSYoshinobu Inoue /* multi-destination mode */ 152cfa1ca9dSYoshinobu Inoue if (sin_dst->sin_addr.s_addr != INADDR_ANY) 153cfa1ca9dSYoshinobu Inoue iphdr.ip_dst = sin_dst->sin_addr; 154cfa1ca9dSYoshinobu Inoue else if (rt) { 155cfa1ca9dSYoshinobu Inoue iphdr.ip_dst = ((struct sockaddr_in *) 156cfa1ca9dSYoshinobu Inoue (rt->rt_gateway))->sin_addr; 157cfa1ca9dSYoshinobu Inoue } else { 158cfa1ca9dSYoshinobu Inoue m_freem(m); 159cfa1ca9dSYoshinobu Inoue return ENETUNREACH; 160cfa1ca9dSYoshinobu Inoue } 161cfa1ca9dSYoshinobu Inoue } else { 162cfa1ca9dSYoshinobu Inoue /* bidirectional configured tunnel mode */ 163cfa1ca9dSYoshinobu Inoue if (sin_dst->sin_addr.s_addr != INADDR_ANY) 164cfa1ca9dSYoshinobu Inoue iphdr.ip_dst = sin_dst->sin_addr; 165cfa1ca9dSYoshinobu Inoue else { 166cfa1ca9dSYoshinobu Inoue m_freem(m); 167cfa1ca9dSYoshinobu Inoue return ENETUNREACH; 168cfa1ca9dSYoshinobu Inoue } 169cfa1ca9dSYoshinobu Inoue } 170cfa1ca9dSYoshinobu Inoue iphdr.ip_p = proto; 171cfa1ca9dSYoshinobu Inoue /* version will be set in ip_output() */ 172cfa1ca9dSYoshinobu Inoue iphdr.ip_ttl = ip_gif_ttl; 173cfa1ca9dSYoshinobu Inoue iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip); 1746a800098SYoshinobu Inoue if (ifp->if_flags & IFF_LINK1) 1756a800098SYoshinobu Inoue ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos); 176cfa1ca9dSYoshinobu Inoue 177cfa1ca9dSYoshinobu Inoue /* prepend new IP header */ 178cfa1ca9dSYoshinobu Inoue M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); 179cfa1ca9dSYoshinobu Inoue if (m && m->m_len < sizeof(struct ip)) 180cfa1ca9dSYoshinobu Inoue m = m_pullup(m, sizeof(struct ip)); 181cfa1ca9dSYoshinobu Inoue if (m == NULL) { 182cfa1ca9dSYoshinobu Inoue printf("ENOBUFS in in_gif_output %d\n", __LINE__); 183cfa1ca9dSYoshinobu Inoue return ENOBUFS; 184cfa1ca9dSYoshinobu Inoue } 185cfa1ca9dSYoshinobu Inoue 186cfa1ca9dSYoshinobu Inoue *(mtod(m, struct ip *)) = iphdr; 187cfa1ca9dSYoshinobu Inoue 188cfa1ca9dSYoshinobu Inoue if (dst->sin_family != sin_dst->sin_family || 189cfa1ca9dSYoshinobu Inoue dst->sin_addr.s_addr != sin_dst->sin_addr.s_addr) { 190cfa1ca9dSYoshinobu Inoue /* cache route doesn't match */ 191cfa1ca9dSYoshinobu Inoue dst->sin_family = sin_dst->sin_family; 192cfa1ca9dSYoshinobu Inoue dst->sin_len = sizeof(struct sockaddr_in); 193cfa1ca9dSYoshinobu Inoue dst->sin_addr = sin_dst->sin_addr; 194cfa1ca9dSYoshinobu Inoue if (sc->gif_ro.ro_rt) { 195cfa1ca9dSYoshinobu Inoue RTFREE(sc->gif_ro.ro_rt); 196cfa1ca9dSYoshinobu Inoue sc->gif_ro.ro_rt = NULL; 197cfa1ca9dSYoshinobu Inoue } 198cfa1ca9dSYoshinobu Inoue } 199cfa1ca9dSYoshinobu Inoue 200cfa1ca9dSYoshinobu Inoue if (sc->gif_ro.ro_rt == NULL) { 201cfa1ca9dSYoshinobu Inoue rtalloc(&sc->gif_ro); 202cfa1ca9dSYoshinobu Inoue if (sc->gif_ro.ro_rt == NULL) { 203cfa1ca9dSYoshinobu Inoue m_freem(m); 204cfa1ca9dSYoshinobu Inoue return ENETUNREACH; 205cfa1ca9dSYoshinobu Inoue } 206cfa1ca9dSYoshinobu Inoue } 207cfa1ca9dSYoshinobu Inoue 208cfa1ca9dSYoshinobu Inoue error = ip_output(m, 0, &sc->gif_ro, 0, 0); 209cfa1ca9dSYoshinobu Inoue return(error); 210cfa1ca9dSYoshinobu Inoue } 211cfa1ca9dSYoshinobu Inoue 212cfa1ca9dSYoshinobu Inoue void 2136a800098SYoshinobu Inoue in_gif_input(struct mbuf *m, int off, int proto) 214cfa1ca9dSYoshinobu Inoue { 215cfa1ca9dSYoshinobu Inoue struct gif_softc *sc; 216cfa1ca9dSYoshinobu Inoue struct ifnet *gifp = NULL; 217cfa1ca9dSYoshinobu Inoue struct ip *ip; 218cfa1ca9dSYoshinobu Inoue int i, af; 2196a800098SYoshinobu Inoue u_int8_t otos; 220cfa1ca9dSYoshinobu Inoue 221cfa1ca9dSYoshinobu Inoue ip = mtod(m, struct ip *); 222cfa1ca9dSYoshinobu Inoue 223cfa1ca9dSYoshinobu Inoue /* this code will be soon improved. */ 224cfa1ca9dSYoshinobu Inoue #define satosin(sa) ((struct sockaddr_in *)(sa)) 225cfa1ca9dSYoshinobu Inoue for (i = 0, sc = gif; i < ngif; i++, sc++) { 226cfa1ca9dSYoshinobu Inoue if (sc->gif_psrc == NULL 227cfa1ca9dSYoshinobu Inoue || sc->gif_pdst == NULL 228cfa1ca9dSYoshinobu Inoue || sc->gif_psrc->sa_family != AF_INET 229cfa1ca9dSYoshinobu Inoue || sc->gif_pdst->sa_family != AF_INET) { 230cfa1ca9dSYoshinobu Inoue continue; 231cfa1ca9dSYoshinobu Inoue } 232cfa1ca9dSYoshinobu Inoue 233cfa1ca9dSYoshinobu Inoue if ((sc->gif_if.if_flags & IFF_UP) == 0) 234cfa1ca9dSYoshinobu Inoue continue; 235cfa1ca9dSYoshinobu Inoue 236cfa1ca9dSYoshinobu Inoue if ((sc->gif_if.if_flags & IFF_LINK0) 237cfa1ca9dSYoshinobu Inoue && satosin(sc->gif_psrc)->sin_addr.s_addr == ip->ip_dst.s_addr 238cfa1ca9dSYoshinobu Inoue && satosin(sc->gif_pdst)->sin_addr.s_addr == INADDR_ANY) { 239cfa1ca9dSYoshinobu Inoue gifp = &sc->gif_if; 240cfa1ca9dSYoshinobu Inoue continue; 241cfa1ca9dSYoshinobu Inoue } 242cfa1ca9dSYoshinobu Inoue 243cfa1ca9dSYoshinobu Inoue if (satosin(sc->gif_psrc)->sin_addr.s_addr == ip->ip_dst.s_addr 244cfa1ca9dSYoshinobu Inoue && satosin(sc->gif_pdst)->sin_addr.s_addr == ip->ip_src.s_addr) 245cfa1ca9dSYoshinobu Inoue { 246cfa1ca9dSYoshinobu Inoue gifp = &sc->gif_if; 247cfa1ca9dSYoshinobu Inoue break; 248cfa1ca9dSYoshinobu Inoue } 249cfa1ca9dSYoshinobu Inoue } 250cfa1ca9dSYoshinobu Inoue 251cfa1ca9dSYoshinobu Inoue if (gifp == NULL) { 252cfa1ca9dSYoshinobu Inoue #ifdef MROUTING 253cfa1ca9dSYoshinobu Inoue /* for backward compatibility */ 254cfa1ca9dSYoshinobu Inoue if (proto == IPPROTO_IPV4) { 2556a800098SYoshinobu Inoue ipip_input(m, off, proto); 256cfa1ca9dSYoshinobu Inoue return; 257cfa1ca9dSYoshinobu Inoue } 258cfa1ca9dSYoshinobu Inoue #endif /*MROUTING*/ 259cfa1ca9dSYoshinobu Inoue m_freem(m); 260cfa1ca9dSYoshinobu Inoue ipstat.ips_nogif++; 261cfa1ca9dSYoshinobu Inoue return; 262cfa1ca9dSYoshinobu Inoue } 263cfa1ca9dSYoshinobu Inoue 2646a800098SYoshinobu Inoue otos = ip->ip_tos; 265cfa1ca9dSYoshinobu Inoue m_adj(m, off); 266cfa1ca9dSYoshinobu Inoue 267cfa1ca9dSYoshinobu Inoue switch (proto) { 268cfa1ca9dSYoshinobu Inoue case IPPROTO_IPV4: 269cfa1ca9dSYoshinobu Inoue { 270cfa1ca9dSYoshinobu Inoue struct ip *ip; 271cfa1ca9dSYoshinobu Inoue af = AF_INET; 272cfa1ca9dSYoshinobu Inoue if (m->m_len < sizeof(*ip)) { 273cfa1ca9dSYoshinobu Inoue m = m_pullup(m, sizeof(*ip)); 274cfa1ca9dSYoshinobu Inoue if (!m) 275cfa1ca9dSYoshinobu Inoue return; 276cfa1ca9dSYoshinobu Inoue } 277cfa1ca9dSYoshinobu Inoue ip = mtod(m, struct ip *); 2786a800098SYoshinobu Inoue if (gifp->if_flags & IFF_LINK1) 2796a800098SYoshinobu Inoue ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos); 280cfa1ca9dSYoshinobu Inoue break; 281cfa1ca9dSYoshinobu Inoue } 282cfa1ca9dSYoshinobu Inoue #ifdef INET6 283cfa1ca9dSYoshinobu Inoue case IPPROTO_IPV6: 284cfa1ca9dSYoshinobu Inoue { 285cfa1ca9dSYoshinobu Inoue struct ip6_hdr *ip6; 2866a800098SYoshinobu Inoue u_int8_t itos; 287cfa1ca9dSYoshinobu Inoue af = AF_INET6; 288cfa1ca9dSYoshinobu Inoue if (m->m_len < sizeof(*ip6)) { 289cfa1ca9dSYoshinobu Inoue m = m_pullup(m, sizeof(*ip6)); 290cfa1ca9dSYoshinobu Inoue if (!m) 291cfa1ca9dSYoshinobu Inoue return; 292cfa1ca9dSYoshinobu Inoue } 293cfa1ca9dSYoshinobu Inoue ip6 = mtod(m, struct ip6_hdr *); 2946a800098SYoshinobu Inoue itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 2956a800098SYoshinobu Inoue if (gifp->if_flags & IFF_LINK1) 2966a800098SYoshinobu Inoue ip_ecn_egress(ECN_ALLOWED, &otos, &itos); 297cfa1ca9dSYoshinobu Inoue ip6->ip6_flow &= ~htonl(0xff << 20); 2986a800098SYoshinobu Inoue ip6->ip6_flow |= htonl((u_int32_t)itos << 20); 299cfa1ca9dSYoshinobu Inoue break; 300cfa1ca9dSYoshinobu Inoue } 301cfa1ca9dSYoshinobu Inoue #endif /* INET6 */ 302cfa1ca9dSYoshinobu Inoue default: 303cfa1ca9dSYoshinobu Inoue ipstat.ips_nogif++; 304cfa1ca9dSYoshinobu Inoue m_freem(m); 305cfa1ca9dSYoshinobu Inoue return; 306cfa1ca9dSYoshinobu Inoue } 307cfa1ca9dSYoshinobu Inoue gif_input(m, af, gifp); 308cfa1ca9dSYoshinobu Inoue return; 309cfa1ca9dSYoshinobu Inoue } 310