1/* $NetBSD: ip_gre.c,v 1.21 2002/08/14 00:23:30 itojun Exp $ */
| 1/* $NetBSD: ip_gre.c,v 1.21 2002/08/14 00:23:30 itojun Exp $ */
|
2/* $FreeBSD: head/sys/netinet/ip_gre.c 107670 2002-12-07 14:22:05Z sobomax $ */
| 2/* $FreeBSD: head/sys/netinet/ip_gre.c 111888 2003-03-04 23:19:55Z jlemon $ */
|
3 4/* 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Heiko W.Rupp <hwr@pilhuhn.de> 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40/* 41 * deencapsulate tunneled packets and send them on 42 * output half is in net/if_gre.[ch] 43 * This currently handles IPPROTO_GRE, IPPROTO_MOBILE 44 */ 45 46#include "opt_inet.h" 47#include "opt_ns.h" 48#include "opt_atalk.h" 49 50#include <sys/param.h> 51#include <sys/systm.h> 52#include <sys/mbuf.h> 53#include <sys/socket.h> 54#include <sys/socketvar.h> 55#include <sys/protosw.h> 56#include <sys/errno.h> 57#include <sys/time.h> 58#include <sys/kernel.h> 59#include <sys/syslog.h> 60#include <net/bpf.h> 61#include <net/ethernet.h> 62#include <net/if.h> 63#include <net/netisr.h> 64#include <net/route.h> 65#include <net/raw_cb.h> 66 67#ifdef INET 68#include <netinet/in.h> 69#include <netinet/in_var.h> 70#include <netinet/in_systm.h> 71#include <netinet/ip.h> 72#include <netinet/ip_var.h> 73#include <netinet/ip_gre.h> 74#include <machine/in_cksum.h> 75#else 76#error ip_gre input without IP? 77#endif 78 79#ifdef NS 80#include <netns/ns.h> 81#include <netns/ns_if.h> 82#endif 83 84#ifdef NETATALK 85#include <netatalk/at.h> 86#include <netatalk/at_var.h> 87#include <netatalk/at_extern.h> 88#endif 89 90/* Needs IP headers. */ 91#include <net/if_gre.h> 92 93#include <machine/stdarg.h> 94 95#if 1 96void gre_inet_ntoa(struct in_addr in); /* XXX */ 97#endif 98 99static struct gre_softc *gre_lookup(struct mbuf *, u_int8_t); 100 101static int gre_input2(struct mbuf *, int, u_char); 102 103/* 104 * De-encapsulate a packet and feed it back through ip input (this 105 * routine is called whenever IP gets a packet with proto type 106 * IPPROTO_GRE and a local destination address). 107 * This really is simple 108 */ 109void 110#if __STDC__ 111gre_input(struct mbuf *m, ...) 112#else 113gre_input(m, va_alist) 114 struct mbuf *m; 115 va_dcl 116#endif 117{ 118 int off, ret, proto; 119 va_list ap; 120 121 va_start(ap, m); 122 off = va_arg(ap, int); 123 va_end(ap); 124 proto = (mtod(m, struct ip *))->ip_p; 125 126 ret = gre_input2(m, off, proto); 127 /* 128 * ret == 0 : packet not processed, meaning that 129 * no matching tunnel that is up is found. 130 * we inject it to raw ip socket to see if anyone picks it up. 131 */ 132 if (ret == 0) 133 rip_input(m, off); 134} 135 136/* 137 * decapsulate. 138 * Does the real work and is called from gre_input() (above) 139 * returns 0 if packet is not yet processed 140 * and 1 if it needs no further processing 141 * proto is the protocol number of the "calling" foo_input() 142 * routine. 143 */ 144 145static int 146gre_input2(struct mbuf *m ,int hlen, u_char proto) 147{ 148 struct greip *gip = mtod(m, struct greip *);
| 3 4/* 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Heiko W.Rupp <hwr@pilhuhn.de> 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40/* 41 * deencapsulate tunneled packets and send them on 42 * output half is in net/if_gre.[ch] 43 * This currently handles IPPROTO_GRE, IPPROTO_MOBILE 44 */ 45 46#include "opt_inet.h" 47#include "opt_ns.h" 48#include "opt_atalk.h" 49 50#include <sys/param.h> 51#include <sys/systm.h> 52#include <sys/mbuf.h> 53#include <sys/socket.h> 54#include <sys/socketvar.h> 55#include <sys/protosw.h> 56#include <sys/errno.h> 57#include <sys/time.h> 58#include <sys/kernel.h> 59#include <sys/syslog.h> 60#include <net/bpf.h> 61#include <net/ethernet.h> 62#include <net/if.h> 63#include <net/netisr.h> 64#include <net/route.h> 65#include <net/raw_cb.h> 66 67#ifdef INET 68#include <netinet/in.h> 69#include <netinet/in_var.h> 70#include <netinet/in_systm.h> 71#include <netinet/ip.h> 72#include <netinet/ip_var.h> 73#include <netinet/ip_gre.h> 74#include <machine/in_cksum.h> 75#else 76#error ip_gre input without IP? 77#endif 78 79#ifdef NS 80#include <netns/ns.h> 81#include <netns/ns_if.h> 82#endif 83 84#ifdef NETATALK 85#include <netatalk/at.h> 86#include <netatalk/at_var.h> 87#include <netatalk/at_extern.h> 88#endif 89 90/* Needs IP headers. */ 91#include <net/if_gre.h> 92 93#include <machine/stdarg.h> 94 95#if 1 96void gre_inet_ntoa(struct in_addr in); /* XXX */ 97#endif 98 99static struct gre_softc *gre_lookup(struct mbuf *, u_int8_t); 100 101static int gre_input2(struct mbuf *, int, u_char); 102 103/* 104 * De-encapsulate a packet and feed it back through ip input (this 105 * routine is called whenever IP gets a packet with proto type 106 * IPPROTO_GRE and a local destination address). 107 * This really is simple 108 */ 109void 110#if __STDC__ 111gre_input(struct mbuf *m, ...) 112#else 113gre_input(m, va_alist) 114 struct mbuf *m; 115 va_dcl 116#endif 117{ 118 int off, ret, proto; 119 va_list ap; 120 121 va_start(ap, m); 122 off = va_arg(ap, int); 123 va_end(ap); 124 proto = (mtod(m, struct ip *))->ip_p; 125 126 ret = gre_input2(m, off, proto); 127 /* 128 * ret == 0 : packet not processed, meaning that 129 * no matching tunnel that is up is found. 130 * we inject it to raw ip socket to see if anyone picks it up. 131 */ 132 if (ret == 0) 133 rip_input(m, off); 134} 135 136/* 137 * decapsulate. 138 * Does the real work and is called from gre_input() (above) 139 * returns 0 if packet is not yet processed 140 * and 1 if it needs no further processing 141 * proto is the protocol number of the "calling" foo_input() 142 * routine. 143 */ 144 145static int 146gre_input2(struct mbuf *m ,int hlen, u_char proto) 147{ 148 struct greip *gip = mtod(m, struct greip *);
|
149 int s; 150 struct ifqueue *ifq;
| 149 int isr;
|
151 struct gre_softc *sc; 152 u_short flags; 153 154 if ((sc = gre_lookup(m, proto)) == NULL) { 155 /* No matching tunnel or tunnel is down. */ 156 return (0); 157 } 158 159 sc->sc_if.if_ipackets++; 160 sc->sc_if.if_ibytes += m->m_pkthdr.len; 161 162 switch (proto) { 163 case IPPROTO_GRE: 164 hlen += sizeof (struct gre_h); 165 166 /* process GRE flags as packet can be of variable len */ 167 flags = ntohs(gip->gi_flags); 168 169 /* Checksum & Offset are present */ 170 if ((flags & GRE_CP) | (flags & GRE_RP)) 171 hlen += 4; 172 /* We don't support routing fields (variable length) */ 173 if (flags & GRE_RP) 174 return(0); 175 if (flags & GRE_KP) 176 hlen += 4; 177 if (flags & GRE_SP) 178 hlen +=4; 179 180 switch (ntohs(gip->gi_ptype)) { /* ethertypes */ 181 case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */ 182 case WCCP_PROTOCOL_TYPE: /* we are in ip_input */
| 150 struct gre_softc *sc; 151 u_short flags; 152 153 if ((sc = gre_lookup(m, proto)) == NULL) { 154 /* No matching tunnel or tunnel is down. */ 155 return (0); 156 } 157 158 sc->sc_if.if_ipackets++; 159 sc->sc_if.if_ibytes += m->m_pkthdr.len; 160 161 switch (proto) { 162 case IPPROTO_GRE: 163 hlen += sizeof (struct gre_h); 164 165 /* process GRE flags as packet can be of variable len */ 166 flags = ntohs(gip->gi_flags); 167 168 /* Checksum & Offset are present */ 169 if ((flags & GRE_CP) | (flags & GRE_RP)) 170 hlen += 4; 171 /* We don't support routing fields (variable length) */ 172 if (flags & GRE_RP) 173 return(0); 174 if (flags & GRE_KP) 175 hlen += 4; 176 if (flags & GRE_SP) 177 hlen +=4; 178 179 switch (ntohs(gip->gi_ptype)) { /* ethertypes */ 180 case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */ 181 case WCCP_PROTOCOL_TYPE: /* we are in ip_input */
|
183 ifq = &ipintrq;
| 182 isr = NETISR_IP;
|
184 break; 185#ifdef NS 186 case ETHERTYPE_NS:
| 183 break; 184#ifdef NS 185 case ETHERTYPE_NS:
|
187 ifq = &nsintrq; 188 schednetisr(NETISR_NS);
| 186 isr = NETISR_NS;
|
189 break; 190#endif 191#ifdef NETATALK 192 case ETHERTYPE_ATALK:
| 187 break; 188#endif 189#ifdef NETATALK 190 case ETHERTYPE_ATALK:
|
193 ifq = &atintrq1; 194 schednetisr(NETISR_ATALK);
| 191 isr = NETISR_ATALK1;
|
195 break; 196#endif 197 case ETHERTYPE_IPV6: 198 /* FALLTHROUGH */ 199 default: /* others not yet supported */ 200 return(0); 201 } 202 break; 203 default: 204 /* others not yet supported */ 205 return(0); 206 } 207 208 m->m_data += hlen; 209 m->m_len -= hlen; 210 m->m_pkthdr.len -= hlen; 211 212 if (sc->sc_if.if_bpf) { 213 struct mbuf m0; 214 u_int32_t af = AF_INET; 215 216 m0.m_next = m; 217 m0.m_len = 4; 218 m0.m_data = (char *)⁡ 219 220 BPF_MTAP(&(sc->sc_if), &m0); 221 } 222 223 m->m_pkthdr.rcvif = &sc->sc_if; 224
| 192 break; 193#endif 194 case ETHERTYPE_IPV6: 195 /* FALLTHROUGH */ 196 default: /* others not yet supported */ 197 return(0); 198 } 199 break; 200 default: 201 /* others not yet supported */ 202 return(0); 203 } 204 205 m->m_data += hlen; 206 m->m_len -= hlen; 207 m->m_pkthdr.len -= hlen; 208 209 if (sc->sc_if.if_bpf) { 210 struct mbuf m0; 211 u_int32_t af = AF_INET; 212 213 m0.m_next = m; 214 m0.m_len = 4; 215 m0.m_data = (char *)⁡ 216 217 BPF_MTAP(&(sc->sc_if), &m0); 218 } 219 220 m->m_pkthdr.rcvif = &sc->sc_if; 221
|
225 s = splnet(); /* possible */ 226 if (_IF_QFULL(ifq)) { 227 _IF_DROP(ifq); 228 m_freem(m); 229 } else { 230 IF_ENQUEUE(ifq,m); 231 } 232 splx(s);
| 222 netisr_dispatch(isr, m);
|
233 234 return(1); /* packet is done, no further processing needed */ 235} 236 237/* 238 * input routine for IPPRPOTO_MOBILE 239 * This is a little bit diffrent from the other modes, as the 240 * encapsulating header was not prepended, but instead inserted 241 * between IP header and payload 242 */ 243 244void 245#if __STDC__ 246gre_mobile_input(struct mbuf *m, ...) 247#else 248gre_mobile_input(m, va_alist) 249 struct mbuf *m; 250 va_dcl 251#endif 252{ 253 struct ip *ip = mtod(m, struct ip *); 254 struct mobip_h *mip = mtod(m, struct mobip_h *);
| 223 224 return(1); /* packet is done, no further processing needed */ 225} 226 227/* 228 * input routine for IPPRPOTO_MOBILE 229 * This is a little bit diffrent from the other modes, as the 230 * encapsulating header was not prepended, but instead inserted 231 * between IP header and payload 232 */ 233 234void 235#if __STDC__ 236gre_mobile_input(struct mbuf *m, ...) 237#else 238gre_mobile_input(m, va_alist) 239 struct mbuf *m; 240 va_dcl 241#endif 242{ 243 struct ip *ip = mtod(m, struct ip *); 244 struct mobip_h *mip = mtod(m, struct mobip_h *);
|
255 struct ifqueue *ifq;
| |
256 struct gre_softc *sc;
| 245 struct gre_softc *sc;
|
257 int hlen,s;
| 246 int hlen;
|
258 va_list ap; 259 u_char osrc = 0; 260 int msiz; 261 262 va_start(ap,m); 263 hlen = va_arg(ap, int); 264 va_end(ap); 265 266 if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { 267 /* No matching tunnel or tunnel is down. */ 268 m_freem(m); 269 return; 270 } 271 272 sc->sc_if.if_ipackets++; 273 sc->sc_if.if_ibytes += m->m_pkthdr.len; 274 275 if(ntohs(mip->mh.proto) & MOB_H_SBIT) { 276 osrc = 1; 277 msiz = MOB_H_SIZ_L; 278 mip->mi.ip_src.s_addr = mip->mh.osrc; 279 } else { 280 msiz = MOB_H_SIZ_S; 281 } 282 mip->mi.ip_dst.s_addr = mip->mh.odst; 283 mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); 284 285 if (gre_in_cksum((u_short*)&mip->mh,msiz) != 0) { 286 m_freem(m); 287 return; 288 } 289 290 bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) + 291 (ip->ip_hl << 2), m->m_len - msiz - (ip->ip_hl << 2)); 292 m->m_len -= msiz; 293 m->m_pkthdr.len -= msiz; 294 295 /* 296 * On FreeBSD, rip_input() supplies us with ip->ip_len 297 * already converted into host byteorder and also decreases 298 * it by the lengh of IP header, however, ip_input() expects 299 * that this field is in the original format (network byteorder 300 * and full size of IP packet), so that adjust accordingly. 301 */ 302 ip->ip_len = htons(ip->ip_len + sizeof(struct ip) - msiz); 303 304 ip->ip_sum = 0; 305 ip->ip_sum = in_cksum(m, (ip->ip_hl << 2)); 306 307 if (sc->sc_if.if_bpf) { 308 struct mbuf m0; 309 u_int af = AF_INET; 310 311 m0.m_next = m; 312 m0.m_len = 4; 313 m0.m_data = (char *)⁡ 314 315 BPF_MTAP(&(sc->sc_if), &m0); 316 } 317 318 m->m_pkthdr.rcvif = &sc->sc_if; 319
| 247 va_list ap; 248 u_char osrc = 0; 249 int msiz; 250 251 va_start(ap,m); 252 hlen = va_arg(ap, int); 253 va_end(ap); 254 255 if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { 256 /* No matching tunnel or tunnel is down. */ 257 m_freem(m); 258 return; 259 } 260 261 sc->sc_if.if_ipackets++; 262 sc->sc_if.if_ibytes += m->m_pkthdr.len; 263 264 if(ntohs(mip->mh.proto) & MOB_H_SBIT) { 265 osrc = 1; 266 msiz = MOB_H_SIZ_L; 267 mip->mi.ip_src.s_addr = mip->mh.osrc; 268 } else { 269 msiz = MOB_H_SIZ_S; 270 } 271 mip->mi.ip_dst.s_addr = mip->mh.odst; 272 mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); 273 274 if (gre_in_cksum((u_short*)&mip->mh,msiz) != 0) { 275 m_freem(m); 276 return; 277 } 278 279 bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) + 280 (ip->ip_hl << 2), m->m_len - msiz - (ip->ip_hl << 2)); 281 m->m_len -= msiz; 282 m->m_pkthdr.len -= msiz; 283 284 /* 285 * On FreeBSD, rip_input() supplies us with ip->ip_len 286 * already converted into host byteorder and also decreases 287 * it by the lengh of IP header, however, ip_input() expects 288 * that this field is in the original format (network byteorder 289 * and full size of IP packet), so that adjust accordingly. 290 */ 291 ip->ip_len = htons(ip->ip_len + sizeof(struct ip) - msiz); 292 293 ip->ip_sum = 0; 294 ip->ip_sum = in_cksum(m, (ip->ip_hl << 2)); 295 296 if (sc->sc_if.if_bpf) { 297 struct mbuf m0; 298 u_int af = AF_INET; 299 300 m0.m_next = m; 301 m0.m_len = 4; 302 m0.m_data = (char *)⁡ 303 304 BPF_MTAP(&(sc->sc_if), &m0); 305 } 306 307 m->m_pkthdr.rcvif = &sc->sc_if; 308
|
320 ifq = &ipintrq; 321 s = splnet(); /* possible */ 322 if (_IF_QFULL(ifq)) { 323 _IF_DROP(ifq); 324 m_freem(m); 325 } else { 326 IF_ENQUEUE(ifq,m); 327 } 328 splx(s);
| 309 netisr_dispatch(NETISR_IP, m);
|
329} 330 331/* 332 * Find the gre interface associated with our src/dst/proto set. 333 */ 334static struct gre_softc * 335gre_lookup(m, proto) 336 struct mbuf *m; 337 u_int8_t proto; 338{ 339 struct ip *ip = mtod(m, struct ip *); 340 struct gre_softc *sc; 341 342 for (sc = LIST_FIRST(&gre_softc_list); sc != NULL; 343 sc = LIST_NEXT(sc, sc_list)) { 344 if ((sc->g_dst.s_addr == ip->ip_src.s_addr) && 345 (sc->g_src.s_addr == ip->ip_dst.s_addr) && 346 (sc->g_proto == proto) && 347 ((sc->sc_if.if_flags & IFF_UP) != 0)) 348 return (sc); 349 } 350 351 return (NULL); 352}
| 310} 311 312/* 313 * Find the gre interface associated with our src/dst/proto set. 314 */ 315static struct gre_softc * 316gre_lookup(m, proto) 317 struct mbuf *m; 318 u_int8_t proto; 319{ 320 struct ip *ip = mtod(m, struct ip *); 321 struct gre_softc *sc; 322 323 for (sc = LIST_FIRST(&gre_softc_list); sc != NULL; 324 sc = LIST_NEXT(sc, sc_list)) { 325 if ((sc->g_dst.s_addr == ip->ip_src.s_addr) && 326 (sc->g_src.s_addr == ip->ip_dst.s_addr) && 327 (sc->g_proto == proto) && 328 ((sc->sc_if.if_flags & IFF_UP) != 0)) 329 return (sc); 330 } 331 332 return (NULL); 333}
|