| File: | net/pipex.c |
| Warning: | line 1832, column 2 Value stored to 'length' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: pipex.c,v 1.136 2022/01/02 22:36:04 jsg Exp $ */ |
| 2 | |
| 3 | /*- |
| 4 | * Copyright (c) 2009 Internet Initiative Japan Inc. |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * Redistribution and use in source and binary forms, with or without |
| 8 | * modification, are permitted provided that the following conditions |
| 9 | * are met: |
| 10 | * 1. Redistributions of source code must retain the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer. |
| 12 | * 2. Redistributions in binary form must reproduce the above copyright |
| 13 | * notice, this list of conditions and the following disclaimer in the |
| 14 | * documentation and/or other materials provided with the distribution. |
| 15 | * |
| 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 26 | * SUCH DAMAGE. |
| 27 | */ |
| 28 | |
| 29 | #include <sys/param.h> |
| 30 | #include <sys/systm.h> |
| 31 | #include <sys/mbuf.h> |
| 32 | #include <sys/socket.h> |
| 33 | #include <sys/ioctl.h> |
| 34 | #include <sys/select.h> |
| 35 | #include <sys/sysctl.h> |
| 36 | #include <sys/syslog.h> |
| 37 | #include <sys/conf.h> |
| 38 | #include <sys/time.h> |
| 39 | #include <sys/timeout.h> |
| 40 | #include <sys/kernel.h> |
| 41 | #include <sys/pool.h> |
| 42 | #include <sys/percpu.h> |
| 43 | |
| 44 | #include <net/if.h> |
| 45 | #include <net/if_types.h> |
| 46 | #include <netinet/in.h> |
| 47 | #include <netinet/if_ether.h> |
| 48 | #include <net/if_dl.h> |
| 49 | |
| 50 | #include <net/radix.h> |
| 51 | #include <net/route.h> |
| 52 | #include <net/ppp_defs.h> |
| 53 | #include <net/ppp-comp.h> |
| 54 | |
| 55 | #include "pf.h" |
| 56 | #if NPF1 > 0 |
| 57 | #include <net/pfvar.h> |
| 58 | #endif |
| 59 | |
| 60 | #include "bpfilter.h" |
| 61 | #if NBPFILTER1 > 0 |
| 62 | #include <net/bpf.h> |
| 63 | #endif |
| 64 | |
| 65 | #include <netinet/ip.h> |
| 66 | #include <netinet/ip_var.h> |
| 67 | #ifdef INET61 |
| 68 | #include <netinet/ip6.h> |
| 69 | #include <netinet6/ip6_var.h> |
| 70 | #endif |
| 71 | #include <netinet/tcp.h> |
| 72 | #include <netinet/udp.h> |
| 73 | #include <netinet/udp_var.h> |
| 74 | #include <crypto/arc4.h> |
| 75 | |
| 76 | /* drop static for ddb debuggability */ |
| 77 | #define Static |
| 78 | |
| 79 | #include <net/pipex.h> |
| 80 | #include "pipex_local.h" |
| 81 | |
| 82 | struct pool pipex_session_pool; |
| 83 | struct pool mppe_key_pool; |
| 84 | |
| 85 | /* |
| 86 | * Global data |
| 87 | * Locks used to protect global data |
| 88 | * A atomic operation |
| 89 | * I immutable after creation |
| 90 | * N net lock |
| 91 | */ |
| 92 | |
| 93 | int pipex_enable = 0; /* [N] */ |
| 94 | struct pipex_hash_head |
| 95 | pipex_session_list, /* [N] master session list */ |
| 96 | pipex_close_wait_list, /* [N] expired session list */ |
| 97 | pipex_peer_addr_hashtable[PIPEX_HASH_SIZE(512/8)], /* [N] peer's address hash */ |
| 98 | pipex_id_hashtable[PIPEX_HASH_SIZE(512/8)]; /* [N] peer id hash */ |
| 99 | |
| 100 | struct radix_node_head *pipex_rd_head4 = NULL((void *)0); /* [N] */ |
| 101 | struct radix_node_head *pipex_rd_head6 = NULL((void *)0); /* [N] */ |
| 102 | struct timeout pipex_timer_ch; /* callout timer context */ |
| 103 | int pipex_prune = 1; /* [I] walk list every seconds */ |
| 104 | |
| 105 | /* borrow an mbuf pkthdr field */ |
| 106 | #define ph_ppp_protoether_vtag ether_vtag |
| 107 | |
| 108 | #ifdef PIPEX_DEBUG |
| 109 | int pipex_debug = 0; /* [A] systcl net.inet.ip.pipex_debug */ |
| 110 | #endif |
| 111 | |
| 112 | /* PPP compression == MPPE is assumed, so don't answer CCP Reset-Request. */ |
| 113 | #define PIPEX_NO_CCP_RESETACK1 1 |
| 114 | |
| 115 | /************************************************************************ |
| 116 | * Core functions |
| 117 | ************************************************************************/ |
| 118 | void |
| 119 | pipex_init(void) |
| 120 | { |
| 121 | int i; |
| 122 | static int pipex_init_done = 0; |
| 123 | |
| 124 | if (pipex_init_done++) |
| 125 | return; |
| 126 | |
| 127 | rn_init(sizeof(struct sockaddr_in6)); |
| 128 | |
| 129 | pool_init(&pipex_session_pool, sizeof(struct pipex_session), 0, |
| 130 | IPL_SOFTNET0x5, PR_WAITOK0x0001, "ppxss", NULL((void *)0)); |
| 131 | pool_init(&mppe_key_pool, PIPEX_MPPE_KEYLEN16 * PIPEX_MPPE_NOLDKEY64, 0, |
| 132 | IPL_SOFTNET0x5, PR_WAITOK0x0001, "mppekey", NULL((void *)0)); |
| 133 | |
| 134 | LIST_INIT(&pipex_session_list)do { ((&pipex_session_list)->lh_first) = ((void *)0); } while (0); |
| 135 | LIST_INIT(&pipex_close_wait_list)do { ((&pipex_close_wait_list)->lh_first) = ((void *)0 ); } while (0); |
| 136 | |
| 137 | for (i = 0; i < nitems(pipex_id_hashtable)(sizeof((pipex_id_hashtable)) / sizeof((pipex_id_hashtable)[0 ])); i++) |
| 138 | LIST_INIT(&pipex_id_hashtable[i])do { ((&pipex_id_hashtable[i])->lh_first) = ((void *)0 ); } while (0); |
| 139 | for (i = 0; i < nitems(pipex_peer_addr_hashtable)(sizeof((pipex_peer_addr_hashtable)) / sizeof((pipex_peer_addr_hashtable )[0])); i++) |
| 140 | LIST_INIT(&pipex_peer_addr_hashtable[i])do { ((&pipex_peer_addr_hashtable[i])->lh_first) = ((void *)0); } while (0); |
| 141 | } |
| 142 | |
| 143 | void |
| 144 | pipex_destroy_all_sessions(void *ownersc) |
| 145 | { |
| 146 | struct pipex_session *session, *session_tmp; |
| 147 | |
| 148 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 149 | |
| 150 | LIST_FOREACH_SAFE(session, &pipex_session_list, session_list,for ((session) = ((&pipex_session_list)->lh_first); (session ) && ((session_tmp) = ((session)->session_list.le_next ), 1); (session) = (session_tmp)) |
| 151 | session_tmp)for ((session) = ((&pipex_session_list)->lh_first); (session ) && ((session_tmp) = ((session)->session_list.le_next ), 1); (session) = (session_tmp)) { |
| 152 | if (session->ownersc == ownersc) { |
| 153 | KASSERT(session->is_pppx == 0)((session->is_pppx == 0) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 153, "session->is_pppx == 0" )); |
| 154 | pipex_unlink_session(session); |
| 155 | pipex_rele_session(session); |
| 156 | } |
| 157 | } |
| 158 | } |
| 159 | |
| 160 | int |
| 161 | pipex_ioctl(void *ownersc, u_long cmd, caddr_t data) |
| 162 | { |
| 163 | int ret = 0; |
| 164 | |
| 165 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 166 | switch (cmd) { |
| 167 | case PIPEXCSESSION((unsigned long)0x80000000 | ((sizeof(struct pipex_session_config_req ) & 0x1fff) << 16) | ((('p')) << 8) | ((5))): |
| 168 | ret = pipex_config_session( |
| 169 | (struct pipex_session_config_req *)data, ownersc); |
| 170 | break; |
| 171 | |
| 172 | case PIPEXGSTAT(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct pipex_session_stat_req) & 0x1fff) << 16) | ( (('p')) << 8) | ((6))): |
| 173 | ret = pipex_get_stat((struct pipex_session_stat_req *)data, |
| 174 | ownersc); |
| 175 | break; |
| 176 | |
| 177 | case PIPEXGCLOSED((unsigned long)0x40000000 | ((sizeof(struct pipex_session_list_req ) & 0x1fff) << 16) | ((('p')) << 8) | ((7))): |
| 178 | ret = pipex_get_closed((struct pipex_session_list_req *)data, |
| 179 | ownersc); |
| 180 | break; |
| 181 | |
| 182 | default: |
| 183 | ret = ENOTTY25; |
| 184 | break; |
| 185 | } |
| 186 | |
| 187 | return (ret); |
| 188 | } |
| 189 | |
| 190 | /************************************************************************ |
| 191 | * Session management functions |
| 192 | ************************************************************************/ |
| 193 | int |
| 194 | pipex_init_session(struct pipex_session **rsession, |
| 195 | struct pipex_session_req *req) |
| 196 | { |
| 197 | struct pipex_session *session; |
| 198 | #ifdef PIPEX_PPPOE1 |
| 199 | struct ifnet *over_ifp = NULL((void *)0); |
| 200 | #endif |
| 201 | |
| 202 | /* Checks requested parameters. */ |
| 203 | switch (req->pr_protocol) { |
| 204 | #ifdef PIPEX_PPPOE1 |
| 205 | case PIPEX_PROTO_PPPOE3: |
| 206 | if (req->pr_peer_address.ss_family != AF_UNSPEC0) |
| 207 | return (EINVAL22); |
| 208 | break; |
| 209 | #endif |
| 210 | #if defined(PIPEX_L2TP1) || defined(PIPEX_PPTP1) |
| 211 | case PIPEX_PROTO_PPTP2: |
| 212 | case PIPEX_PROTO_L2TP1: |
| 213 | switch (req->pr_peer_address.ss_family) { |
| 214 | case AF_INET2: |
| 215 | if (req->pr_peer_address.ss_len != |
| 216 | sizeof(struct sockaddr_in)) |
| 217 | return (EINVAL22); |
| 218 | break; |
| 219 | #ifdef INET61 |
| 220 | case AF_INET624: |
| 221 | if (req->pr_peer_address.ss_len != |
| 222 | sizeof(struct sockaddr_in6)) |
| 223 | return (EINVAL22); |
| 224 | break; |
| 225 | #endif |
| 226 | default: |
| 227 | return (EPROTONOSUPPORT43); |
| 228 | } |
| 229 | if (req->pr_peer_address.ss_family != |
| 230 | req->pr_local_address.ss_family || |
| 231 | req->pr_peer_address.ss_len != |
| 232 | req->pr_local_address.ss_len) |
| 233 | return (EINVAL22); |
| 234 | break; |
| 235 | #endif /* defined(PIPEX_PPTP) || defined(PIPEX_L2TP) */ |
| 236 | default: |
| 237 | return (EPROTONOSUPPORT43); |
| 238 | } |
| 239 | #ifdef PIPEX_MPPE1 |
| 240 | if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED0x0010) != 0) { |
| 241 | if (req->pr_mppe_recv.keylenbits <= 0) |
| 242 | return (EINVAL22); |
| 243 | } |
| 244 | if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED0x0020) != 0) { |
| 245 | if (req->pr_mppe_send.keylenbits <= 0) |
| 246 | return (EINVAL22); |
| 247 | } |
| 248 | if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_REQUIRED0x0040) != 0) { |
| 249 | if ((req->pr_ppp_flags & |
| 250 | (PIPEX_PPP_MPPE_ACCEPTED0x0010 | PIPEX_PPP_MPPE_ENABLED0x0020)) != |
| 251 | (PIPEX_PPP_MPPE_ACCEPTED0x0010 | PIPEX_PPP_MPPE_ENABLED0x0020)) |
| 252 | return (EINVAL22); |
| 253 | } |
| 254 | #endif |
| 255 | |
| 256 | #ifdef PIPEX_PPPOE1 |
| 257 | if (req->pr_protocol == PIPEX_PROTO_PPPOE3) { |
| 258 | over_ifp = if_unit(req->pr_proto.pppoe.over_ifname); |
| 259 | if (over_ifp == NULL((void *)0)) |
| 260 | return (EINVAL22); |
| 261 | } |
| 262 | #endif |
| 263 | |
| 264 | /* prepare a new session */ |
| 265 | session = pool_get(&pipex_session_pool, PR_WAITOK0x0001 | PR_ZERO0x0008); |
| 266 | mtx_init(&session->pxs_mtx, IPL_SOFTNET)do { (void)(((void *)0)); (void)(0); __mtx_init((&session ->pxs_mtx), ((((0x5)) > 0x0 && ((0x5)) < 0x9 ) ? 0x9 : ((0x5)))); } while (0); |
| 267 | session->state = PIPEX_STATE_INITIAL0x0000; |
| 268 | session->protocol = req->pr_protocol; |
| 269 | session->session_id = req->pr_session_id; |
| 270 | session->peer_session_id = req->pr_peer_session_id; |
| 271 | session->peer_mru = req->pr_peer_mru; |
| 272 | session->timeout_sec = req->pr_timeout_sec; |
| 273 | session->ppp_flags = req->pr_ppp_flags; |
| 274 | session->ppp_id = req->pr_ppp_id; |
| 275 | |
| 276 | session->ip_forward = 1; |
| 277 | |
| 278 | session->stat_counters = counters_alloc(pxc_ncounters); |
| 279 | |
| 280 | session->ip_address.sin_family = AF_INET2; |
| 281 | session->ip_address.sin_len = sizeof(struct sockaddr_in); |
| 282 | session->ip_address.sin_addr = req->pr_ip_address; |
| 283 | |
| 284 | session->ip_netmask.sin_family = AF_INET2; |
| 285 | session->ip_netmask.sin_len = sizeof(struct sockaddr_in); |
| 286 | session->ip_netmask.sin_addr = req->pr_ip_netmask; |
| 287 | |
| 288 | if (session->ip_netmask.sin_addr.s_addr == 0L) |
| 289 | session->ip_netmask.sin_addr.s_addr = 0xffffffffL; |
| 290 | session->ip_address.sin_addr.s_addr &= |
| 291 | session->ip_netmask.sin_addr.s_addr; |
| 292 | |
| 293 | if (req->pr_peer_address.ss_len > 0) |
| 294 | memcpy(&session->peer, &req->pr_peer_address,__builtin_memcpy((&session->peer), (&req->pr_peer_address ), ((((req->pr_peer_address.ss_len)<(sizeof(session-> peer)))?(req->pr_peer_address.ss_len):(sizeof(session-> peer))))) |
| 295 | MIN(req->pr_peer_address.ss_len, sizeof(session->peer)))__builtin_memcpy((&session->peer), (&req->pr_peer_address ), ((((req->pr_peer_address.ss_len)<(sizeof(session-> peer)))?(req->pr_peer_address.ss_len):(sizeof(session-> peer))))); |
| 296 | if (req->pr_local_address.ss_len > 0) |
| 297 | memcpy(&session->local, &req->pr_local_address,__builtin_memcpy((&session->local), (&req->pr_local_address ), ((((req->pr_local_address.ss_len)<(sizeof(session-> local)))?(req->pr_local_address.ss_len):(sizeof(session-> local))))) |
| 298 | MIN(req->pr_local_address.ss_len, sizeof(session->local)))__builtin_memcpy((&session->local), (&req->pr_local_address ), ((((req->pr_local_address.ss_len)<(sizeof(session-> local)))?(req->pr_local_address.ss_len):(sizeof(session-> local))))); |
| 299 | #ifdef PIPEX_PPPOE1 |
| 300 | if (req->pr_protocol == PIPEX_PROTO_PPPOE3) { |
| 301 | session->proto.pppoe.over_ifidx = over_ifp->if_index; |
| 302 | if_put(over_ifp); |
| 303 | } |
| 304 | #endif |
| 305 | #ifdef PIPEX_PPTP1 |
| 306 | if (req->pr_protocol == PIPEX_PROTO_PPTP2) { |
| 307 | struct pipex_pptp_session *sess_pptp = &session->proto.pptp; |
| 308 | |
| 309 | sess_pptp->snd_gap = 0; |
| 310 | sess_pptp->rcv_gap = 0; |
| 311 | sess_pptp->snd_una = req->pr_proto.pptp.snd_una; |
| 312 | sess_pptp->snd_nxt = req->pr_proto.pptp.snd_nxt; |
| 313 | sess_pptp->rcv_nxt = req->pr_proto.pptp.rcv_nxt; |
| 314 | sess_pptp->rcv_acked = req->pr_proto.pptp.rcv_acked; |
| 315 | |
| 316 | sess_pptp->winsz = req->pr_proto.pptp.winsz; |
| 317 | sess_pptp->maxwinsz = req->pr_proto.pptp.maxwinsz; |
| 318 | sess_pptp->peer_maxwinsz = req->pr_proto.pptp.peer_maxwinsz; |
| 319 | /* last ack number */ |
| 320 | sess_pptp->ul_snd_una = sess_pptp->snd_una - 1; |
| 321 | } |
| 322 | #endif |
| 323 | #ifdef PIPEX_L2TP1 |
| 324 | if (req->pr_protocol == PIPEX_PROTO_L2TP1) { |
| 325 | struct pipex_l2tp_session *sess_l2tp = &session->proto.l2tp; |
| 326 | |
| 327 | /* session keys */ |
| 328 | sess_l2tp->tunnel_id = req->pr_proto.l2tp.tunnel_id; |
| 329 | sess_l2tp->peer_tunnel_id = req->pr_proto.l2tp.peer_tunnel_id; |
| 330 | |
| 331 | /* protocol options */ |
| 332 | sess_l2tp->option_flags = req->pr_proto.l2tp.option_flags; |
| 333 | |
| 334 | /* initial state of dynamic context */ |
| 335 | sess_l2tp->ns_gap = sess_l2tp->nr_gap = 0; |
| 336 | sess_l2tp->ns_nxt = req->pr_proto.l2tp.ns_nxt; |
| 337 | sess_l2tp->nr_nxt = req->pr_proto.l2tp.nr_nxt; |
| 338 | sess_l2tp->ns_una = req->pr_proto.l2tp.ns_una; |
| 339 | sess_l2tp->nr_acked = req->pr_proto.l2tp.nr_acked; |
| 340 | /* last ack number */ |
| 341 | sess_l2tp->ul_ns_una = sess_l2tp->ns_una - 1; |
| 342 | sess_l2tp->ipsecflowinfo = req->pr_proto.l2tp.ipsecflowinfo; |
| 343 | } |
| 344 | #endif |
| 345 | #ifdef PIPEX_MPPE1 |
| 346 | if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED0x0010) != 0) { |
| 347 | pipex_session_init_mppe_recv(session, |
| 348 | req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits, |
| 349 | req->pr_mppe_recv.master_key); |
| 350 | } |
| 351 | if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED0x0020) != 0) { |
| 352 | pipex_session_init_mppe_send(session, |
| 353 | req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits, |
| 354 | req->pr_mppe_send.master_key); |
| 355 | } |
| 356 | #endif |
| 357 | |
| 358 | *rsession = session; |
| 359 | |
| 360 | return 0; |
| 361 | } |
| 362 | |
| 363 | void |
| 364 | pipex_rele_session(struct pipex_session *session) |
| 365 | { |
| 366 | if (session->mppe_recv.old_session_keys) |
| 367 | pool_put(&mppe_key_pool, session->mppe_recv.old_session_keys); |
| 368 | counters_free(session->stat_counters, pxc_ncounters); |
| 369 | pool_put(&pipex_session_pool, session); |
| 370 | } |
| 371 | |
| 372 | int |
| 373 | pipex_link_session(struct pipex_session *session, struct ifnet *ifp, |
| 374 | void *ownersc) |
| 375 | { |
| 376 | struct pipex_hash_head *chain; |
| 377 | struct radix_node *rn; |
| 378 | |
| 379 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 380 | |
| 381 | if (pipex_rd_head4 == NULL((void *)0)) { |
| 382 | if (!rn_inithead((void **)&pipex_rd_head4, |
| 383 | offsetof(struct sockaddr_in, sin_addr)__builtin_offsetof(struct sockaddr_in, sin_addr))) |
| 384 | panic("rn_inithead() failed on pipex_link_session()"); |
| 385 | } |
| 386 | if (pipex_rd_head6 == NULL((void *)0)) { |
| 387 | if (!rn_inithead((void **)&pipex_rd_head6, |
| 388 | offsetof(struct sockaddr_in6, sin6_addr)__builtin_offsetof(struct sockaddr_in6, sin6_addr))) |
| 389 | panic("rn_inithead() failed on pipex_link_session()"); |
| 390 | } |
| 391 | if (pipex_lookup_by_session_id(session->protocol, |
| 392 | session->session_id)) |
| 393 | return (EEXIST17); |
| 394 | |
| 395 | session->ownersc = ownersc; |
| 396 | session->ifindex = ifp->if_index; |
| 397 | if (ifp->if_flags & IFF_POINTOPOINT0x10) |
| 398 | session->is_pppx = 1; |
| 399 | |
| 400 | if (session->is_pppx == 0 && |
| 401 | !in_nullhost(session->ip_address.sin_addr)((session->ip_address.sin_addr).s_addr == ((u_int32_t) (__uint32_t )(__builtin_constant_p((u_int32_t)(0x00000000)) ? (__uint32_t )(((__uint32_t)((u_int32_t)(0x00000000)) & 0xff) << 24 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff00) << 8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff0000) >> 8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff000000) >> 24) : __swap32md((u_int32_t)(0x00000000)))))) { |
| 402 | if (pipex_lookup_by_ip_address(session->ip_address.sin_addr) |
| 403 | != NULL((void *)0)) |
| 404 | return (EADDRINUSE48); |
| 405 | rn = rn_addroute(&session->ip_address, &session->ip_netmask, |
| 406 | pipex_rd_head4, session->ps4_rn, RTP_STATIC8); |
| 407 | if (rn == NULL((void *)0)) |
| 408 | return (ENOMEM12); |
| 409 | } |
| 410 | |
| 411 | LIST_INSERT_HEAD(&pipex_session_list, session, session_list)do { if (((session)->session_list.le_next = (&pipex_session_list )->lh_first) != ((void *)0)) (&pipex_session_list)-> lh_first->session_list.le_prev = &(session)->session_list .le_next; (&pipex_session_list)->lh_first = (session); (session)->session_list.le_prev = &(&pipex_session_list )->lh_first; } while (0); |
| 412 | chain = PIPEX_ID_HASHTABLE(session->session_id)(&pipex_id_hashtable[(session->session_id) & ((512 /8)-1)]); |
| 413 | LIST_INSERT_HEAD(chain, session, id_chain)do { if (((session)->id_chain.le_next = (chain)->lh_first ) != ((void *)0)) (chain)->lh_first->id_chain.le_prev = &(session)->id_chain.le_next; (chain)->lh_first = ( session); (session)->id_chain.le_prev = &(chain)->lh_first ; } while (0); |
| 414 | #if defined(PIPEX_PPTP1) || defined(PIPEX_L2TP1) |
| 415 | switch (session->protocol) { |
| 416 | case PIPEX_PROTO_PPTP2: |
| 417 | case PIPEX_PROTO_L2TP1: |
| 418 | chain = PIPEX_PEER_ADDR_HASHTABLE((&pipex_peer_addr_hashtable[(pipex_sockaddr_hash_key(& session->peer.sa)) & ((512/8)-1)]) |
| 419 | pipex_sockaddr_hash_key(&session->peer.sa))(&pipex_peer_addr_hashtable[(pipex_sockaddr_hash_key(& session->peer.sa)) & ((512/8)-1)]); |
| 420 | LIST_INSERT_HEAD(chain, session, peer_addr_chain)do { if (((session)->peer_addr_chain.le_next = (chain)-> lh_first) != ((void *)0)) (chain)->lh_first->peer_addr_chain .le_prev = &(session)->peer_addr_chain.le_next; (chain )->lh_first = (session); (session)->peer_addr_chain.le_prev = &(chain)->lh_first; } while (0); |
| 421 | } |
| 422 | #endif |
| 423 | |
| 424 | /* if first session is added, start timer */ |
| 425 | if (LIST_NEXT(session, session_list)((session)->session_list.le_next) == NULL((void *)0)) |
| 426 | pipex_timer_start(); |
| 427 | session->state = PIPEX_STATE_OPENED0x0001; |
| 428 | |
| 429 | return (0); |
| 430 | } |
| 431 | |
| 432 | void |
| 433 | pipex_unlink_session(struct pipex_session *session) |
| 434 | { |
| 435 | struct radix_node *rn; |
| 436 | |
| 437 | session->ifindex = 0; |
| 438 | |
| 439 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 440 | if (session->state == PIPEX_STATE_CLOSED0x0004) |
| 441 | return; |
| 442 | if (session->is_pppx == 0 && |
| 443 | !in_nullhost(session->ip_address.sin_addr)((session->ip_address.sin_addr).s_addr == ((u_int32_t) (__uint32_t )(__builtin_constant_p((u_int32_t)(0x00000000)) ? (__uint32_t )(((__uint32_t)((u_int32_t)(0x00000000)) & 0xff) << 24 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff00) << 8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff0000) >> 8 | ((__uint32_t)((u_int32_t)(0x00000000)) & 0xff000000) >> 24) : __swap32md((u_int32_t)(0x00000000)))))) { |
| 444 | KASSERT(pipex_rd_head4 != NULL)((pipex_rd_head4 != ((void *)0)) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 444, "pipex_rd_head4 != NULL")); |
| 445 | rn = rn_delete(&session->ip_address, &session->ip_netmask, |
| 446 | pipex_rd_head4, (struct radix_node *)session); |
| 447 | KASSERT(rn != NULL)((rn != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 447, "rn != NULL")); |
| 448 | } |
| 449 | |
| 450 | LIST_REMOVE(session, id_chain)do { if ((session)->id_chain.le_next != ((void *)0)) (session )->id_chain.le_next->id_chain.le_prev = (session)->id_chain .le_prev; *(session)->id_chain.le_prev = (session)->id_chain .le_next; ((session)->id_chain.le_prev) = ((void *)-1); (( session)->id_chain.le_next) = ((void *)-1); } while (0); |
| 451 | #if defined(PIPEX_PPTP1) || defined(PIPEX_L2TP1) |
| 452 | switch (session->protocol) { |
| 453 | case PIPEX_PROTO_PPTP2: |
| 454 | case PIPEX_PROTO_L2TP1: |
| 455 | LIST_REMOVE(session, peer_addr_chain)do { if ((session)->peer_addr_chain.le_next != ((void *)0) ) (session)->peer_addr_chain.le_next->peer_addr_chain.le_prev = (session)->peer_addr_chain.le_prev; *(session)->peer_addr_chain .le_prev = (session)->peer_addr_chain.le_next; ((session)-> peer_addr_chain.le_prev) = ((void *)-1); ((session)->peer_addr_chain .le_next) = ((void *)-1); } while (0); |
| 456 | break; |
| 457 | } |
| 458 | #endif |
| 459 | if (session->state == PIPEX_STATE_CLOSE_WAIT0x0002) |
| 460 | LIST_REMOVE(session, state_list)do { if ((session)->state_list.le_next != ((void *)0)) (session )->state_list.le_next->state_list.le_prev = (session)-> state_list.le_prev; *(session)->state_list.le_prev = (session )->state_list.le_next; ((session)->state_list.le_prev) = ((void *)-1); ((session)->state_list.le_next) = ((void *) -1); } while (0); |
| 461 | LIST_REMOVE(session, session_list)do { if ((session)->session_list.le_next != ((void *)0)) ( session)->session_list.le_next->session_list.le_prev = ( session)->session_list.le_prev; *(session)->session_list .le_prev = (session)->session_list.le_next; ((session)-> session_list.le_prev) = ((void *)-1); ((session)->session_list .le_next) = ((void *)-1); } while (0); |
| 462 | session->state = PIPEX_STATE_CLOSED0x0004; |
| 463 | |
| 464 | /* if final session is destroyed, stop timer */ |
| 465 | if (LIST_EMPTY(&pipex_session_list)(((&pipex_session_list)->lh_first) == ((void *)0))) |
| 466 | pipex_timer_stop(); |
| 467 | } |
| 468 | |
| 469 | int |
| 470 | pipex_notify_close_session(struct pipex_session *session) |
| 471 | { |
| 472 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 473 | session->state = PIPEX_STATE_CLOSE_WAIT0x0002; |
| 474 | session->idle_time = 0; |
| 475 | LIST_INSERT_HEAD(&pipex_close_wait_list, session, state_list)do { if (((session)->state_list.le_next = (&pipex_close_wait_list )->lh_first) != ((void *)0)) (&pipex_close_wait_list)-> lh_first->state_list.le_prev = &(session)->state_list .le_next; (&pipex_close_wait_list)->lh_first = (session ); (session)->state_list.le_prev = &(&pipex_close_wait_list )->lh_first; } while (0); |
| 476 | |
| 477 | return (0); |
| 478 | } |
| 479 | |
| 480 | void |
| 481 | pipex_export_session_stats(struct pipex_session *session, |
| 482 | struct pipex_statistics *stats) |
| 483 | { |
| 484 | uint64_t counters[pxc_ncounters]; |
| 485 | |
| 486 | memset(stats, 0, sizeof(*stats))__builtin_memset((stats), (0), (sizeof(*stats))); |
| 487 | |
| 488 | counters_read(session->stat_counters, counters, pxc_ncounters); |
| 489 | stats->ipackets = counters[pxc_ipackets]; |
| 490 | stats->ierrors = counters[pxc_ierrors]; |
| 491 | stats->ibytes = counters[pxc_ibytes]; |
| 492 | stats->opackets = counters[pxc_opackets]; |
| 493 | stats->oerrors = counters[pxc_oerrors]; |
| 494 | stats->obytes = counters[pxc_obytes]; |
| 495 | stats->idle_time = session->idle_time; |
| 496 | } |
| 497 | |
| 498 | Static int |
| 499 | pipex_config_session(struct pipex_session_config_req *req, void *ownersc) |
| 500 | { |
| 501 | struct pipex_session *session; |
| 502 | |
| 503 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 504 | session = pipex_lookup_by_session_id(req->pcr_protocolpsr_protocol, |
| 505 | req->pcr_session_idpsr_session_id); |
| 506 | if (session == NULL((void *)0)) |
| 507 | return (EINVAL22); |
| 508 | if (session->ownersc != ownersc) |
| 509 | return (EINVAL22); |
| 510 | session->ip_forward = req->pcr_ip_forward; |
| 511 | |
| 512 | return (0); |
| 513 | } |
| 514 | |
| 515 | Static int |
| 516 | pipex_get_stat(struct pipex_session_stat_req *req, void *ownersc) |
| 517 | { |
| 518 | struct pipex_session *session; |
| 519 | |
| 520 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 521 | session = pipex_lookup_by_session_id(req->psr_protocol, |
| 522 | req->psr_session_id); |
| 523 | if (session == NULL((void *)0)) |
| 524 | return (EINVAL22); |
| 525 | if (session->ownersc != ownersc) |
| 526 | return (EINVAL22); |
| 527 | pipex_export_session_stats(session, &req->psr_stat); |
| 528 | |
| 529 | return (0); |
| 530 | } |
| 531 | |
| 532 | Static int |
| 533 | pipex_get_closed(struct pipex_session_list_req *req, void *ownersc) |
| 534 | { |
| 535 | struct pipex_session *session, *session_tmp; |
| 536 | |
| 537 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 538 | bzero(req, sizeof(*req))__builtin_bzero((req), (sizeof(*req))); |
| 539 | LIST_FOREACH_SAFE(session, &pipex_close_wait_list, state_list,for ((session) = ((&pipex_close_wait_list)->lh_first); (session) && ((session_tmp) = ((session)->state_list .le_next), 1); (session) = (session_tmp)) |
| 540 | session_tmp)for ((session) = ((&pipex_close_wait_list)->lh_first); (session) && ((session_tmp) = ((session)->state_list .le_next), 1); (session) = (session_tmp)) { |
| 541 | if (session->ownersc != ownersc) |
| 542 | continue; |
| 543 | req->plr_ppp_id[req->plr_ppp_id_count++] = session->ppp_id; |
| 544 | LIST_REMOVE(session, state_list)do { if ((session)->state_list.le_next != ((void *)0)) (session )->state_list.le_next->state_list.le_prev = (session)-> state_list.le_prev; *(session)->state_list.le_prev = (session )->state_list.le_next; ((session)->state_list.le_prev) = ((void *)-1); ((session)->state_list.le_next) = ((void *) -1); } while (0); |
| 545 | session->state = PIPEX_STATE_CLOSE_WAIT20x0003; |
| 546 | if (req->plr_ppp_id_count >= PIPEX_MAX_LISTREQ128) { |
| 547 | if (!LIST_EMPTY(&pipex_close_wait_list)(((&pipex_close_wait_list)->lh_first) == ((void *)0))) |
| 548 | req->plr_flags |= PIPEX_LISTREQ_MORE0x01; |
| 549 | break; |
| 550 | } |
| 551 | } |
| 552 | |
| 553 | return (0); |
| 554 | } |
| 555 | |
| 556 | Static struct pipex_session * |
| 557 | pipex_lookup_by_ip_address(struct in_addr addr) |
| 558 | { |
| 559 | struct pipex_session *session; |
| 560 | struct sockaddr_in pipex_in4, pipex_in4mask; |
| 561 | |
| 562 | if (pipex_rd_head4 == NULL((void *)0)) |
| 563 | return (NULL((void *)0)); |
| 564 | bzero(&pipex_in4, sizeof(pipex_in4))__builtin_bzero((&pipex_in4), (sizeof(pipex_in4))); |
| 565 | pipex_in4.sin_addr = addr; |
| 566 | pipex_in4.sin_family = AF_INET2; |
| 567 | pipex_in4.sin_len = sizeof(pipex_in4); |
| 568 | |
| 569 | bzero(&pipex_in4mask, sizeof(pipex_in4mask))__builtin_bzero((&pipex_in4mask), (sizeof(pipex_in4mask)) ); |
| 570 | pipex_in4mask.sin_addr.s_addr = htonl(0xFFFFFFFFL)(__uint32_t)(__builtin_constant_p(0xFFFFFFFFL) ? (__uint32_t) (((__uint32_t)(0xFFFFFFFFL) & 0xff) << 24 | ((__uint32_t )(0xFFFFFFFFL) & 0xff00) << 8 | ((__uint32_t)(0xFFFFFFFFL ) & 0xff0000) >> 8 | ((__uint32_t)(0xFFFFFFFFL) & 0xff000000) >> 24) : __swap32md(0xFFFFFFFFL)); |
| 571 | pipex_in4mask.sin_family = AF_INET2; |
| 572 | pipex_in4mask.sin_len = sizeof(pipex_in4mask); |
| 573 | |
| 574 | session = (struct pipex_session *)rn_lookup(&pipex_in4, &pipex_in4mask, |
| 575 | pipex_rd_head4); |
| 576 | |
| 577 | #ifdef PIPEX_DEBUG |
| 578 | if (session == NULL((void *)0)) { |
| 579 | char buf[INET_ADDRSTRLEN16]; |
| 580 | |
| 581 | PIPEX_DBG((NULL, LOG_DEBUG, "<%s> session not found (addr=%s)", |
| 582 | __func__, inet_ntop(AF_INET, &addr, buf, sizeof(buf)))); |
| 583 | } |
| 584 | #endif |
| 585 | |
| 586 | return (session); |
| 587 | } |
| 588 | |
| 589 | Static struct pipex_session * |
| 590 | pipex_lookup_by_session_id(int protocol, int session_id) |
| 591 | { |
| 592 | struct pipex_hash_head *list; |
| 593 | struct pipex_session *session; |
| 594 | |
| 595 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 596 | list = PIPEX_ID_HASHTABLE(session_id)(&pipex_id_hashtable[(session_id) & ((512/8)-1)]); |
| 597 | LIST_FOREACH(session, list, id_chain)for((session) = ((list)->lh_first); (session)!= ((void *)0 ); (session) = ((session)->id_chain.le_next)) { |
| 598 | if (session->protocol == protocol && |
| 599 | session->session_id == session_id) |
| 600 | break; |
| 601 | } |
| 602 | |
| 603 | #ifdef PIPEX_DEBUG |
| 604 | if (session == NULL((void *)0)) |
| 605 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 606 | "<%s> session not found (session_id=%d)", __func__, |
| 607 | session_id)); |
| 608 | #endif |
| 609 | |
| 610 | return (session); |
| 611 | } |
| 612 | |
| 613 | /*********************************************************************** |
| 614 | * Timer functions |
| 615 | ***********************************************************************/ |
| 616 | Static void |
| 617 | pipex_timer_start(void) |
| 618 | { |
| 619 | timeout_set_proc(&pipex_timer_ch, pipex_timer, NULL((void *)0)); |
| 620 | timeout_add_sec(&pipex_timer_ch, pipex_prune); |
| 621 | } |
| 622 | |
| 623 | Static void |
| 624 | pipex_timer_stop(void) |
| 625 | { |
| 626 | timeout_del(&pipex_timer_ch); |
| 627 | } |
| 628 | |
| 629 | Static void |
| 630 | pipex_timer(void *ignored_arg) |
| 631 | { |
| 632 | struct pipex_session *session, *session_tmp; |
| 633 | |
| 634 | timeout_add_sec(&pipex_timer_ch, pipex_prune); |
| 635 | |
| 636 | NET_LOCK()do { rw_enter_write(&netlock); } while (0); |
| 637 | /* walk through */ |
| 638 | LIST_FOREACH_SAFE(session, &pipex_session_list, session_list,for ((session) = ((&pipex_session_list)->lh_first); (session ) && ((session_tmp) = ((session)->session_list.le_next ), 1); (session) = (session_tmp)) |
| 639 | session_tmp)for ((session) = ((&pipex_session_list)->lh_first); (session ) && ((session_tmp) = ((session)->session_list.le_next ), 1); (session) = (session_tmp)) { |
| 640 | switch (session->state) { |
| 641 | case PIPEX_STATE_OPENED0x0001: |
| 642 | if (session->timeout_sec == 0) |
| 643 | continue; |
| 644 | |
| 645 | session->idle_time++; |
| 646 | if (session->idle_time < session->timeout_sec) |
| 647 | continue; |
| 648 | |
| 649 | pipex_notify_close_session(session); |
| 650 | break; |
| 651 | |
| 652 | case PIPEX_STATE_CLOSE_WAIT0x0002: |
| 653 | case PIPEX_STATE_CLOSE_WAIT20x0003: |
| 654 | /* Waiting PIPEXDSESSION from userland */ |
| 655 | session->idle_time++; |
| 656 | if (session->idle_time < PIPEX_CLOSE_TIMEOUT30) |
| 657 | continue; |
| 658 | /* Release the sessions when timeout */ |
| 659 | pipex_unlink_session(session); |
| 660 | KASSERTMSG(session->is_pppx == 0,((session->is_pppx == 0) ? (void)0 : panic("kernel %sassertion \"%s\" failed: file \"%s\", line %d" " " "FIXME session must not be released when pppx", "diagnostic " , "session->is_pppx == 0", "/usr/src/sys/net/pipex.c", 661 )) |
| 661 | "FIXME session must not be released when pppx")((session->is_pppx == 0) ? (void)0 : panic("kernel %sassertion \"%s\" failed: file \"%s\", line %d" " " "FIXME session must not be released when pppx", "diagnostic " , "session->is_pppx == 0", "/usr/src/sys/net/pipex.c", 661 )); |
| 662 | pipex_rele_session(session); |
| 663 | break; |
| 664 | |
| 665 | default: |
| 666 | break; |
| 667 | } |
| 668 | } |
| 669 | |
| 670 | NET_UNLOCK()do { rw_exit_write(&netlock); } while (0); |
| 671 | } |
| 672 | |
| 673 | /*********************************************************************** |
| 674 | * Common network I/O functions. (tunnel protocol independent) |
| 675 | ***********************************************************************/ |
| 676 | Static void |
| 677 | pipex_ip_output(struct mbuf *m0, struct pipex_session *session) |
| 678 | { |
| 679 | int is_idle; |
| 680 | |
| 681 | if (session->is_multicast == 0) { |
| 682 | /* |
| 683 | * Multicast packet is a idle packet and it's not TCP. |
| 684 | */ |
| 685 | if (session->ip_forward == 0 && session->ip6_forward == 0) |
| 686 | goto drop; |
| 687 | /* reset idle timer */ |
| 688 | if (session->timeout_sec != 0) { |
| 689 | is_idle = 0; |
| 690 | m0 = ip_is_idle_packet(m0, &is_idle); |
| 691 | if (m0 == NULL((void *)0)) |
| 692 | goto dropped; |
| 693 | if (is_idle == 0) |
| 694 | /* update expire time */ |
| 695 | session->idle_time = 0; |
| 696 | } |
| 697 | |
| 698 | /* adjust tcpmss */ |
| 699 | if ((session->ppp_flags & PIPEX_PPP_ADJUST_TCPMSS0x0100) != 0) { |
| 700 | m0 = adjust_tcp_mss(m0, session->peer_mru); |
| 701 | if (m0 == NULL((void *)0)) |
| 702 | goto dropped; |
| 703 | } |
| 704 | |
| 705 | pipex_ppp_output(m0, session, PPP_IP0x21); |
| 706 | } else { |
| 707 | struct pipex_session *session_tmp; |
| 708 | struct mbuf *m; |
| 709 | |
| 710 | m0->m_flagsm_hdr.mh_flags &= ~(M_BCAST0x0100|M_MCAST0x0200); |
| 711 | |
| 712 | LIST_FOREACH(session_tmp, &pipex_session_list, session_list)for((session_tmp) = ((&pipex_session_list)->lh_first); (session_tmp)!= ((void *)0); (session_tmp) = ((session_tmp)-> session_list.le_next)) { |
| 713 | if (session_tmp->ownersc != session->ownersc) |
| 714 | continue; |
| 715 | if (session_tmp->ip_forward == 0 && |
| 716 | session_tmp->ip6_forward == 0) |
| 717 | continue; |
| 718 | m = m_copym(m0, 0, M_COPYALL1000000000, M_NOWAIT0x0002); |
| 719 | if (m == NULL((void *)0)) { |
| 720 | counters_inc(session->stat_counters, |
| 721 | pxc_oerrors); |
| 722 | continue; |
| 723 | } |
| 724 | pipex_ppp_output(m, session_tmp, PPP_IP0x21); |
| 725 | } |
| 726 | m_freem(m0); |
| 727 | } |
| 728 | |
| 729 | return; |
| 730 | drop: |
| 731 | m_freem(m0); |
| 732 | dropped: |
| 733 | counters_inc(session->stat_counters, pxc_oerrors); |
| 734 | } |
| 735 | |
| 736 | Static void |
| 737 | pipex_ppp_output(struct mbuf *m0, struct pipex_session *session, int proto) |
| 738 | { |
| 739 | u_char *cp, hdr[16]; |
| 740 | |
| 741 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 742 | |
| 743 | #ifdef PIPEX_MPPE1 |
| 744 | if (pipex_session_is_mppe_enabled(session)(((session)->ppp_flags & 0x0020)? 1 : 0)) { |
| 745 | if (proto == PPP_IP0x21) { |
| 746 | pipex_mppe_output(m0, session, PPP_IP0x21); |
| 747 | return; |
| 748 | } |
| 749 | } |
| 750 | #endif /* PIPEX_MPPE */ |
| 751 | cp = hdr; |
| 752 | if (session->protocol != PIPEX_PROTO_PPPOE3) { |
| 753 | /* PPPoE has not address and control field */ |
| 754 | PUTCHAR(PPP_ALLSTATIONS, cp)do { *(cp)++ = (u_char)(0xff); } while (0); |
| 755 | PUTCHAR(PPP_UI, cp)do { *(cp)++ = (u_char)(0x03); } while (0); |
| 756 | } |
| 757 | PUTSHORT(proto, cp)do { *(cp)++ = (u_char) ((proto) >> 8); *(cp)++ = (u_char ) (proto); } while (0); |
| 758 | |
| 759 | M_PREPEND(m0, cp - hdr, M_NOWAIT)(m0) = m_prepend((m0), (cp - hdr), (0x0002)); |
| 760 | if (m0 == NULL((void *)0)) |
| 761 | goto drop; |
| 762 | memcpy(mtod(m0, u_char *), hdr, cp - hdr)__builtin_memcpy((((u_char *)((m0)->m_hdr.mh_data))), (hdr ), (cp - hdr)); |
| 763 | |
| 764 | switch (session->protocol) { |
| 765 | #ifdef PIPEX_PPPOE1 |
| 766 | case PIPEX_PROTO_PPPOE3: |
| 767 | pipex_pppoe_output(m0, session); |
| 768 | break; |
| 769 | #endif |
| 770 | #ifdef PIPEX_PPTP1 |
| 771 | case PIPEX_PROTO_PPTP2: |
| 772 | pipex_pptp_output(m0, session, 1, 1); |
| 773 | break; |
| 774 | #endif |
| 775 | #ifdef PIPEX_L2TP1 |
| 776 | case PIPEX_PROTO_L2TP1: |
| 777 | pipex_l2tp_output(m0, session); |
| 778 | break; |
| 779 | #endif |
| 780 | default: |
| 781 | goto drop; |
| 782 | } |
| 783 | |
| 784 | return; |
| 785 | drop: |
| 786 | m_freem(m0); |
| 787 | counters_inc(session->stat_counters, pxc_oerrors); |
| 788 | } |
| 789 | |
| 790 | Static void |
| 791 | pipex_ppp_input(struct mbuf *m0, struct pipex_session *session, int decrypted) |
| 792 | { |
| 793 | int proto, hlen = 0; |
| 794 | struct mbuf *n; |
| 795 | |
| 796 | KASSERT(m0->m_pkthdr.len >= PIPEX_PPPMINLEN)((m0->M_dat.MH.MH_pkthdr.len >= 5) ? (void)0 : __assert ("diagnostic ", "/usr/src/sys/net/pipex.c", 796, "m0->m_pkthdr.len >= PIPEX_PPPMINLEN" )); |
| 797 | proto = pipex_ppp_proto(m0, session, 0, &hlen); |
| 798 | #ifdef PIPEX_MPPE1 |
| 799 | if (proto == PPP_COMP0xfd) { |
| 800 | if (decrypted) |
| 801 | goto drop; |
| 802 | |
| 803 | /* checked this on ppp_common_input() already. */ |
| 804 | KASSERT(pipex_session_is_mppe_accepted(session))(((((session)->ppp_flags & 0x0010)? 1 : 0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c", 804, "pipex_session_is_mppe_accepted(session)" )); |
| 805 | |
| 806 | m_adj(m0, hlen); |
| 807 | pipex_mppe_input(m0, session); |
| 808 | return; |
| 809 | } |
| 810 | if (proto == PPP_CCP0x80fd) { |
| 811 | if (decrypted) |
| 812 | goto drop; |
| 813 | |
| 814 | #if NBPFILTER1 > 0 |
| 815 | { |
| 816 | struct ifnet *ifp; |
| 817 | |
| 818 | if ((ifp = if_get(session->ifindex)) != NULL((void *)0)) { |
| 819 | if (ifp->if_bpf && ifp->if_typeif_data.ifi_type == IFT_PPP0x17) |
| 820 | bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_IN(1 << 0)); |
| 821 | } |
| 822 | if_put(ifp); |
| 823 | } |
| 824 | #endif |
| 825 | m_adj(m0, hlen); |
| 826 | pipex_ccp_input(m0, session); |
| 827 | return; |
| 828 | } |
| 829 | #endif |
| 830 | m_adj(m0, hlen); |
| 831 | if (!ALIGNED_POINTER(mtod(m0, caddr_t), uint32_t)1) { |
| 832 | n = m_dup_pkt(m0, 0, M_NOWAIT0x0002); |
| 833 | if (n == NULL((void *)0)) |
| 834 | goto drop; |
| 835 | m_freem(m0); |
| 836 | m0 = n; |
| 837 | } |
| 838 | |
| 839 | switch (proto) { |
| 840 | case PPP_IP0x21: |
| 841 | if (session->ip_forward == 0) |
| 842 | goto drop; |
| 843 | if (!decrypted && pipex_session_is_mppe_required(session)(((session)->ppp_flags & 0x0040)? 1 : 0)) |
| 844 | /* |
| 845 | * if ip packet received when mppe |
| 846 | * is required, discard it. |
| 847 | */ |
| 848 | goto drop; |
| 849 | pipex_ip_input(m0, session); |
| 850 | return; |
| 851 | #ifdef INET61 |
| 852 | case PPP_IPV60x57: |
| 853 | if (session->ip6_forward == 0) |
| 854 | goto drop; |
| 855 | if (!decrypted && pipex_session_is_mppe_required(session)(((session)->ppp_flags & 0x0040)? 1 : 0)) |
| 856 | /* |
| 857 | * if ip packet received when mppe |
| 858 | * is required, discard it. |
| 859 | */ |
| 860 | goto drop; |
| 861 | pipex_ip6_input(m0, session); |
| 862 | return; |
| 863 | #endif |
| 864 | default: |
| 865 | if (decrypted) |
| 866 | goto drop; |
| 867 | /* protocol must be checked on pipex_common_input() already */ |
| 868 | KASSERT(0)((0) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 868, "0")); |
| 869 | goto drop; |
| 870 | } |
| 871 | |
| 872 | return; |
| 873 | drop: |
| 874 | m_freem(m0); |
| 875 | counters_inc(session->stat_counters, pxc_ierrors); |
| 876 | } |
| 877 | |
| 878 | Static void |
| 879 | pipex_ip_input(struct mbuf *m0, struct pipex_session *session) |
| 880 | { |
| 881 | struct ifnet *ifp; |
| 882 | struct ip *ip; |
| 883 | int len; |
| 884 | int is_idle; |
| 885 | |
| 886 | /* change recvif */ |
| 887 | m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = session->ifindex; |
| 888 | |
| 889 | if (ISSET(session->ppp_flags, PIPEX_PPP_INGRESS_FILTER)((session->ppp_flags) & (0x0200))) { |
| 890 | PIPEX_PULLUP(m0, sizeof(struct ip))if ((m0)->m_hdr.mh_len < (sizeof(struct ip))) { if ((m0 )->M_dat.MH.MH_pkthdr.len < (sizeof(struct ip))) { ; m_freem (m0); (m0) = ((void *)0); } else { (m0) = m_pullup((m0), (sizeof (struct ip))); (((m0) != ((void *)0)) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 890, "(m0) != NULL")); } }; |
| 891 | if (m0 == NULL((void *)0)) |
| 892 | goto drop; |
| 893 | /* ingress filter */ |
| 894 | ip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
| 895 | if ((ip->ip_src.s_addr & session->ip_netmask.sin_addr.s_addr) != |
| 896 | session->ip_address.sin_addr.s_addr) { |
| 897 | char src[INET_ADDRSTRLEN16]; |
| 898 | |
| 899 | pipex_session_log(session, LOG_DEBUG7, |
| 900 | "ip packet discarded by ingress filter (src %s)", |
| 901 | inet_ntop(AF_INET2, &ip->ip_src, src, sizeof(src))); |
| 902 | goto drop; |
| 903 | } |
| 904 | } |
| 905 | |
| 906 | /* idle timer */ |
| 907 | if (session->timeout_sec != 0) { |
| 908 | is_idle = 0; |
| 909 | m0 = ip_is_idle_packet(m0, &is_idle); |
| 910 | if (m0 == NULL((void *)0)) |
| 911 | goto drop; |
| 912 | if (is_idle == 0) |
| 913 | /* update expire time */ |
| 914 | session->idle_time = 0; |
| 915 | } |
| 916 | |
| 917 | /* adjust tcpmss */ |
| 918 | if (session->ppp_flags & PIPEX_PPP_ADJUST_TCPMSS0x0100) { |
| 919 | m0 = adjust_tcp_mss(m0, session->peer_mru); |
| 920 | if (m0 == NULL((void *)0)) |
| 921 | goto drop; |
| 922 | } |
| 923 | |
| 924 | #if NPF1 > 0 |
| 925 | pf_pkt_addr_changed(m0); |
| 926 | #endif |
| 927 | |
| 928 | len = m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
| 929 | |
| 930 | if ((ifp = if_get(session->ifindex)) == NULL((void *)0)) |
| 931 | goto drop; |
| 932 | |
| 933 | #if NBPFILTER1 > 0 |
| 934 | if (ifp->if_bpf) |
| 935 | bpf_mtap_af(ifp->if_bpf, AF_INET2, m0, BPF_DIRECTION_IN(1 << 0)); |
| 936 | #endif |
| 937 | |
| 938 | counters_pkt(ifp->if_counters, ifc_ipackets, ifc_ibytes, len); |
| 939 | counters_pkt(session->stat_counters, pxc_ipackets, pxc_ibytes, len); |
| 940 | ipv4_input(ifp, m0); |
| 941 | |
| 942 | if_put(ifp); |
| 943 | |
| 944 | return; |
| 945 | drop: |
| 946 | m_freem(m0); |
| 947 | counters_inc(session->stat_counters, pxc_ierrors); |
| 948 | } |
| 949 | |
| 950 | #ifdef INET61 |
| 951 | Static void |
| 952 | pipex_ip6_input(struct mbuf *m0, struct pipex_session *session) |
| 953 | { |
| 954 | struct ifnet *ifp; |
| 955 | int len; |
| 956 | |
| 957 | /* change recvif */ |
| 958 | m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = session->ifindex; |
| 959 | |
| 960 | /* |
| 961 | * XXX: what is reasonable ingress filter ??? |
| 962 | * only one address is enough ?? |
| 963 | */ |
| 964 | |
| 965 | /* XXX: we must define idle packet for IPv6(ICMPv6). */ |
| 966 | |
| 967 | /* |
| 968 | * XXX: tcpmss adjustment for IPv6 is required??? |
| 969 | * We may use PMTUD in IPv6.... |
| 970 | */ |
| 971 | |
| 972 | #if NPF1 > 0 |
| 973 | pf_pkt_addr_changed(m0); |
| 974 | #endif |
| 975 | |
| 976 | len = m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
| 977 | |
| 978 | if ((ifp = if_get(session->ifindex)) == NULL((void *)0)) |
| 979 | goto drop; |
| 980 | |
| 981 | #if NBPFILTER1 > 0 |
| 982 | if (ifp->if_bpf) |
| 983 | bpf_mtap_af(ifp->if_bpf, AF_INET624, m0, BPF_DIRECTION_IN(1 << 0)); |
| 984 | #endif |
| 985 | |
| 986 | counters_pkt(ifp->if_counters, ifc_ipackets, ifc_ibytes, len); |
| 987 | counters_pkt(session->stat_counters, pxc_ipackets, pxc_ibytes, len); |
| 988 | ipv6_input(ifp, m0); |
| 989 | |
| 990 | if_put(ifp); |
| 991 | |
| 992 | return; |
| 993 | drop: |
| 994 | m_freem(m0); |
| 995 | counters_inc(session->stat_counters, pxc_ierrors); |
| 996 | } |
| 997 | #endif |
| 998 | |
| 999 | Static struct mbuf * |
| 1000 | pipex_common_input(struct pipex_session *session, struct mbuf *m0, int hlen, |
| 1001 | int plen) |
| 1002 | { |
| 1003 | int proto, ppphlen; |
| 1004 | u_char code; |
| 1005 | |
| 1006 | if ((m0->m_pkthdrM_dat.MH.MH_pkthdr.len < hlen + PIPEX_PPPMINLEN5) || |
| 1007 | (plen < PIPEX_PPPMINLEN5)) |
| 1008 | goto drop; |
| 1009 | |
| 1010 | proto = pipex_ppp_proto(m0, session, hlen, &ppphlen); |
| 1011 | switch (proto) { |
| 1012 | #ifdef PIPEX_MPPE1 |
| 1013 | case PPP_CCP0x80fd: |
| 1014 | code = 0; |
| 1015 | KASSERT(m0->m_pkthdr.len >= hlen + ppphlen + 1)((m0->M_dat.MH.MH_pkthdr.len >= hlen + ppphlen + 1) ? ( void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c", 1015 , "m0->m_pkthdr.len >= hlen + ppphlen + 1")); |
| 1016 | m_copydata(m0, hlen + ppphlen, 1, &code); |
| 1017 | if (code != CCP_RESETREQ14 && code != CCP_RESETACK15) |
| 1018 | goto not_ours; |
| 1019 | break; |
| 1020 | |
| 1021 | case PPP_COMP0xfd: |
| 1022 | if (pipex_session_is_mppe_accepted(session)(((session)->ppp_flags & 0x0010)? 1 : 0)) |
| 1023 | break; |
| 1024 | goto not_ours; |
| 1025 | #endif |
| 1026 | case PPP_IP0x21: |
| 1027 | #ifdef INET61 |
| 1028 | case PPP_IPV60x57: |
| 1029 | #endif |
| 1030 | break; |
| 1031 | default: |
| 1032 | goto not_ours; |
| 1033 | } |
| 1034 | |
| 1035 | /* ok, The packet is for PIPEX */ |
| 1036 | m_adj(m0, hlen);/* cut off the tunnel protocol header */ |
| 1037 | |
| 1038 | /* ensure the mbuf length equals the PPP frame length */ |
| 1039 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < plen) |
| 1040 | goto drop; |
| 1041 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len > plen) { |
| 1042 | if (m0->m_lenm_hdr.mh_len == m0->m_pkthdrM_dat.MH.MH_pkthdr.len) { |
| 1043 | m0->m_lenm_hdr.mh_len = plen; |
| 1044 | m0->m_pkthdrM_dat.MH.MH_pkthdr.len = plen; |
| 1045 | } else |
| 1046 | m_adj(m0, plen - m0->m_pkthdrM_dat.MH.MH_pkthdr.len); |
| 1047 | } |
| 1048 | |
| 1049 | pipex_ppp_input(m0, session, 0); |
| 1050 | |
| 1051 | return (NULL((void *)0)); |
| 1052 | |
| 1053 | drop: |
| 1054 | m_freem(m0); |
| 1055 | counters_inc(session->stat_counters, pxc_ierrors); |
| 1056 | return (NULL((void *)0)); |
| 1057 | |
| 1058 | not_ours: |
| 1059 | return (m0); /* Not to be handled by PIPEX */ |
| 1060 | } |
| 1061 | |
| 1062 | /* |
| 1063 | * pipex_ppp_proto |
| 1064 | */ |
| 1065 | Static int |
| 1066 | pipex_ppp_proto(struct mbuf *m0, struct pipex_session *session, int off, |
| 1067 | int *hlenp) |
| 1068 | { |
| 1069 | int proto; |
| 1070 | u_char *cp, pktbuf[4]; |
| 1071 | |
| 1072 | KASSERT(m0->m_pkthdr.len > sizeof(pktbuf))((m0->M_dat.MH.MH_pkthdr.len > sizeof(pktbuf)) ? (void) 0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c", 1072, "m0->m_pkthdr.len > sizeof(pktbuf)")); |
| 1073 | m_copydata(m0, off, sizeof(pktbuf), pktbuf); |
| 1074 | cp = pktbuf; |
| 1075 | |
| 1076 | if (pipex_session_has_acf(session)(((session)->ppp_flags & 0x0080)? 1 : 0)) { |
| 1077 | if (cp[0] == PPP_ALLSTATIONS0xff && cp[1] == PPP_UI0x03) |
| 1078 | cp += 2; |
| 1079 | #ifdef PIPEX_DEBUG |
| 1080 | else if (!pipex_session_is_acfc_accepted(session)(((session)->ppp_flags & 0x0001)? 1 : 0)) |
| 1081 | PIPEX_DBG((session, LOG_DEBUG, |
| 1082 | "no acf but acfc is not accepted by the peer.")); |
| 1083 | #endif |
| 1084 | } |
| 1085 | if ((*cp & 0x01) != 0) { |
| 1086 | if (!pipex_session_is_pfc_accepted(session)(((session)->ppp_flags & 0x0002)? 1 : 0)) { |
| 1087 | PIPEX_DBG((session, LOG_DEBUG, "Received a broken ppp " |
| 1088 | "frame. No protocol field. %02x-%02x", |
| 1089 | cp[0], cp[1])); |
| 1090 | return (-1); |
| 1091 | } |
| 1092 | GETCHAR(proto, cp)do { (proto) = *(cp)++; } while (0); |
| 1093 | } else |
| 1094 | GETSHORT(proto, cp)do { (proto) = *(cp)++ << 8; (proto) |= *(cp)++; } while (0); |
| 1095 | |
| 1096 | if (hlenp != NULL((void *)0)) |
| 1097 | *hlenp = cp - pktbuf; |
| 1098 | |
| 1099 | return (proto); |
| 1100 | } |
| 1101 | |
| 1102 | #ifdef PIPEX_PPPOE1 |
| 1103 | /*********************************************************************** |
| 1104 | * PPPoE |
| 1105 | ***********************************************************************/ |
| 1106 | Static u_char pipex_pppoe_padding[ETHERMIN(64 - ((6 * 2) + 2) - 4)]; |
| 1107 | /* |
| 1108 | * pipex_pppoe_lookup_session |
| 1109 | */ |
| 1110 | struct pipex_session * |
| 1111 | pipex_pppoe_lookup_session(struct mbuf *m0) |
| 1112 | { |
| 1113 | struct pipex_session *session; |
| 1114 | struct pipex_pppoe_header pppoe; |
| 1115 | |
| 1116 | /* short packet */ |
| 1117 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < (sizeof(struct ether_header) + sizeof(pppoe))) |
| 1118 | return (NULL((void *)0)); |
| 1119 | |
| 1120 | m_copydata(m0, sizeof(struct ether_header), |
| 1121 | sizeof(struct pipex_pppoe_header), &pppoe); |
| 1122 | pppoe.session_id = ntohs(pppoe.session_id)(__uint16_t)(__builtin_constant_p(pppoe.session_id) ? (__uint16_t )(((__uint16_t)(pppoe.session_id) & 0xffU) << 8 | ( (__uint16_t)(pppoe.session_id) & 0xff00U) >> 8) : __swap16md (pppoe.session_id)); |
| 1123 | session = pipex_lookup_by_session_id(PIPEX_PROTO_PPPOE3, |
| 1124 | pppoe.session_id); |
| 1125 | #ifdef PIPEX_DEBUG |
| 1126 | if (session == NULL((void *)0)) |
| 1127 | PIPEX_DBG((NULL, LOG_DEBUG, "<%s> session not found (id=%d)", |
| 1128 | __func__, pppoe.session_id)); |
| 1129 | #endif |
| 1130 | if (session && session->proto.pppoe.over_ifidx != m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx) |
| 1131 | session = NULL((void *)0); |
| 1132 | |
| 1133 | return (session); |
| 1134 | } |
| 1135 | |
| 1136 | struct mbuf * |
| 1137 | pipex_pppoe_input(struct mbuf *m0, struct pipex_session *session) |
| 1138 | { |
| 1139 | int hlen; |
| 1140 | struct pipex_pppoe_header pppoe; |
| 1141 | |
| 1142 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 1143 | /* already checked at pipex_pppoe_lookup_session */ |
| 1144 | KASSERT(m0->m_pkthdr.len >= (sizeof(struct ether_header) +((m0->M_dat.MH.MH_pkthdr.len >= (sizeof(struct ether_header ) + sizeof(pppoe))) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 1145, "m0->m_pkthdr.len >= (sizeof(struct ether_header) + sizeof(pppoe))" )) |
| 1145 | sizeof(pppoe)))((m0->M_dat.MH.MH_pkthdr.len >= (sizeof(struct ether_header ) + sizeof(pppoe))) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 1145, "m0->m_pkthdr.len >= (sizeof(struct ether_header) + sizeof(pppoe))" )); |
| 1146 | |
| 1147 | m_copydata(m0, sizeof(struct ether_header), |
| 1148 | sizeof(struct pipex_pppoe_header), &pppoe); |
| 1149 | |
| 1150 | hlen = sizeof(struct ether_header) + sizeof(struct pipex_pppoe_header); |
| 1151 | if ((m0 = pipex_common_input(session, m0, hlen, ntohs(pppoe.length)(__uint16_t)(__builtin_constant_p(pppoe.length) ? (__uint16_t )(((__uint16_t)(pppoe.length) & 0xffU) << 8 | ((__uint16_t )(pppoe.length) & 0xff00U) >> 8) : __swap16md(pppoe .length)))) |
| 1152 | == NULL((void *)0)) |
| 1153 | return (NULL((void *)0)); |
| 1154 | m_freem(m0); |
| 1155 | counters_inc(session->stat_counters, pxc_ierrors); |
| 1156 | return (NULL((void *)0)); |
| 1157 | } |
| 1158 | |
| 1159 | /* |
| 1160 | * pipex_ppope_output |
| 1161 | */ |
| 1162 | Static void |
| 1163 | pipex_pppoe_output(struct mbuf *m0, struct pipex_session *session) |
| 1164 | { |
| 1165 | struct pipex_pppoe_header *pppoe; |
| 1166 | struct ifnet *ifp; |
| 1167 | int len, padlen; |
| 1168 | |
| 1169 | /* save length for pppoe header */ |
| 1170 | len = m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
| 1171 | |
| 1172 | /* prepend protocol header */ |
| 1173 | M_PREPEND(m0, sizeof(struct pipex_pppoe_header), M_NOWAIT)(m0) = m_prepend((m0), (sizeof(struct pipex_pppoe_header)), ( 0x0002)); |
| 1174 | if (m0 == NULL((void *)0)) { |
| 1175 | PIPEX_DBG((NULL, LOG_ERR, |
| 1176 | "<%s> cannot prepend header.", __func__)); |
| 1177 | counters_inc(session->stat_counters, pxc_oerrors); |
| 1178 | return; |
| 1179 | } |
| 1180 | padlen = ETHERMIN(64 - ((6 * 2) + 2) - 4) - m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
| 1181 | if (padlen > 0) |
| 1182 | m_copyback(m0, m0->m_pkthdrM_dat.MH.MH_pkthdr.len, padlen, pipex_pppoe_padding, |
| 1183 | M_NOWAIT0x0002); |
| 1184 | |
| 1185 | /* setup pppoe header information */ |
| 1186 | pppoe = mtod(m0, struct pipex_pppoe_header *)((struct pipex_pppoe_header *)((m0)->m_hdr.mh_data)); |
| 1187 | pppoe->vertype = PIPEX_PPPOE_VERTYPE0x11; |
| 1188 | pppoe->code = PIPEX_PPPOE_CODE_SESSION0x00; |
| 1189 | pppoe->session_id = htons(session->session_id)(__uint16_t)(__builtin_constant_p(session->session_id) ? ( __uint16_t)(((__uint16_t)(session->session_id) & 0xffU ) << 8 | ((__uint16_t)(session->session_id) & 0xff00U ) >> 8) : __swap16md(session->session_id)); |
| 1190 | pppoe->length = htons(len)(__uint16_t)(__builtin_constant_p(len) ? (__uint16_t)(((__uint16_t )(len) & 0xffU) << 8 | ((__uint16_t)(len) & 0xff00U ) >> 8) : __swap16md(len)); |
| 1191 | |
| 1192 | m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = session->proto.pppoe.over_ifidx; |
| 1193 | m0->m_flagsm_hdr.mh_flags &= ~(M_BCAST0x0100|M_MCAST0x0200); |
| 1194 | |
| 1195 | ifp = if_get(session->proto.pppoe.over_ifidx); |
| 1196 | if (ifp != NULL((void *)0)) { |
| 1197 | ifp->if_output(ifp, m0, &session->peer.sa, NULL((void *)0)); |
| 1198 | counters_pkt(session->stat_counters, pxc_opackets, |
| 1199 | pxc_obytes, len); |
| 1200 | } else { |
| 1201 | m_freem(m0); |
| 1202 | counters_inc(session->stat_counters, pxc_oerrors); |
| 1203 | } |
| 1204 | if_put(ifp); |
| 1205 | } |
| 1206 | #endif /* PIPEX_PPPOE */ |
| 1207 | |
| 1208 | #ifdef PIPEX_PPTP1 |
| 1209 | /*********************************************************************** |
| 1210 | * PPTP |
| 1211 | ***********************************************************************/ |
| 1212 | Static void |
| 1213 | pipex_pptp_output(struct mbuf *m0, struct pipex_session *session, |
| 1214 | int has_seq, int has_ack) |
| 1215 | { |
| 1216 | int len, reqlen; |
| 1217 | struct pipex_gre_header *gre = NULL((void *)0); |
| 1218 | struct ip *ip; |
| 1219 | u_char *cp; |
| 1220 | |
| 1221 | reqlen = PIPEX_IPGRE_HDRLEN(sizeof(struct ip) + sizeof(struct pipex_gre_header)) + (has_seq + has_ack) * 4; |
| 1222 | |
| 1223 | len = 0; |
| 1224 | if (m0 != NULL((void *)0)) { |
| 1225 | /* save length for gre header */ |
| 1226 | len = m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
| 1227 | /* prepend protocol header */ |
| 1228 | M_PREPEND(m0, reqlen, M_NOWAIT)(m0) = m_prepend((m0), (reqlen), (0x0002)); |
| 1229 | if (m0 == NULL((void *)0)) |
| 1230 | goto drop; |
| 1231 | } else { |
| 1232 | MGETHDR(m0, M_DONTWAIT, MT_DATA)m0 = m_gethdr((0x0002), (1)); |
| 1233 | if (m0 && reqlen > MHLEN((256 - sizeof(struct m_hdr)) - sizeof(struct pkthdr))) { |
| 1234 | MCLGET(m0, M_DONTWAIT)(void) m_clget((m0), (0x0002), (1 << 11)); |
| 1235 | if ((m0->m_flagsm_hdr.mh_flags & M_EXT0x0001) == 0) { |
| 1236 | m_freem(m0); |
| 1237 | m0 = NULL((void *)0); |
| 1238 | } |
| 1239 | } |
| 1240 | if (m0 == NULL((void *)0)) |
| 1241 | goto drop; |
| 1242 | m0->m_pkthdrM_dat.MH.MH_pkthdr.len = m0->m_lenm_hdr.mh_len = reqlen; |
| 1243 | } |
| 1244 | |
| 1245 | /* setup ip header information */ |
| 1246 | ip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
| 1247 | |
| 1248 | ip->ip_len = htons(m0->m_pkthdr.len)(__uint16_t)(__builtin_constant_p(m0->M_dat.MH.MH_pkthdr.len ) ? (__uint16_t)(((__uint16_t)(m0->M_dat.MH.MH_pkthdr.len) & 0xffU) << 8 | ((__uint16_t)(m0->M_dat.MH.MH_pkthdr .len) & 0xff00U) >> 8) : __swap16md(m0->M_dat.MH .MH_pkthdr.len)); |
| 1249 | ip->ip_off = 0; |
| 1250 | ip->ip_ttl = MAXTTL255; |
| 1251 | ip->ip_p = IPPROTO_GRE47; |
| 1252 | ip->ip_tos = 0; |
| 1253 | |
| 1254 | ip->ip_src = session->local.sin4.sin_addr; |
| 1255 | ip->ip_dst = session->peer.sin4.sin_addr; |
| 1256 | #if NPF1 > 0 |
| 1257 | pf_pkt_addr_changed(m0); |
| 1258 | #endif |
| 1259 | |
| 1260 | /* setup gre(ver1) header information */ |
| 1261 | gre = PIPEX_SEEK_NEXTHDR(ip, sizeof(struct ip),((struct pipex_gre_header *) (((char *)ip) + sizeof(struct ip ))) |
| 1262 | struct pipex_gre_header *)((struct pipex_gre_header *) (((char *)ip) + sizeof(struct ip ))); |
| 1263 | gre->type = htons(PIPEX_GRE_PROTO_PPP)(__uint16_t)(__builtin_constant_p(0x880b) ? (__uint16_t)(((__uint16_t )(0x880b) & 0xffU) << 8 | ((__uint16_t)(0x880b) & 0xff00U) >> 8) : __swap16md(0x880b)); |
| 1264 | gre->call_id = htons(session->peer_session_id)(__uint16_t)(__builtin_constant_p(session->peer_session_id ) ? (__uint16_t)(((__uint16_t)(session->peer_session_id) & 0xffU) << 8 | ((__uint16_t)(session->peer_session_id ) & 0xff00U) >> 8) : __swap16md(session->peer_session_id )); |
| 1265 | gre->flags = PIPEX_GRE_KFLAG0x2000 | PIPEX_GRE_VER0x0001; /* do htons later */ |
| 1266 | gre->len = htons(len)(__uint16_t)(__builtin_constant_p(len) ? (__uint16_t)(((__uint16_t )(len) & 0xffU) << 8 | ((__uint16_t)(len) & 0xff00U ) >> 8) : __swap16md(len)); |
| 1267 | |
| 1268 | cp = PIPEX_SEEK_NEXTHDR(gre, sizeof(struct pipex_gre_header),u_char *)((u_char *) (((char *)gre) + sizeof(struct pipex_gre_header)) ); |
| 1269 | if (has_seq) { |
| 1270 | gre->flags |= PIPEX_GRE_SFLAG0x1000; |
| 1271 | PUTLONG(session->proto.pptp.snd_nxt, cp)do { *(cp)++ = (u_char) ((session->proto.pptp.snd_nxt) >> 24); *(cp)++ = (u_char) ((session->proto.pptp.snd_nxt) >> 16); *(cp)++ = (u_char) ((session->proto.pptp.snd_nxt) >> 8); *(cp)++ = (u_char) (session->proto.pptp.snd_nxt); } while (0); |
| 1272 | session->proto.pptp.snd_nxt++; |
| 1273 | session->proto.pptp.snd_gap++; |
| 1274 | } |
| 1275 | if (has_ack) { |
| 1276 | gre->flags |= PIPEX_GRE_AFLAG0x0080; |
| 1277 | session->proto.pptp.rcv_acked = session->proto.pptp.rcv_nxt - 1; |
| 1278 | PUTLONG(session->proto.pptp.rcv_acked, cp)do { *(cp)++ = (u_char) ((session->proto.pptp.rcv_acked) >> 24); *(cp)++ = (u_char) ((session->proto.pptp.rcv_acked) >> 16); *(cp)++ = (u_char) ((session->proto.pptp.rcv_acked) >> 8); *(cp)++ = (u_char) (session->proto.pptp.rcv_acked); } while (0); |
| 1279 | } |
| 1280 | gre->flags = htons(gre->flags)(__uint16_t)(__builtin_constant_p(gre->flags) ? (__uint16_t )(((__uint16_t)(gre->flags) & 0xffU) << 8 | ((__uint16_t )(gre->flags) & 0xff00U) >> 8) : __swap16md(gre-> flags)); |
| 1281 | |
| 1282 | m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = session->ifindex; |
| 1283 | ip_send(m0); |
| 1284 | if (len > 0) { /* network layer only */ |
| 1285 | /* countup statistics */ |
| 1286 | counters_pkt(session->stat_counters, pxc_opackets, |
| 1287 | pxc_obytes, len); |
| 1288 | } |
| 1289 | |
| 1290 | return; |
| 1291 | drop: |
| 1292 | counters_inc(session->stat_counters, pxc_oerrors); |
| 1293 | } |
| 1294 | |
| 1295 | struct pipex_session * |
| 1296 | pipex_pptp_lookup_session(struct mbuf *m0) |
| 1297 | { |
| 1298 | struct pipex_session *session; |
| 1299 | struct pipex_gre_header gre; |
| 1300 | struct ip ip; |
| 1301 | uint16_t flags; |
| 1302 | uint16_t id; |
| 1303 | int hlen; |
| 1304 | |
| 1305 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < PIPEX_IPGRE_HDRLEN(sizeof(struct ip) + sizeof(struct pipex_gre_header))) { |
| 1306 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1307 | "<%s> packet length is too short", __func__)); |
| 1308 | goto not_ours; |
| 1309 | } |
| 1310 | |
| 1311 | /* get ip header info */ |
| 1312 | m_copydata(m0, 0, sizeof(struct ip), &ip); |
| 1313 | hlen = ip.ip_hl << 2; |
| 1314 | |
| 1315 | /* |
| 1316 | * m0 has already passed ip_input(), so there is |
| 1317 | * no necessity for ip packet inspection. |
| 1318 | */ |
| 1319 | |
| 1320 | /* get gre flags */ |
| 1321 | m_copydata(m0, hlen, sizeof(gre), &gre); |
| 1322 | flags = ntohs(gre.flags)(__uint16_t)(__builtin_constant_p(gre.flags) ? (__uint16_t)(( (__uint16_t)(gre.flags) & 0xffU) << 8 | ((__uint16_t )(gre.flags) & 0xff00U) >> 8) : __swap16md(gre.flags )); |
| 1323 | |
| 1324 | /* gre version must be '1' */ |
| 1325 | if ((flags & PIPEX_GRE_VERMASK0x0007) != PIPEX_GRE_VER0x0001) { |
| 1326 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1327 | "<%s> gre header wrong version.", __func__)); |
| 1328 | goto not_ours; |
| 1329 | } |
| 1330 | |
| 1331 | /* gre keys must be present */ |
| 1332 | if ((flags & PIPEX_GRE_KFLAG0x2000) == 0) { |
| 1333 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1334 | "<%s> gre header has no keys.", __func__)); |
| 1335 | goto not_ours; |
| 1336 | } |
| 1337 | |
| 1338 | /* flag check */ |
| 1339 | if ((flags & PIPEX_GRE_UNUSEDFLAGS0xcf78) != 0) { |
| 1340 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1341 | "<%s> gre header has unused flags at pptp.", __func__)); |
| 1342 | goto not_ours; |
| 1343 | } |
| 1344 | |
| 1345 | /* lookup pipex session table */ |
| 1346 | id = ntohs(gre.call_id)(__uint16_t)(__builtin_constant_p(gre.call_id) ? (__uint16_t) (((__uint16_t)(gre.call_id) & 0xffU) << 8 | ((__uint16_t )(gre.call_id) & 0xff00U) >> 8) : __swap16md(gre.call_id )); |
| 1347 | session = pipex_lookup_by_session_id(PIPEX_PROTO_PPTP2, id); |
| 1348 | #ifdef PIPEX_DEBUG |
| 1349 | if (session == NULL((void *)0)) { |
| 1350 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1351 | "<%s> session not found (id=%d)", __func__, id)); |
| 1352 | goto not_ours; |
| 1353 | } |
| 1354 | #endif |
| 1355 | |
| 1356 | return (session); |
| 1357 | |
| 1358 | not_ours: |
| 1359 | return (NULL((void *)0)); |
| 1360 | } |
| 1361 | |
| 1362 | struct mbuf * |
| 1363 | pipex_pptp_input(struct mbuf *m0, struct pipex_session *session) |
| 1364 | { |
| 1365 | int hlen, has_seq, has_ack, nseq; |
| 1366 | const char *reason = ""; |
| 1367 | u_char *cp, *seqp = NULL((void *)0), *ackp = NULL((void *)0); |
| 1368 | uint32_t flags, seq = 0, ack = 0; |
| 1369 | struct ip *ip; |
| 1370 | struct pipex_gre_header *gre; |
| 1371 | struct pipex_pptp_session *pptp_session; |
| 1372 | int rewind = 0; |
| 1373 | |
| 1374 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 1375 | KASSERT(m0->m_pkthdr.len >= PIPEX_IPGRE_HDRLEN)((m0->M_dat.MH.MH_pkthdr.len >= (sizeof(struct ip) + sizeof (struct pipex_gre_header))) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 1375, "m0->m_pkthdr.len >= PIPEX_IPGRE_HDRLEN" )); |
| 1376 | pptp_session = &session->proto.pptp; |
| 1377 | |
| 1378 | /* get ip header */ |
| 1379 | ip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
| 1380 | hlen = ip->ip_hl << 2; |
| 1381 | |
| 1382 | /* seek gre header */ |
| 1383 | gre = PIPEX_SEEK_NEXTHDR(ip, hlen, struct pipex_gre_header *)((struct pipex_gre_header *) (((char *)ip) + hlen)); |
| 1384 | flags = ntohs(gre->flags)(__uint16_t)(__builtin_constant_p(gre->flags) ? (__uint16_t )(((__uint16_t)(gre->flags) & 0xffU) << 8 | ((__uint16_t )(gre->flags) & 0xff00U) >> 8) : __swap16md(gre-> flags)); |
| 1385 | |
| 1386 | /* pullup for seek sequences in header */ |
| 1387 | has_seq = (flags & PIPEX_GRE_SFLAG0x1000) ? 1 : 0; |
| 1388 | has_ack = (flags & PIPEX_GRE_AFLAG0x0080) ? 1 : 0; |
| 1389 | hlen = PIPEX_IPGRE_HDRLEN(sizeof(struct ip) + sizeof(struct pipex_gre_header)) + 4 * (has_seq + has_ack); |
| 1390 | if (m0->m_lenm_hdr.mh_len < hlen) { |
| 1391 | m0 = m_pullup(m0, hlen); |
| 1392 | if (m0 == NULL((void *)0)) { |
| 1393 | PIPEX_DBG((session, LOG_DEBUG, "pullup failed.")); |
| 1394 | goto drop; |
| 1395 | } |
| 1396 | } |
| 1397 | |
| 1398 | /* check sequence */ |
| 1399 | cp = PIPEX_SEEK_NEXTHDR(gre, sizeof(struct pipex_gre_header),u_char *)((u_char *) (((char *)gre) + sizeof(struct pipex_gre_header)) ); |
| 1400 | if (has_seq) { |
| 1401 | seqp = cp; |
| 1402 | GETLONG(seq, cp)do { (seq) = *(cp)++ << 8; (seq) |= *(cp)++; (seq) <<= 8; (seq) |= *(cp)++; (seq) <<= 8; (seq) |= *(cp)++; } while (0); |
| 1403 | } |
| 1404 | if (has_ack) { |
| 1405 | ackp = cp; |
| 1406 | GETLONG(ack, cp)do { (ack) = *(cp)++ << 8; (ack) |= *(cp)++; (ack) <<= 8; (ack) |= *(cp)++; (ack) <<= 8; (ack) |= *(cp)++; } while (0); |
| 1407 | if (ack + 1 == pptp_session->snd_una) { |
| 1408 | /* ack has not changed before */ |
| 1409 | } else if (SEQ32_LT(ack, pptp_session->snd_una)((int32_t)((ack) - (pptp_session->snd_una)) < 0)) { |
| 1410 | /* OoO ack packets should not be dropped. */ |
| 1411 | rewind = 1; |
| 1412 | } else if (SEQ32_GT(ack, pptp_session->snd_nxt)((int32_t)((ack) - (pptp_session->snd_nxt)) > 0)) { |
| 1413 | reason = "ack for unknown sequence"; |
| 1414 | goto out_seq; |
| 1415 | } else |
| 1416 | pptp_session->snd_una = ack + 1; |
| 1417 | } |
| 1418 | if (!has_seq) { |
| 1419 | /* ack only packet */ |
| 1420 | goto not_ours; |
| 1421 | } |
| 1422 | if (SEQ32_LT(seq, pptp_session->rcv_nxt)((int32_t)((seq) - (pptp_session->rcv_nxt)) < 0)) { |
| 1423 | rewind = 1; |
| 1424 | if (SEQ32_LT(seq,((int32_t)((seq) - (pptp_session->rcv_nxt - 64)) < 0) |
| 1425 | pptp_session->rcv_nxt - PIPEX_REWIND_LIMIT)((int32_t)((seq) - (pptp_session->rcv_nxt - 64)) < 0)) { |
| 1426 | reason = "out of sequence"; |
| 1427 | goto out_seq; |
| 1428 | } |
| 1429 | } else if (SEQ32_GE(seq, pptp_session->rcv_nxt +((int32_t)((seq) - (pptp_session->rcv_nxt + pptp_session-> maxwinsz)) >= 0) |
| 1430 | pptp_session->maxwinsz)((int32_t)((seq) - (pptp_session->rcv_nxt + pptp_session-> maxwinsz)) >= 0)) { |
| 1431 | pipex_session_log(session, LOG_DEBUG7, |
| 1432 | "received packet caused window overflow. seq=%u(%u-%u)" |
| 1433 | "may lost %d packets.", seq, pptp_session->rcv_nxt, |
| 1434 | pptp_session->rcv_nxt + pptp_session->maxwinsz, |
| 1435 | (int)SEQ32_SUB(seq, pptp_session->rcv_nxt)((int32_t)((seq) - (pptp_session->rcv_nxt)))); |
| 1436 | } |
| 1437 | |
| 1438 | seq++; |
| 1439 | nseq = SEQ32_SUB(seq, pptp_session->rcv_nxt)((int32_t)((seq) - (pptp_session->rcv_nxt))); |
| 1440 | if (!rewind) { |
| 1441 | pptp_session->rcv_nxt = seq; |
| 1442 | if (SEQ32_SUB(seq, pptp_session->rcv_acked)((int32_t)((seq) - (pptp_session->rcv_acked))) > |
| 1443 | roundup(pptp_session->winsz, 2)((((pptp_session->winsz)+((2)-1))/(2))*(2)) / 2) /* Send ack only packet. */ |
| 1444 | pipex_pptp_output(NULL((void *)0), session, 0, 1); |
| 1445 | } |
| 1446 | |
| 1447 | if ((m0 = pipex_common_input(session, m0, hlen, ntohs(gre->len)(__uint16_t)(__builtin_constant_p(gre->len) ? (__uint16_t) (((__uint16_t)(gre->len) & 0xffU) << 8 | ((__uint16_t )(gre->len) & 0xff00U) >> 8) : __swap16md(gre-> len)))) |
| 1448 | == NULL((void *)0)) { |
| 1449 | /* ok, The packet is for PIPEX */ |
| 1450 | if (!rewind) |
| 1451 | session->proto.pptp.rcv_gap += nseq; |
| 1452 | return (NULL((void *)0)); |
| 1453 | } |
| 1454 | |
| 1455 | if (rewind) |
| 1456 | goto out_seq; |
| 1457 | |
| 1458 | not_ours: |
| 1459 | seq--; /* revert original seq value */ |
| 1460 | |
| 1461 | /* |
| 1462 | * overwrite sequence numbers to adjust a gap between pipex and |
| 1463 | * userland. |
| 1464 | */ |
| 1465 | if (seqp != NULL((void *)0)) { |
| 1466 | seq -= pptp_session->rcv_gap; |
| 1467 | PUTLONG(seq, seqp)do { *(seqp)++ = (u_char) ((seq) >> 24); *(seqp)++ = (u_char ) ((seq) >> 16); *(seqp)++ = (u_char) ((seq) >> 8 ); *(seqp)++ = (u_char) (seq); } while (0); |
| 1468 | } |
| 1469 | if (ackp != NULL((void *)0)) { |
| 1470 | if (pptp_session->snd_nxt == pptp_session->snd_una) { |
| 1471 | ack -= session->proto.pptp.snd_gap; |
| 1472 | pptp_session->ul_snd_una = ack; |
| 1473 | } else { |
| 1474 | /* |
| 1475 | * There are sending packets they are not acked. |
| 1476 | * In this situation, (ack - snd_gap) may points |
| 1477 | * before sending window of userland. So we don't |
| 1478 | * update the ack number. |
| 1479 | */ |
| 1480 | ack = pptp_session->ul_snd_una; |
| 1481 | } |
| 1482 | PUTLONG(ack, ackp)do { *(ackp)++ = (u_char) ((ack) >> 24); *(ackp)++ = (u_char ) ((ack) >> 16); *(ackp)++ = (u_char) ((ack) >> 8 ); *(ackp)++ = (u_char) (ack); } while (0); |
| 1483 | } |
| 1484 | |
| 1485 | return (m0); |
| 1486 | out_seq: |
| 1487 | pipex_session_log(session, LOG_DEBUG7, |
| 1488 | "Received bad data packet: %s: seq=%u(%u-%u) ack=%u(%u-%u)", |
| 1489 | reason, seq, pptp_session->rcv_nxt, |
| 1490 | pptp_session->rcv_nxt + pptp_session->maxwinsz, |
| 1491 | ack, pptp_session->snd_una, |
| 1492 | pptp_session->snd_nxt); |
| 1493 | |
| 1494 | /* FALLTHROUGH */ |
| 1495 | drop: |
| 1496 | m_freem(m0); |
| 1497 | counters_inc(session->stat_counters, pxc_ierrors); |
| 1498 | |
| 1499 | return (NULL((void *)0)); |
| 1500 | } |
| 1501 | |
| 1502 | struct pipex_session * |
| 1503 | pipex_pptp_userland_lookup_session_ipv4(struct mbuf *m0, struct in_addr dst) |
| 1504 | { |
| 1505 | struct sockaddr_in sin; |
| 1506 | |
| 1507 | memset(&sin, 0, sizeof(sin))__builtin_memset((&sin), (0), (sizeof(sin))); |
| 1508 | sin.sin_len = sizeof(sin); |
| 1509 | sin.sin_family = AF_INET2; |
| 1510 | sin.sin_addr = dst; |
| 1511 | |
| 1512 | return pipex_pptp_userland_lookup_session(m0, sintosa(&sin)); |
| 1513 | } |
| 1514 | |
| 1515 | #ifdef INET61 |
| 1516 | struct pipex_session * |
| 1517 | pipex_pptp_userland_lookup_session_ipv6(struct mbuf *m0, struct in6_addr dst) |
| 1518 | { |
| 1519 | struct sockaddr_in6 sin6; |
| 1520 | |
| 1521 | memset(&sin6, 0, sizeof(sin6))__builtin_memset((&sin6), (0), (sizeof(sin6))); |
| 1522 | sin6.sin6_len = sizeof(sin6); |
| 1523 | sin6.sin6_family = AF_INET624; |
| 1524 | in6_recoverscope(&sin6, &dst); |
| 1525 | |
| 1526 | return pipex_pptp_userland_lookup_session(m0, sin6tosa(&sin6)); |
| 1527 | } |
| 1528 | #endif |
| 1529 | |
| 1530 | Static struct pipex_session * |
| 1531 | pipex_pptp_userland_lookup_session(struct mbuf *m0, struct sockaddr *sa) |
| 1532 | { |
| 1533 | struct pipex_gre_header gre; |
| 1534 | struct pipex_hash_head *list; |
| 1535 | struct pipex_session *session; |
| 1536 | uint16_t id, flags; |
| 1537 | |
| 1538 | /* pullup */ |
| 1539 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < sizeof(gre)) { |
| 1540 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1541 | "<%s> packet length is too short", __func__)); |
| 1542 | return (NULL((void *)0)); |
| 1543 | } |
| 1544 | |
| 1545 | /* get flags */ |
| 1546 | m_copydata(m0, 0, sizeof(struct pipex_gre_header), &gre); |
| 1547 | flags = ntohs(gre.flags)(__uint16_t)(__builtin_constant_p(gre.flags) ? (__uint16_t)(( (__uint16_t)(gre.flags) & 0xffU) << 8 | ((__uint16_t )(gre.flags) & 0xff00U) >> 8) : __swap16md(gre.flags )); |
| 1548 | |
| 1549 | /* gre version must be '1' */ |
| 1550 | if ((flags & PIPEX_GRE_VERMASK0x0007) != PIPEX_GRE_VER0x0001) { |
| 1551 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1552 | "<%s> gre header wrong version.", __func__)); |
| 1553 | return (NULL((void *)0)); |
| 1554 | } |
| 1555 | |
| 1556 | /* gre keys must be present */ |
| 1557 | if ((flags & PIPEX_GRE_KFLAG0x2000) == 0) { |
| 1558 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1559 | "<%s> gre header has no keys.", __func__)); |
| 1560 | return (NULL((void *)0)); |
| 1561 | } |
| 1562 | |
| 1563 | /* lookup pipex session table */ |
| 1564 | id = ntohs(gre.call_id)(__uint16_t)(__builtin_constant_p(gre.call_id) ? (__uint16_t) (((__uint16_t)(gre.call_id) & 0xffU) << 8 | ((__uint16_t )(gre.call_id) & 0xff00U) >> 8) : __swap16md(gre.call_id )); |
| 1565 | |
| 1566 | list = PIPEX_PEER_ADDR_HASHTABLE(pipex_sockaddr_hash_key(sa))(&pipex_peer_addr_hashtable[(pipex_sockaddr_hash_key(sa)) & ((512/8)-1)]); |
| 1567 | LIST_FOREACH(session, list, peer_addr_chain)for((session) = ((list)->lh_first); (session)!= ((void *)0 ); (session) = ((session)->peer_addr_chain.le_next)) { |
| 1568 | if (pipex_sockaddr_compar_addr(&session->peer.sa, sa) != 0) |
| 1569 | continue; |
| 1570 | if (session->peer_session_id == id) |
| 1571 | break; |
| 1572 | } |
| 1573 | #ifdef PIPEX_DEBUG |
| 1574 | if (session == NULL((void *)0)) { |
| 1575 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1576 | "<%s> session not found (,call_id=%d)", |
| 1577 | __func__, (int)gre.call_id)); |
| 1578 | } |
| 1579 | #endif |
| 1580 | return (session); |
| 1581 | } |
| 1582 | |
| 1583 | /* |
| 1584 | * pipex_pptp_userland_output |
| 1585 | */ |
| 1586 | struct mbuf * |
| 1587 | pipex_pptp_userland_output(struct mbuf *m0, struct pipex_session *session) |
| 1588 | { |
| 1589 | int len; |
| 1590 | struct pipex_gre_header *gre, gre0; |
| 1591 | uint16_t flags; |
| 1592 | u_char *cp, *cp0; |
| 1593 | uint32_t val32; |
| 1594 | |
| 1595 | len = sizeof(struct pipex_gre_header); |
| 1596 | m_copydata(m0, 0, len, &gre0); |
| 1597 | gre = &gre0; |
| 1598 | flags = ntohs(gre->flags)(__uint16_t)(__builtin_constant_p(gre->flags) ? (__uint16_t )(((__uint16_t)(gre->flags) & 0xffU) << 8 | ((__uint16_t )(gre->flags) & 0xff00U) >> 8) : __swap16md(gre-> flags)); |
| 1599 | if ((flags & PIPEX_GRE_SFLAG0x1000) != 0) |
| 1600 | len += 4; |
| 1601 | if ((flags & PIPEX_GRE_AFLAG0x0080) != 0) |
| 1602 | len += 4; |
| 1603 | |
| 1604 | /* check length */ |
| 1605 | PIPEX_PULLUP(m0, len)if ((m0)->m_hdr.mh_len < (len)) { if ((m0)->M_dat.MH .MH_pkthdr.len < (len)) { ; m_freem(m0); (m0) = ((void *)0 ); } else { (m0) = m_pullup((m0), (len)); (((m0) != ((void *) 0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 1605, "(m0) != NULL")); } }; |
| 1606 | if (m0 == NULL((void *)0)) { |
| 1607 | PIPEX_DBG((session, LOG_DEBUG, "gre header is too short.")); |
| 1608 | return (NULL((void *)0)); |
| 1609 | } |
| 1610 | |
| 1611 | gre = mtod(m0, struct pipex_gre_header *)((struct pipex_gre_header *)((m0)->m_hdr.mh_data)); |
| 1612 | cp = PIPEX_SEEK_NEXTHDR(gre, sizeof(struct pipex_gre_header), u_char *)((u_char *) (((char *)gre) + sizeof(struct pipex_gre_header)) ); |
| 1613 | |
| 1614 | /* |
| 1615 | * overwrite sequence numbers to adjust a gap between pipex and |
| 1616 | * userland. |
| 1617 | */ |
| 1618 | if ((flags & PIPEX_GRE_SFLAG0x1000) != 0) { |
| 1619 | cp0 = cp; |
| 1620 | GETLONG(val32, cp)do { (val32) = *(cp)++ << 8; (val32) |= *(cp)++; (val32 ) <<= 8; (val32) |= *(cp)++; (val32) <<= 8; (val32 ) |= *(cp)++; } while (0); |
| 1621 | val32 += session->proto.pptp.snd_gap; |
| 1622 | PUTLONG(val32, cp0)do { *(cp0)++ = (u_char) ((val32) >> 24); *(cp0)++ = (u_char ) ((val32) >> 16); *(cp0)++ = (u_char) ((val32) >> 8); *(cp0)++ = (u_char) (val32); } while (0); |
| 1623 | session->proto.pptp.snd_nxt++; |
| 1624 | } |
| 1625 | if ((flags & PIPEX_GRE_AFLAG0x0080) != 0) { |
| 1626 | cp0 = cp; |
| 1627 | GETLONG(val32, cp)do { (val32) = *(cp)++ << 8; (val32) |= *(cp)++; (val32 ) <<= 8; (val32) |= *(cp)++; (val32) <<= 8; (val32 ) |= *(cp)++; } while (0); |
| 1628 | val32 += session->proto.pptp.rcv_gap; |
| 1629 | PUTLONG(val32, cp0)do { *(cp0)++ = (u_char) ((val32) >> 24); *(cp0)++ = (u_char ) ((val32) >> 16); *(cp0)++ = (u_char) ((val32) >> 8); *(cp0)++ = (u_char) (val32); } while (0); |
| 1630 | if (SEQ32_GT(val32, session->proto.pptp.rcv_acked)((int32_t)((val32) - (session->proto.pptp.rcv_acked)) > 0)) |
| 1631 | session->proto.pptp.rcv_acked = val32; |
| 1632 | } |
| 1633 | |
| 1634 | return (m0); |
| 1635 | } |
| 1636 | #endif /* PIPEX_PPTP */ |
| 1637 | |
| 1638 | #ifdef PIPEX_L2TP1 |
| 1639 | /*********************************************************************** |
| 1640 | * L2TP support |
| 1641 | ***********************************************************************/ |
| 1642 | Static void |
| 1643 | pipex_l2tp_output(struct mbuf *m0, struct pipex_session *session) |
| 1644 | { |
| 1645 | int hlen, plen, datalen; |
| 1646 | struct pipex_l2tp_header *l2tp = NULL((void *)0); |
| 1647 | struct pipex_l2tp_seq_header *seq = NULL((void *)0); |
| 1648 | struct udphdr *udp; |
| 1649 | struct ip *ip; |
| 1650 | #ifdef INET61 |
| 1651 | struct ip6_hdr *ip6; |
| 1652 | #endif |
| 1653 | struct m_tag *mtag; |
| 1654 | |
| 1655 | hlen = sizeof(struct pipex_l2tp_header) + |
| 1656 | ((pipex_session_is_l2tp_data_sequencing_on(session)(((session)->proto.l2tp.option_flags & 0x00000001) ? 1 : 0)) |
| 1657 | ? sizeof(struct pipex_l2tp_seq_header) : 0) + |
| 1658 | sizeof(struct udphdr) + |
| 1659 | #ifdef INET61 |
| 1660 | ((session->peer.sin6.sin6_family == AF_INET624) |
| 1661 | ? sizeof(struct ip6_hdr) : sizeof(struct ip)); |
| 1662 | #else |
| 1663 | sizeof(struct ip); |
| 1664 | #endif |
| 1665 | |
| 1666 | datalen = 0; |
| 1667 | if (m0 != NULL((void *)0)) { |
| 1668 | datalen = m0->m_pkthdrM_dat.MH.MH_pkthdr.len; |
| 1669 | M_PREPEND(m0, hlen, M_NOWAIT)(m0) = m_prepend((m0), (hlen), (0x0002)); |
| 1670 | if (m0 == NULL((void *)0)) |
| 1671 | goto drop; |
| 1672 | } else { |
| 1673 | MGETHDR(m0, M_DONTWAIT, MT_DATA)m0 = m_gethdr((0x0002), (1)); |
| 1674 | if (m0 == NULL((void *)0)) |
| 1675 | goto drop; |
| 1676 | KASSERT(hlen <= MHLEN)((hlen <= ((256 - sizeof(struct m_hdr)) - sizeof(struct pkthdr ))) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 1676, "hlen <= MHLEN")); |
| 1677 | m0->m_pkthdrM_dat.MH.MH_pkthdr.len = m0->m_lenm_hdr.mh_len = hlen; |
| 1678 | } |
| 1679 | |
| 1680 | #ifdef INET61 |
| 1681 | hlen = (session->peer.sin6.sin6_family == AF_INET624) |
| 1682 | ? sizeof(struct ip6_hdr) : sizeof(struct ip); |
| 1683 | #else |
| 1684 | hlen = sizeof(struct ip); |
| 1685 | #endif |
| 1686 | plen = datalen + sizeof(struct pipex_l2tp_header) + |
| 1687 | ((pipex_session_is_l2tp_data_sequencing_on(session)(((session)->proto.l2tp.option_flags & 0x00000001) ? 1 : 0)) |
| 1688 | ? sizeof(struct pipex_l2tp_seq_header) : 0); |
| 1689 | |
| 1690 | l2tp = (struct pipex_l2tp_header *) |
| 1691 | (mtod(m0, caddr_t)((caddr_t)((m0)->m_hdr.mh_data)) + hlen + sizeof(struct udphdr)); |
| 1692 | l2tp->flagsver = PIPEX_L2TP_VER2 | PIPEX_L2TP_FLAG_LENGTH0x4000; |
| 1693 | l2tp->length = htons(plen)(__uint16_t)(__builtin_constant_p(plen) ? (__uint16_t)(((__uint16_t )(plen) & 0xffU) << 8 | ((__uint16_t)(plen) & 0xff00U ) >> 8) : __swap16md(plen)); |
| 1694 | l2tp->tunnel_id = htons(session->proto.l2tp.peer_tunnel_id)(__uint16_t)(__builtin_constant_p(session->proto.l2tp.peer_tunnel_id ) ? (__uint16_t)(((__uint16_t)(session->proto.l2tp.peer_tunnel_id ) & 0xffU) << 8 | ((__uint16_t)(session->proto.l2tp .peer_tunnel_id) & 0xff00U) >> 8) : __swap16md(session ->proto.l2tp.peer_tunnel_id)); |
| 1695 | l2tp->session_id = htons(session->peer_session_id)(__uint16_t)(__builtin_constant_p(session->peer_session_id ) ? (__uint16_t)(((__uint16_t)(session->peer_session_id) & 0xffU) << 8 | ((__uint16_t)(session->peer_session_id ) & 0xff00U) >> 8) : __swap16md(session->peer_session_id )); |
| 1696 | if (pipex_session_is_l2tp_data_sequencing_on(session)(((session)->proto.l2tp.option_flags & 0x00000001) ? 1 : 0)) { |
| 1697 | seq = (struct pipex_l2tp_seq_header *)(l2tp + 1); |
| 1698 | l2tp->flagsver |= PIPEX_L2TP_FLAG_SEQUENCE0x0800; |
| 1699 | seq->ns = htons(session->proto.l2tp.ns_nxt)(__uint16_t)(__builtin_constant_p(session->proto.l2tp.ns_nxt ) ? (__uint16_t)(((__uint16_t)(session->proto.l2tp.ns_nxt) & 0xffU) << 8 | ((__uint16_t)(session->proto.l2tp .ns_nxt) & 0xff00U) >> 8) : __swap16md(session-> proto.l2tp.ns_nxt)); |
| 1700 | session->proto.l2tp.ns_nxt++; |
| 1701 | session->proto.l2tp.ns_gap++; |
| 1702 | session->proto.l2tp.nr_acked = session->proto.l2tp.nr_nxt - 1; |
| 1703 | seq->nr = htons(session->proto.l2tp.nr_acked)(__uint16_t)(__builtin_constant_p(session->proto.l2tp.nr_acked ) ? (__uint16_t)(((__uint16_t)(session->proto.l2tp.nr_acked ) & 0xffU) << 8 | ((__uint16_t)(session->proto.l2tp .nr_acked) & 0xff00U) >> 8) : __swap16md(session-> proto.l2tp.nr_acked)); |
| 1704 | } |
| 1705 | l2tp->flagsver = htons(l2tp->flagsver)(__uint16_t)(__builtin_constant_p(l2tp->flagsver) ? (__uint16_t )(((__uint16_t)(l2tp->flagsver) & 0xffU) << 8 | ( (__uint16_t)(l2tp->flagsver) & 0xff00U) >> 8) : __swap16md (l2tp->flagsver)); |
| 1706 | |
| 1707 | plen += sizeof(struct udphdr); |
| 1708 | udp = (struct udphdr *)(mtod(m0, caddr_t)((caddr_t)((m0)->m_hdr.mh_data)) + hlen); |
| 1709 | udp->uh_sport = session->local.sin6.sin6_port; |
| 1710 | udp->uh_dport = session->peer.sin6.sin6_port; |
| 1711 | udp->uh_ulen = htons(plen)(__uint16_t)(__builtin_constant_p(plen) ? (__uint16_t)(((__uint16_t )(plen) & 0xffU) << 8 | ((__uint16_t)(plen) & 0xff00U ) >> 8) : __swap16md(plen)); |
| 1712 | udp->uh_sum = 0; |
| 1713 | |
| 1714 | m0->m_pkthdrM_dat.MH.MH_pkthdr.csum_flags |= M_UDP_CSUM_OUT0x0004; |
| 1715 | m0->m_pkthdrM_dat.MH.MH_pkthdr.ph_ifidx = session->ifindex; |
| 1716 | #if NPF1 > 0 |
| 1717 | pf_pkt_addr_changed(m0); |
| 1718 | #endif |
| 1719 | switch (session->peer.sin6.sin6_family) { |
| 1720 | case AF_INET2: |
| 1721 | ip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
| 1722 | ip->ip_p = IPPROTO_UDP17; |
| 1723 | ip->ip_src = session->local.sin4.sin_addr; |
| 1724 | ip->ip_dst = session->peer.sin4.sin_addr; |
| 1725 | ip->ip_len = htons(hlen + plen)(__uint16_t)(__builtin_constant_p(hlen + plen) ? (__uint16_t) (((__uint16_t)(hlen + plen) & 0xffU) << 8 | ((__uint16_t )(hlen + plen) & 0xff00U) >> 8) : __swap16md(hlen + plen)); |
| 1726 | ip->ip_ttl = MAXTTL255; |
| 1727 | ip->ip_tos = 0; |
| 1728 | ip->ip_off = 0; |
| 1729 | |
| 1730 | if (session->proto.l2tp.ipsecflowinfo > 0) { |
| 1731 | if ((mtag = m_tag_get(PACKET_TAG_IPSEC_FLOWINFO0x0004, |
| 1732 | sizeof(u_int32_t), M_NOWAIT0x0002)) == NULL((void *)0)) |
| 1733 | goto drop; |
| 1734 | *(u_int32_t *)(mtag + 1) = |
| 1735 | session->proto.l2tp.ipsecflowinfo; |
| 1736 | m_tag_prepend(m0, mtag); |
| 1737 | } |
| 1738 | |
| 1739 | ip_send(m0); |
| 1740 | break; |
| 1741 | #ifdef INET61 |
| 1742 | case AF_INET624: |
| 1743 | ip6 = mtod(m0, struct ip6_hdr *)((struct ip6_hdr *)((m0)->m_hdr.mh_data)); |
| 1744 | |
| 1745 | ip6->ip6_flowip6_ctlun.ip6_un1.ip6_un1_flow = 0; |
| 1746 | ip6->ip6_vfcip6_ctlun.ip6_un2_vfc &= ~IPV6_VERSION_MASK0xf0; |
| 1747 | ip6->ip6_vfcip6_ctlun.ip6_un2_vfc |= IPV6_VERSION0x60; |
| 1748 | ip6->ip6_nxtip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_UDP17; |
| 1749 | ip6->ip6_src = session->local.sin6.sin6_addr; |
| 1750 | (void)in6_embedscope(&ip6->ip6_dst, |
| 1751 | &session->peer.sin6, NULL((void *)0)); |
| 1752 | /* ip6->ip6_plen will be filled in ip6_output. */ |
| 1753 | |
| 1754 | ip6_send(m0); |
| 1755 | break; |
| 1756 | #endif |
| 1757 | } |
| 1758 | udpstat_inc(udps_opackets); |
| 1759 | |
| 1760 | if (datalen > 0) { /* network layer only */ |
| 1761 | /* countup statistics */ |
| 1762 | counters_pkt(session->stat_counters, pxc_opackets, |
| 1763 | pxc_obytes, datalen); |
| 1764 | } |
| 1765 | |
| 1766 | return; |
| 1767 | drop: |
| 1768 | m_freem(m0); |
| 1769 | counters_inc(session->stat_counters, pxc_oerrors); |
| 1770 | } |
| 1771 | |
| 1772 | struct pipex_session * |
| 1773 | pipex_l2tp_lookup_session(struct mbuf *m0, int off) |
| 1774 | { |
| 1775 | struct pipex_session *session; |
| 1776 | uint16_t flags, session_id, ver; |
| 1777 | u_char *cp, buf[PIPEX_L2TP_MINLEN8]; |
| 1778 | |
| 1779 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < off + PIPEX_L2TP_MINLEN8) { |
| 1780 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1781 | "<%s> packet length is too short", __func__)); |
| 1782 | goto not_ours; |
| 1783 | } |
| 1784 | |
| 1785 | /* get first 16bits of L2TP */ |
| 1786 | m_copydata(m0, off, sizeof(buf), buf); |
| 1787 | cp = buf; |
| 1788 | GETSHORT(flags, cp)do { (flags) = *(cp)++ << 8; (flags) |= *(cp)++; } while (0); |
| 1789 | ver = flags & PIPEX_L2TP_VER_MASK0x000f; |
| 1790 | |
| 1791 | /* l2tp version must be '2' */ |
| 1792 | if (ver != PIPEX_L2TP_VER2) { |
| 1793 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1794 | "<%s> l2tp header wrong version %u.", __func__, ver)); |
| 1795 | goto not_ours; |
| 1796 | } |
| 1797 | if ((flags & PIPEX_L2TP_FLAG_TYPE0x8000) != 0) |
| 1798 | goto not_ours; |
| 1799 | |
| 1800 | if (flags & PIPEX_L2TP_FLAG_LENGTH0x4000) |
| 1801 | cp += 2; /* skip length field */ |
| 1802 | cp += 2; /* skip tunnel-id field */ |
| 1803 | GETSHORT(session_id, cp)do { (session_id) = *(cp)++ << 8; (session_id) |= *(cp) ++; } while (0); /* get session-id field */ |
| 1804 | |
| 1805 | /* lookup pipex session table */ |
| 1806 | session = pipex_lookup_by_session_id(PIPEX_PROTO_L2TP1, session_id); |
| 1807 | #ifdef PIPEX_DEBUG |
| 1808 | if (session == NULL((void *)0)) { |
| 1809 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1810 | "<%s> session not found (id=%d)", __func__, session_id)); |
| 1811 | goto not_ours; |
| 1812 | } |
| 1813 | #endif |
| 1814 | |
| 1815 | return (session); |
| 1816 | |
| 1817 | not_ours: |
| 1818 | return (NULL((void *)0)); |
| 1819 | } |
| 1820 | |
| 1821 | struct mbuf * |
| 1822 | pipex_l2tp_input(struct mbuf *m0, int off0, struct pipex_session *session, |
| 1823 | uint32_t ipsecflowinfo) |
| 1824 | { |
| 1825 | struct pipex_l2tp_session *l2tp_session; |
| 1826 | int length, offset, hlen, nseq; |
| 1827 | u_char *cp, *nsp, *nrp; |
| 1828 | uint16_t flags, ns = 0, nr = 0; |
| 1829 | int rewind = 0; |
| 1830 | |
| 1831 | NET_ASSERT_LOCKED()do { int _s = rw_status(&netlock); if ((splassert_ctl > 0) && (_s != 0x0001UL && _s != 0x0002UL)) splassert_fail (0x0002UL, _s, __func__); } while (0); |
| 1832 | length = offset = ns = nr = 0; |
Value stored to 'length' is never read | |
| 1833 | l2tp_session = &session->proto.l2tp; |
| 1834 | l2tp_session->ipsecflowinfo = ipsecflowinfo; |
| 1835 | nsp = nrp = NULL((void *)0); |
| 1836 | |
| 1837 | m_copydata(m0, off0, sizeof(flags), &flags); |
| 1838 | |
| 1839 | flags = ntohs(flags)(__uint16_t)(__builtin_constant_p(flags) ? (__uint16_t)(((__uint16_t )(flags) & 0xffU) << 8 | ((__uint16_t)(flags) & 0xff00U) >> 8) : __swap16md(flags)) & PIPEX_L2TP_FLAG_MASK0xfff0; |
| 1840 | KASSERT((flags & PIPEX_L2TP_FLAG_TYPE) == 0)(((flags & 0x8000) == 0) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 1840, "(flags & PIPEX_L2TP_FLAG_TYPE) == 0" )); |
| 1841 | |
| 1842 | hlen = 2; /* flags and version fields */ |
| 1843 | if (flags & PIPEX_L2TP_FLAG_LENGTH0x4000) /* length */ |
| 1844 | hlen += 2; |
| 1845 | hlen += 4; /* tunnel-id and session-id */ |
| 1846 | if (flags & PIPEX_L2TP_FLAG_SEQUENCE0x0800) /* ns and nr */ |
| 1847 | hlen += 4; |
| 1848 | if (flags & PIPEX_L2TP_FLAG_OFFSET0x0200) /* offset */ |
| 1849 | hlen += 2; |
| 1850 | |
| 1851 | PIPEX_PULLUP(m0, off0 + hlen)if ((m0)->m_hdr.mh_len < (off0 + hlen)) { if ((m0)-> M_dat.MH.MH_pkthdr.len < (off0 + hlen)) { ; m_freem(m0); ( m0) = ((void *)0); } else { (m0) = m_pullup((m0), (off0 + hlen )); (((m0) != ((void *)0)) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 1851, "(m0) != NULL")); } }; |
| 1852 | if (m0 == NULL((void *)0)) |
| 1853 | goto drop; |
| 1854 | |
| 1855 | cp = mtod(m0, u_char *)((u_char *)((m0)->m_hdr.mh_data)) + off0; |
| 1856 | cp += 2; /* flags and version */ |
| 1857 | if (flags & PIPEX_L2TP_FLAG_LENGTH0x4000) |
| 1858 | GETSHORT(length, cp)do { (length) = *(cp)++ << 8; (length) |= *(cp)++; } while (0); |
| 1859 | else |
| 1860 | length = m0->m_pkthdrM_dat.MH.MH_pkthdr.len - off0; |
| 1861 | cp += 4; /* skip tunnel-id and session-id field */ |
| 1862 | |
| 1863 | /* pullup for seek sequences in header */ |
| 1864 | nseq = 0; |
| 1865 | if (flags & PIPEX_L2TP_FLAG_SEQUENCE0x0800) { |
| 1866 | nsp = cp; |
| 1867 | GETSHORT(ns, cp)do { (ns) = *(cp)++ << 8; (ns) |= *(cp)++; } while (0); |
| 1868 | nrp = cp; |
| 1869 | GETSHORT(nr, cp)do { (nr) = *(cp)++ << 8; (nr) |= *(cp)++; } while (0); |
| 1870 | |
| 1871 | nr++; |
| 1872 | if (SEQ16_GT(nr, l2tp_session->ns_una)((int16_t)((nr) - (l2tp_session->ns_una)) > 0) && |
| 1873 | SEQ16_LE(nr, l2tp_session->ns_nxt)((int16_t)((nr) - (l2tp_session->ns_nxt)) <= 0)) |
| 1874 | /* update 'ns_una' only if the ns is in valid range */ |
| 1875 | l2tp_session->ns_una = nr; |
| 1876 | if (SEQ16_LT(ns, l2tp_session->nr_nxt)((int16_t)((ns) - (l2tp_session->nr_nxt)) < 0)) { |
| 1877 | rewind = 1; |
| 1878 | if (SEQ16_LT(ns,((int16_t)((ns) - (l2tp_session->nr_nxt - 64)) < 0) |
| 1879 | l2tp_session->nr_nxt - PIPEX_REWIND_LIMIT)((int16_t)((ns) - (l2tp_session->nr_nxt - 64)) < 0)) |
| 1880 | goto out_seq; |
| 1881 | } |
| 1882 | |
| 1883 | ns++; |
| 1884 | nseq = SEQ16_SUB(ns, l2tp_session->nr_nxt)((int16_t)((ns) - (l2tp_session->nr_nxt))); |
| 1885 | if (!rewind) |
| 1886 | l2tp_session->nr_nxt = ns; |
| 1887 | } |
| 1888 | if (flags & PIPEX_L2TP_FLAG_OFFSET0x0200) |
| 1889 | GETSHORT(offset, cp)do { (offset) = *(cp)++ << 8; (offset) |= *(cp)++; } while (0); |
| 1890 | |
| 1891 | length -= hlen + offset; |
| 1892 | hlen += off0 + offset; |
| 1893 | if ((m0 = pipex_common_input(session, m0, hlen, length)) == NULL((void *)0)) { |
| 1894 | /* ok, The packet is for PIPEX */ |
| 1895 | if (!rewind) |
| 1896 | session->proto.l2tp.nr_gap += nseq; |
| 1897 | return (NULL((void *)0)); |
| 1898 | } |
| 1899 | |
| 1900 | if (rewind) |
| 1901 | goto out_seq; |
| 1902 | |
| 1903 | /* |
| 1904 | * overwrite sequence numbers to adjust a gap between pipex and |
| 1905 | * userland. |
| 1906 | */ |
| 1907 | if (flags & PIPEX_L2TP_FLAG_SEQUENCE0x0800) { |
| 1908 | --ns; --nr; /* revert original values */ |
| 1909 | ns -= l2tp_session->nr_gap; |
| 1910 | PUTSHORT(ns, nsp)do { *(nsp)++ = (u_char) ((ns) >> 8); *(nsp)++ = (u_char ) (ns); } while (0); |
| 1911 | |
| 1912 | if (l2tp_session->ns_nxt == l2tp_session->ns_una) { |
| 1913 | nr -= l2tp_session->ns_gap; |
| 1914 | l2tp_session->ul_ns_una = nr; |
| 1915 | } else { |
| 1916 | /* |
| 1917 | * There are sending packets they are not acked. |
| 1918 | * In this situation, (ack - snd_gap) may points |
| 1919 | * before sending window of userland. So we don't |
| 1920 | * update the ack number. |
| 1921 | */ |
| 1922 | nr = l2tp_session->ul_ns_una; |
| 1923 | } |
| 1924 | PUTSHORT(nr, nrp)do { *(nrp)++ = (u_char) ((nr) >> 8); *(nrp)++ = (u_char ) (nr); } while (0); |
| 1925 | } |
| 1926 | |
| 1927 | return (m0); |
| 1928 | out_seq: |
| 1929 | pipex_session_log(session, LOG_DEBUG7, |
| 1930 | "Received bad data packet: out of sequence: seq=%u(%u-) " |
| 1931 | "ack=%u(%u-%u)", ns, l2tp_session->nr_nxt, nr, l2tp_session->ns_una, |
| 1932 | l2tp_session->ns_nxt); |
| 1933 | |
| 1934 | /* FALLTHROUGH */ |
| 1935 | drop: |
| 1936 | m_freem(m0); |
| 1937 | counters_inc(session->stat_counters, pxc_ierrors); |
| 1938 | |
| 1939 | return (NULL((void *)0)); |
| 1940 | } |
| 1941 | |
| 1942 | struct pipex_session * |
| 1943 | pipex_l2tp_userland_lookup_session_ipv4(struct mbuf *m0, struct in_addr dst) |
| 1944 | { |
| 1945 | struct sockaddr_in sin; |
| 1946 | |
| 1947 | memset(&sin, 0, sizeof(sin))__builtin_memset((&sin), (0), (sizeof(sin))); |
| 1948 | sin.sin_len = sizeof(sin); |
| 1949 | sin.sin_family = AF_INET2; |
| 1950 | sin.sin_addr = dst; |
| 1951 | |
| 1952 | return pipex_l2tp_userland_lookup_session(m0, sintosa(&sin)); |
| 1953 | } |
| 1954 | |
| 1955 | #ifdef INET61 |
| 1956 | struct pipex_session * |
| 1957 | pipex_l2tp_userland_lookup_session_ipv6(struct mbuf *m0, struct in6_addr dst) |
| 1958 | { |
| 1959 | struct sockaddr_in6 sin6; |
| 1960 | |
| 1961 | memset(&sin6, 0, sizeof(sin6))__builtin_memset((&sin6), (0), (sizeof(sin6))); |
| 1962 | sin6.sin6_len = sizeof(sin6); |
| 1963 | sin6.sin6_family = AF_INET624; |
| 1964 | in6_recoverscope(&sin6, &dst); |
| 1965 | |
| 1966 | return pipex_l2tp_userland_lookup_session(m0, sin6tosa(&sin6)); |
| 1967 | } |
| 1968 | #endif |
| 1969 | |
| 1970 | struct pipex_session * |
| 1971 | pipex_l2tp_userland_lookup_session(struct mbuf *m0, struct sockaddr *sa) |
| 1972 | { |
| 1973 | struct pipex_l2tp_header l2tp; |
| 1974 | struct pipex_hash_head *list; |
| 1975 | struct pipex_session *session; |
| 1976 | uint16_t session_id, tunnel_id, flags; |
| 1977 | |
| 1978 | if (sa->sa_family != AF_INET2 && sa->sa_family != AF_INET624) |
| 1979 | return (NULL((void *)0)); |
| 1980 | |
| 1981 | /* pullup */ |
| 1982 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < sizeof(l2tp)) { |
| 1983 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1984 | "<%s> packet length is too short", __func__)); |
| 1985 | return (NULL((void *)0)); |
| 1986 | } |
| 1987 | |
| 1988 | /* get flags */ |
| 1989 | m_copydata(m0, 0, sizeof(l2tp), &l2tp); |
| 1990 | flags = ntohs(l2tp.flagsver)(__uint16_t)(__builtin_constant_p(l2tp.flagsver) ? (__uint16_t )(((__uint16_t)(l2tp.flagsver) & 0xffU) << 8 | ((__uint16_t )(l2tp.flagsver) & 0xff00U) >> 8) : __swap16md(l2tp .flagsver)); |
| 1991 | |
| 1992 | /* l2tp version must be '2' */ |
| 1993 | if ((flags & PIPEX_L2TP_VER_MASK0x000f) != PIPEX_L2TP_VER2) { |
| 1994 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 1995 | "<%s> l2tp header wrong version.", __func__)); |
| 1996 | return (NULL((void *)0)); |
| 1997 | } |
| 1998 | /* We need L2TP data messages only */ |
| 1999 | if ((flags & PIPEX_L2TP_FLAG_TYPE0x8000) != 0) |
| 2000 | return (NULL((void *)0)); |
| 2001 | /* No need to hook packets that don't have the sequence field */ |
| 2002 | if ((flags & PIPEX_L2TP_FLAG_SEQUENCE0x0800) == 0) |
| 2003 | return (NULL((void *)0)); |
| 2004 | |
| 2005 | session_id = ntohs(l2tp.session_id)(__uint16_t)(__builtin_constant_p(l2tp.session_id) ? (__uint16_t )(((__uint16_t)(l2tp.session_id) & 0xffU) << 8 | (( __uint16_t)(l2tp.session_id) & 0xff00U) >> 8) : __swap16md (l2tp.session_id)); |
| 2006 | tunnel_id = ntohs(l2tp.tunnel_id)(__uint16_t)(__builtin_constant_p(l2tp.tunnel_id) ? (__uint16_t )(((__uint16_t)(l2tp.tunnel_id) & 0xffU) << 8 | ((__uint16_t )(l2tp.tunnel_id) & 0xff00U) >> 8) : __swap16md(l2tp .tunnel_id)); |
| 2007 | |
| 2008 | list = PIPEX_PEER_ADDR_HASHTABLE(pipex_sockaddr_hash_key(sa))(&pipex_peer_addr_hashtable[(pipex_sockaddr_hash_key(sa)) & ((512/8)-1)]); |
| 2009 | LIST_FOREACH(session, list, peer_addr_chain)for((session) = ((list)->lh_first); (session)!= ((void *)0 ); (session) = ((session)->peer_addr_chain.le_next)) { |
| 2010 | if (pipex_sockaddr_compar_addr(&session->peer.sa, sa) != 0) |
| 2011 | continue; |
| 2012 | if (session->proto.l2tp.peer_tunnel_id != tunnel_id) |
| 2013 | continue; |
| 2014 | if (session->peer_session_id == session_id) |
| 2015 | break; |
| 2016 | } |
| 2017 | #ifdef PIPEX_DEBUG |
| 2018 | if (session == NULL((void *)0)) { |
| 2019 | PIPEX_DBG((NULL, LOG_DEBUG, "<%s> session not found " |
| 2020 | "(tunnel_id=%d, session_id=%d)", __func__, |
| 2021 | tunnel_id, session_id)); |
| 2022 | } |
| 2023 | #endif |
| 2024 | |
| 2025 | return (session); |
| 2026 | } |
| 2027 | |
| 2028 | struct mbuf * |
| 2029 | pipex_l2tp_userland_output(struct mbuf *m0, struct pipex_session *session) |
| 2030 | { |
| 2031 | struct pipex_l2tp_header *l2tp; |
| 2032 | struct pipex_l2tp_seq_header *seq; |
| 2033 | uint16_t ns, nr; |
| 2034 | |
| 2035 | /* check length */ |
| 2036 | PIPEX_PULLUP(m0, sizeof(struct pipex_l2tp_header) +if ((m0)->m_hdr.mh_len < (sizeof(struct pipex_l2tp_header ) + sizeof(struct pipex_l2tp_seq_header))) { if ((m0)->M_dat .MH.MH_pkthdr.len < (sizeof(struct pipex_l2tp_header) + sizeof (struct pipex_l2tp_seq_header))) { ; m_freem(m0); (m0) = ((void *)0); } else { (m0) = m_pullup((m0), (sizeof(struct pipex_l2tp_header ) + sizeof(struct pipex_l2tp_seq_header))); (((m0) != ((void * )0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2037, "(m0) != NULL")); } } |
| 2037 | sizeof(struct pipex_l2tp_seq_header))if ((m0)->m_hdr.mh_len < (sizeof(struct pipex_l2tp_header ) + sizeof(struct pipex_l2tp_seq_header))) { if ((m0)->M_dat .MH.MH_pkthdr.len < (sizeof(struct pipex_l2tp_header) + sizeof (struct pipex_l2tp_seq_header))) { ; m_freem(m0); (m0) = ((void *)0); } else { (m0) = m_pullup((m0), (sizeof(struct pipex_l2tp_header ) + sizeof(struct pipex_l2tp_seq_header))); (((m0) != ((void * )0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2037, "(m0) != NULL")); } }; |
| 2038 | if (m0 == NULL((void *)0)) |
| 2039 | return (NULL((void *)0)); |
| 2040 | |
| 2041 | l2tp = mtod(m0, struct pipex_l2tp_header *)((struct pipex_l2tp_header *)((m0)->m_hdr.mh_data)); |
| 2042 | KASSERT(ntohs(l2tp->flagsver) & PIPEX_L2TP_FLAG_SEQUENCE)(((__uint16_t)(__builtin_constant_p(l2tp->flagsver) ? (__uint16_t )(((__uint16_t)(l2tp->flagsver) & 0xffU) << 8 | ( (__uint16_t)(l2tp->flagsver) & 0xff00U) >> 8) : __swap16md (l2tp->flagsver)) & 0x0800) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 2042, "ntohs(l2tp->flagsver) & PIPEX_L2TP_FLAG_SEQUENCE" )); |
| 2043 | |
| 2044 | /* |
| 2045 | * overwrite sequence numbers to adjust a gap between pipex and |
| 2046 | * userland. |
| 2047 | */ |
| 2048 | seq = (struct pipex_l2tp_seq_header *)(l2tp + 1); |
| 2049 | ns = ntohs(seq->ns)(__uint16_t)(__builtin_constant_p(seq->ns) ? (__uint16_t)( ((__uint16_t)(seq->ns) & 0xffU) << 8 | ((__uint16_t )(seq->ns) & 0xff00U) >> 8) : __swap16md(seq-> ns)); |
| 2050 | nr = ntohs(seq->nr)(__uint16_t)(__builtin_constant_p(seq->nr) ? (__uint16_t)( ((__uint16_t)(seq->nr) & 0xffU) << 8 | ((__uint16_t )(seq->nr) & 0xff00U) >> 8) : __swap16md(seq-> nr)); |
| 2051 | |
| 2052 | ns += session->proto.l2tp.ns_gap; |
| 2053 | seq->ns = htons(ns)(__uint16_t)(__builtin_constant_p(ns) ? (__uint16_t)(((__uint16_t )(ns) & 0xffU) << 8 | ((__uint16_t)(ns) & 0xff00U ) >> 8) : __swap16md(ns)); |
| 2054 | session->proto.l2tp.ns_nxt++; |
| 2055 | |
| 2056 | nr += session->proto.l2tp.nr_gap; |
| 2057 | seq->nr = htons(nr)(__uint16_t)(__builtin_constant_p(nr) ? (__uint16_t)(((__uint16_t )(nr) & 0xffU) << 8 | ((__uint16_t)(nr) & 0xff00U ) >> 8) : __swap16md(nr)); |
| 2058 | if (SEQ16_GT(nr, session->proto.l2tp.nr_acked)((int16_t)((nr) - (session->proto.l2tp.nr_acked)) > 0)) |
| 2059 | session->proto.l2tp.nr_acked = nr; |
| 2060 | |
| 2061 | return (m0); |
| 2062 | } |
| 2063 | #endif /* PIPEX_L2TP */ |
| 2064 | |
| 2065 | #ifdef PIPEX_MPPE1 |
| 2066 | /********************************************************************** |
| 2067 | * MPPE |
| 2068 | ***********************************************************************/ |
| 2069 | #define PIPEX_COHERENCY_CNT_MASK0x0fff 0x0fff |
| 2070 | |
| 2071 | static inline int |
| 2072 | pipex_mppe_setkey(struct pipex_mppe *mppe) |
| 2073 | { |
| 2074 | rc4_keysetup(&mppe->rc4ctx, mppe->session_key, mppe->keylen); |
| 2075 | |
| 2076 | return (0); |
| 2077 | } |
| 2078 | |
| 2079 | static inline int |
| 2080 | pipex_mppe_setoldkey(struct pipex_mppe *mppe, uint16_t coher_cnt) |
| 2081 | { |
| 2082 | KASSERT(mppe->old_session_keys != NULL)((mppe->old_session_keys != ((void *)0)) ? (void)0 : __assert ("diagnostic ", "/usr/src/sys/net/pipex.c", 2082, "mppe->old_session_keys != NULL" )); |
| 2083 | |
| 2084 | rc4_keysetup(&mppe->rc4ctx, |
| 2085 | mppe->old_session_keys[coher_cnt & PIPEX_MPPE_OLDKEYMASK(64 - 1)], |
| 2086 | mppe->keylen); |
| 2087 | |
| 2088 | return (0); |
| 2089 | } |
| 2090 | |
| 2091 | static inline void |
| 2092 | pipex_mppe_crypt(struct pipex_mppe *mppe, int len, u_char *indata, |
| 2093 | u_char *outdata) |
| 2094 | { |
| 2095 | rc4_crypt(&mppe->rc4ctx, indata, outdata, len); |
| 2096 | } |
| 2097 | |
| 2098 | Static void |
| 2099 | pipex_mppe_init(struct pipex_mppe *mppe, int stateless, int keylenbits, |
| 2100 | u_char *master_key, int has_oldkey) |
| 2101 | { |
| 2102 | memset(mppe, 0, sizeof(struct pipex_mppe))__builtin_memset((mppe), (0), (sizeof(struct pipex_mppe))); |
| 2103 | mtx_init(&mppe->pxm_mtx, IPL_SOFTNET)do { (void)(((void *)0)); (void)(0); __mtx_init((&mppe-> pxm_mtx), ((((0x5)) > 0x0 && ((0x5)) < 0x9) ? 0x9 : ((0x5)))); } while (0); |
| 2104 | if (stateless) |
| 2105 | mppe->stateless = 1; |
| 2106 | if (has_oldkey) |
| 2107 | mppe->old_session_keys = |
| 2108 | pool_get(&mppe_key_pool, PR_WAITOK0x0001); |
| 2109 | else |
| 2110 | mppe->old_session_keys = NULL((void *)0); |
| 2111 | memcpy(mppe->master_key, master_key, sizeof(mppe->master_key))__builtin_memcpy((mppe->master_key), (master_key), (sizeof (mppe->master_key))); |
| 2112 | |
| 2113 | mppe->keylenbits = keylenbits; |
| 2114 | switch (keylenbits) { |
| 2115 | case 40: |
| 2116 | case 56: |
| 2117 | mppe->keylen = 8; |
| 2118 | break; |
| 2119 | case 128: |
| 2120 | mppe->keylen = 16; |
| 2121 | break; |
| 2122 | } |
| 2123 | |
| 2124 | GetNewKeyFromSHA(mppe->master_key, mppe->master_key, mppe->keylen, |
| 2125 | mppe->session_key); |
| 2126 | pipex_mppe_reduce_key(mppe); |
| 2127 | pipex_mppe_setkey(mppe); |
| 2128 | } |
| 2129 | |
| 2130 | void |
| 2131 | pipex_session_init_mppe_recv(struct pipex_session *session, int stateless, |
| 2132 | int keylenbits, u_char *master_key) |
| 2133 | { |
| 2134 | pipex_mppe_init(&session->mppe_recv, stateless, keylenbits, |
| 2135 | master_key, stateless); |
| 2136 | session->ppp_flags |= PIPEX_PPP_MPPE_ACCEPTED0x0010; |
| 2137 | } |
| 2138 | |
| 2139 | void |
| 2140 | pipex_session_init_mppe_send(struct pipex_session *session, int stateless, |
| 2141 | int keylenbits, u_char *master_key) |
| 2142 | { |
| 2143 | pipex_mppe_init(&session->mppe_send, stateless, keylenbits, |
| 2144 | master_key, 0); |
| 2145 | session->ppp_flags |= PIPEX_PPP_MPPE_ENABLED0x0020; |
| 2146 | } |
| 2147 | |
| 2148 | #include <crypto/sha1.h> |
| 2149 | |
| 2150 | static u_char SHAPad1[] = { |
| 2151 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 2152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 2153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 2154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 2155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 2156 | }, SHAPad2[] = { |
| 2157 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
| 2158 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
| 2159 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
| 2160 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
| 2161 | 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, |
| 2162 | }; |
| 2163 | |
| 2164 | Static void |
| 2165 | GetNewKeyFromSHA(u_char *StartKey, u_char *SessionKey, int SessionKeyLength, |
| 2166 | u_char *InterimKey) |
| 2167 | { |
| 2168 | u_char Digest[20]; |
| 2169 | SHA1_CTX Context; |
| 2170 | |
| 2171 | SHA1Init(&Context); |
| 2172 | SHA1Update(&Context, StartKey, SessionKeyLength); |
| 2173 | SHA1Update(&Context, SHAPad1, 40); |
| 2174 | SHA1Update(&Context, SessionKey, SessionKeyLength); |
| 2175 | SHA1Update(&Context, SHAPad2, 40); |
| 2176 | SHA1Final(Digest, &Context); |
| 2177 | |
| 2178 | memcpy(InterimKey, Digest, SessionKeyLength)__builtin_memcpy((InterimKey), (Digest), (SessionKeyLength)); |
| 2179 | } |
| 2180 | |
| 2181 | Static void |
| 2182 | pipex_mppe_reduce_key(struct pipex_mppe *mppe) |
| 2183 | { |
| 2184 | switch (mppe->keylenbits) { |
| 2185 | case 40: |
| 2186 | mppe->session_key[0] = 0xd1; |
| 2187 | mppe->session_key[1] = 0x26; |
| 2188 | mppe->session_key[2] = 0x9e; |
| 2189 | break; |
| 2190 | case 56: |
| 2191 | mppe->session_key[0] = 0xd1; |
| 2192 | break; |
| 2193 | } |
| 2194 | } |
| 2195 | |
| 2196 | Static void |
| 2197 | mppe_key_change(struct pipex_mppe *mppe) |
| 2198 | { |
| 2199 | u_char interim[16]; |
| 2200 | struct rc4_ctx keychg; |
| 2201 | |
| 2202 | memset(&keychg, 0, sizeof(keychg))__builtin_memset((&keychg), (0), (sizeof(keychg))); |
| 2203 | |
| 2204 | GetNewKeyFromSHA(mppe->master_key, mppe->session_key, mppe->keylen, |
| 2205 | interim); |
| 2206 | |
| 2207 | rc4_keysetup(&keychg, interim, mppe->keylen); |
| 2208 | rc4_crypt(&keychg, interim, mppe->session_key, mppe->keylen); |
| 2209 | |
| 2210 | pipex_mppe_reduce_key(mppe); |
| 2211 | |
| 2212 | if (mppe->old_session_keys) { |
| 2213 | int idx = mppe->coher_cnt & PIPEX_MPPE_OLDKEYMASK(64 - 1); |
| 2214 | memcpy(mppe->old_session_keys[idx],__builtin_memcpy((mppe->old_session_keys[idx]), (mppe-> session_key), (16)) |
| 2215 | mppe->session_key, PIPEX_MPPE_KEYLEN)__builtin_memcpy((mppe->old_session_keys[idx]), (mppe-> session_key), (16)); |
| 2216 | } |
| 2217 | } |
| 2218 | |
| 2219 | Static void |
| 2220 | pipex_mppe_input(struct mbuf *m0, struct pipex_session *session) |
| 2221 | { |
| 2222 | int pktloss, encrypt, flushed, m, n, len; |
| 2223 | struct pipex_mppe *mppe; |
| 2224 | uint16_t coher_cnt; |
| 2225 | struct mbuf *m1; |
| 2226 | u_char *cp; |
| 2227 | int rewind = 0; |
| 2228 | |
| 2229 | /* pullup */ |
| 2230 | PIPEX_PULLUP(m0, sizeof(coher_cnt))if ((m0)->m_hdr.mh_len < (sizeof(coher_cnt))) { if ((m0 )->M_dat.MH.MH_pkthdr.len < (sizeof(coher_cnt))) { ; m_freem (m0); (m0) = ((void *)0); } else { (m0) = m_pullup((m0), (sizeof (coher_cnt))); (((m0) != ((void *)0)) ? (void)0 : __assert("diagnostic " , "/usr/src/sys/net/pipex.c", 2230, "(m0) != NULL")); } }; |
| 2231 | if (m0 == NULL((void *)0)) |
| 2232 | goto drop; |
| 2233 | |
| 2234 | mppe = &session->mppe_recv; |
| 2235 | /* get header information */ |
| 2236 | cp = mtod(m0, u_char *)((u_char *)((m0)->m_hdr.mh_data)); |
| 2237 | GETSHORT(coher_cnt, cp)do { (coher_cnt) = *(cp)++ << 8; (coher_cnt) |= *(cp)++ ; } while (0); |
| 2238 | flushed = ((coher_cnt & 0x8000) != 0) ? 1 : 0; |
| 2239 | encrypt = ((coher_cnt & 0x1000) != 0) ? 1 : 0; |
| 2240 | coher_cnt &= PIPEX_COHERENCY_CNT_MASK0x0fff; |
| 2241 | pktloss = 0; |
| 2242 | |
| 2243 | mtx_enter(&mppe->pxm_mtx); |
| 2244 | |
| 2245 | PIPEX_MPPE_DBG((session, LOG_DEBUG, "in coher_cnt=%03x %s%s", |
| 2246 | mppe->coher_cnt, (flushed) ? "[flushed]" : "", |
| 2247 | (encrypt) ? "[encrypt]" : "")); |
| 2248 | |
| 2249 | if (encrypt == 0) { |
| 2250 | mtx_leave(&mppe->pxm_mtx); |
| 2251 | pipex_session_log(session, LOG_DEBUG7, |
| 2252 | "Received unexpected MPPE packet.(no ecrypt)"); |
| 2253 | goto drop; |
| 2254 | } |
| 2255 | |
| 2256 | /* adjust mbuf */ |
| 2257 | m_adj(m0, sizeof(coher_cnt)); |
| 2258 | |
| 2259 | /* |
| 2260 | * L2TP data session may be used without sequencing, PPP frames may |
| 2261 | * arrive in disorder. The 'coherency counter' of MPPE detects such |
| 2262 | * situations, but we cannot distinguish between 'disorder' and |
| 2263 | * 'packet loss' exactly. |
| 2264 | * |
| 2265 | * When 'coherency counter' detects lost packets greater than |
| 2266 | * (4096 - 256), we treat as 'disorder' otherwise treat as |
| 2267 | * 'packet loss'. |
| 2268 | */ |
| 2269 | { |
| 2270 | int coher_cnt0; |
| 2271 | |
| 2272 | coher_cnt0 = coher_cnt; |
| 2273 | if (coher_cnt < mppe->coher_cnt) |
| 2274 | coher_cnt0 += 0x1000; |
| 2275 | if (coher_cnt0 - mppe->coher_cnt > 0x0f00) { |
| 2276 | if (!mppe->stateless || |
| 2277 | coher_cnt0 - mppe->coher_cnt |
| 2278 | <= 0x1000 - PIPEX_MPPE_NOLDKEY64) { |
| 2279 | pipex_session_log(session, LOG_DEBUG7, |
| 2280 | "Workaround the out-of-sequence PPP framing problem: " |
| 2281 | "%d => %d", mppe->coher_cnt, coher_cnt); |
| 2282 | mtx_leave(&mppe->pxm_mtx); |
| 2283 | goto drop; |
| 2284 | } |
| 2285 | rewind = 1; |
| 2286 | } |
| 2287 | } |
| 2288 | |
| 2289 | if (mppe->stateless != 0) { |
| 2290 | if (!rewind) { |
| 2291 | mppe_key_change(mppe); |
| 2292 | while (mppe->coher_cnt != coher_cnt) { |
| 2293 | mppe->coher_cnt++; |
| 2294 | mppe->coher_cnt &= PIPEX_COHERENCY_CNT_MASK0x0fff; |
| 2295 | mppe_key_change(mppe); |
| 2296 | pktloss++; |
| 2297 | } |
| 2298 | } |
| 2299 | pipex_mppe_setoldkey(mppe, coher_cnt); |
| 2300 | } else { |
| 2301 | if (flushed) { |
| 2302 | if (coher_cnt < mppe->coher_cnt) { |
| 2303 | coher_cnt += 0x1000; |
| 2304 | } |
| 2305 | pktloss += coher_cnt - mppe->coher_cnt; |
| 2306 | m = mppe->coher_cnt / 256; |
| 2307 | n = coher_cnt / 256; |
| 2308 | while (m++ < n) |
| 2309 | mppe_key_change(mppe); |
| 2310 | |
| 2311 | coher_cnt &= PIPEX_COHERENCY_CNT_MASK0x0fff; |
| 2312 | mppe->coher_cnt = coher_cnt; |
| 2313 | } else if (mppe->coher_cnt != coher_cnt) { |
| 2314 | int ccp_id; |
| 2315 | |
| 2316 | mtx_leave(&mppe->pxm_mtx); |
| 2317 | |
| 2318 | /* Send CCP ResetReq */ |
| 2319 | PIPEX_DBG((session, LOG_DEBUG, "CCP SendResetReq")); |
| 2320 | |
| 2321 | mtx_enter(&session->pxs_mtx); |
| 2322 | ccp_id = session->ccp_id; |
| 2323 | session->ccp_id++; |
| 2324 | mtx_leave(&session->pxs_mtx); |
| 2325 | |
| 2326 | pipex_ccp_output(session, CCP_RESETREQ14, ccp_id); |
| 2327 | goto drop; |
| 2328 | } |
| 2329 | if ((coher_cnt & 0xff) == 0xff) { |
| 2330 | mppe_key_change(mppe); |
| 2331 | flushed = 1; |
| 2332 | } |
| 2333 | if (flushed) |
| 2334 | pipex_mppe_setkey(mppe); |
| 2335 | } |
| 2336 | |
| 2337 | if (pktloss > 1000) { |
| 2338 | pipex_session_log(session, LOG_DEBUG7, |
| 2339 | "%d packets loss.", pktloss); |
| 2340 | } |
| 2341 | |
| 2342 | /* decrypt ppp payload */ |
| 2343 | for (m1 = m0; m1; m1 = m1->m_nextm_hdr.mh_next) { |
| 2344 | cp = mtod(m1, u_char *)((u_char *)((m1)->m_hdr.mh_data)); |
| 2345 | len = m1->m_lenm_hdr.mh_len; |
| 2346 | pipex_mppe_crypt(mppe, len, cp, cp); |
| 2347 | } |
| 2348 | |
| 2349 | if (!rewind) { |
| 2350 | /* update coher_cnt */ |
| 2351 | mppe->coher_cnt++; |
| 2352 | mppe->coher_cnt &= PIPEX_COHERENCY_CNT_MASK0x0fff; |
| 2353 | } |
| 2354 | |
| 2355 | mtx_leave(&mppe->pxm_mtx); |
| 2356 | |
| 2357 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < PIPEX_PPPMINLEN5) |
| 2358 | goto drop; |
| 2359 | |
| 2360 | pipex_ppp_input(m0, session, 1); |
| 2361 | |
| 2362 | return; |
| 2363 | drop: |
| 2364 | m_freem(m0); |
| 2365 | counters_inc(session->stat_counters, pxc_ierrors); |
| 2366 | } |
| 2367 | |
| 2368 | Static void |
| 2369 | pipex_mppe_output(struct mbuf *m0, struct pipex_session *session, |
| 2370 | uint16_t protocol) |
| 2371 | { |
| 2372 | int encrypt, flushed, len; |
| 2373 | struct mppe_header { |
| 2374 | uint16_t coher_cnt; |
| 2375 | uint16_t protocol; |
| 2376 | } __packed__attribute__((__packed__)) *hdr; |
| 2377 | u_char *cp; |
| 2378 | struct pipex_mppe *mppe; |
| 2379 | struct mbuf *m; |
| 2380 | |
| 2381 | mppe = &session->mppe_send; |
| 2382 | |
| 2383 | /* |
| 2384 | * create a deep-copy if the mbuf has a shared mbuf cluster. |
| 2385 | * this is required to handle cases of tcp retransmission. |
| 2386 | */ |
| 2387 | for (m = m0; m != NULL((void *)0); m = m->m_nextm_hdr.mh_next) { |
| 2388 | if (M_READONLY(m)(((m)->m_hdr.mh_flags & 0x0001) != 0 && (((m)-> m_hdr.mh_flags & 0x0008) == 0 || ((m)->M_dat.MH.MH_dat .MH_ext.ext_nextref != (m))))) { |
| 2389 | m = m_dup_pkt(m0, max_linkhdr, M_NOWAIT0x0002); |
| 2390 | m_freem(m0); |
| 2391 | if (m == NULL((void *)0)) |
| 2392 | goto drop; |
| 2393 | m0 = m; |
| 2394 | break; |
| 2395 | } |
| 2396 | } |
| 2397 | /* prepend mppe header */ |
| 2398 | M_PREPEND(m0, sizeof(struct mppe_header), M_NOWAIT)(m0) = m_prepend((m0), (sizeof(struct mppe_header)), (0x0002) ); |
| 2399 | if (m0 == NULL((void *)0)) |
| 2400 | goto drop; |
| 2401 | hdr = mtod(m0, struct mppe_header *)((struct mppe_header *)((m0)->m_hdr.mh_data)); |
| 2402 | hdr->protocol = protocol; |
| 2403 | |
| 2404 | /* check coherency counter */ |
| 2405 | flushed = 0; |
| 2406 | encrypt = 1; |
| 2407 | |
| 2408 | mtx_enter(&mppe->pxm_mtx); |
| 2409 | |
| 2410 | if (mppe->stateless != 0) { |
| 2411 | flushed = 1; |
| 2412 | mppe_key_change(mppe); |
| 2413 | } else { |
| 2414 | if ((mppe->coher_cnt % 0x100) == 0xff) { |
| 2415 | flushed = 1; |
| 2416 | mppe_key_change(mppe); |
| 2417 | } else if (mppe->resetreq != 0) { |
| 2418 | flushed = 1; |
| 2419 | mppe->resetreq = 0; |
| 2420 | } |
| 2421 | } |
| 2422 | |
| 2423 | if (flushed) |
| 2424 | pipex_mppe_setkey(mppe); |
| 2425 | |
| 2426 | PIPEX_MPPE_DBG((session, LOG_DEBUG, "out coher_cnt=%03x %s%s", |
| 2427 | mppe->coher_cnt, (flushed) ? "[flushed]" : "", |
| 2428 | (encrypt) ? "[encrypt]" : "")); |
| 2429 | |
| 2430 | /* setup header information */ |
| 2431 | hdr->coher_cnt = (mppe->coher_cnt++) & PIPEX_COHERENCY_CNT_MASK0x0fff; |
| 2432 | hdr->coher_cnt &= PIPEX_COHERENCY_CNT_MASK0x0fff; |
| 2433 | if (flushed) |
| 2434 | hdr->coher_cnt |= 0x8000; |
| 2435 | if (encrypt) |
| 2436 | hdr->coher_cnt |= 0x1000; |
| 2437 | |
| 2438 | hdr->protocol = htons(hdr->protocol)(__uint16_t)(__builtin_constant_p(hdr->protocol) ? (__uint16_t )(((__uint16_t)(hdr->protocol) & 0xffU) << 8 | ( (__uint16_t)(hdr->protocol) & 0xff00U) >> 8) : __swap16md (hdr->protocol)); |
| 2439 | hdr->coher_cnt = htons(hdr->coher_cnt)(__uint16_t)(__builtin_constant_p(hdr->coher_cnt) ? (__uint16_t )(((__uint16_t)(hdr->coher_cnt) & 0xffU) << 8 | ( (__uint16_t)(hdr->coher_cnt) & 0xff00U) >> 8) : __swap16md (hdr->coher_cnt)); |
| 2440 | |
| 2441 | /* encrypt chain */ |
| 2442 | for (m = m0; m; m = m->m_nextm_hdr.mh_next) { |
| 2443 | cp = mtod(m, u_char *)((u_char *)((m)->m_hdr.mh_data)); |
| 2444 | len = m->m_lenm_hdr.mh_len; |
| 2445 | if (m == m0 && len > offsetof(struct mppe_header, protocol)__builtin_offsetof(struct mppe_header, protocol)) { |
| 2446 | len -= offsetof(struct mppe_header, protocol)__builtin_offsetof(struct mppe_header, protocol); |
| 2447 | cp += offsetof(struct mppe_header, protocol)__builtin_offsetof(struct mppe_header, protocol); |
| 2448 | } |
| 2449 | pipex_mppe_crypt(mppe, len, cp, cp); |
| 2450 | } |
| 2451 | |
| 2452 | mtx_leave(&mppe->pxm_mtx); |
| 2453 | |
| 2454 | pipex_ppp_output(m0, session, PPP_COMP0xfd); |
| 2455 | |
| 2456 | return; |
| 2457 | drop: |
| 2458 | counters_inc(session->stat_counters, pxc_oerrors); |
| 2459 | } |
| 2460 | |
| 2461 | Static void |
| 2462 | pipex_ccp_input(struct mbuf *m0, struct pipex_session *session) |
| 2463 | { |
| 2464 | u_char *cp; |
| 2465 | int code, id, len; |
| 2466 | |
| 2467 | if (m0->m_pkthdrM_dat.MH.MH_pkthdr.len < PPP_HDRLEN4) |
| 2468 | goto drop; |
| 2469 | if ((m0 = m_pullup(m0, PPP_HDRLEN4)) == NULL((void *)0)) |
| 2470 | goto drop; |
| 2471 | |
| 2472 | cp = mtod(m0, u_char *)((u_char *)((m0)->m_hdr.mh_data)); |
| 2473 | GETCHAR(code, cp)do { (code) = *(cp)++; } while (0); |
| 2474 | GETCHAR(id, cp)do { (id) = *(cp)++; } while (0); |
| 2475 | GETSHORT(len, cp)do { (len) = *(cp)++ << 8; (len) |= *(cp)++; } while (0 ); |
| 2476 | |
| 2477 | switch (code) { |
| 2478 | case CCP_RESETREQ14: |
| 2479 | PIPEX_DBG((session, LOG_DEBUG, "CCP RecvResetReq")); |
| 2480 | mtx_enter(&session->mppe_send.pxm_mtx); |
| 2481 | session->mppe_send.resetreq = 1; |
| 2482 | mtx_leave(&session->mppe_send.pxm_mtx); |
| 2483 | #ifndef PIPEX_NO_CCP_RESETACK1 |
| 2484 | PIPEX_DBG((session, LOG_DEBUG, "CCP SendResetAck")); |
| 2485 | pipex_ccp_output(session, CCP_RESETACK15, id); |
| 2486 | #endif |
| 2487 | /* ignore error */ |
| 2488 | break; |
| 2489 | case CCP_RESETACK15: |
| 2490 | PIPEX_DBG((session, LOG_DEBUG, "CCP RecvResetAck")); |
| 2491 | break; |
| 2492 | default: |
| 2493 | PIPEX_DBG((session, LOG_DEBUG, "CCP Recv code=%d", code)); |
| 2494 | goto drop; |
| 2495 | } |
| 2496 | m_freem(m0); |
| 2497 | |
| 2498 | return; |
| 2499 | drop: |
| 2500 | m_freem(m0); |
| 2501 | counters_inc(session->stat_counters, pxc_ierrors); |
| 2502 | } |
| 2503 | |
| 2504 | Static int |
| 2505 | pipex_ccp_output(struct pipex_session *session, int code, int id) |
| 2506 | { |
| 2507 | u_char *cp; |
| 2508 | struct mbuf *m; |
| 2509 | |
| 2510 | MGETHDR(m, M_DONTWAIT, MT_DATA)m = m_gethdr((0x0002), (1)); |
| 2511 | if (m == NULL((void *)0)) { |
| 2512 | counters_inc(session->stat_counters, pxc_oerrors); |
| 2513 | return (1); |
| 2514 | } |
| 2515 | m->m_pkthdrM_dat.MH.MH_pkthdr.len = m->m_lenm_hdr.mh_len = 4; |
| 2516 | cp = mtod(m, u_char *)((u_char *)((m)->m_hdr.mh_data)); |
| 2517 | PUTCHAR(code, cp)do { *(cp)++ = (u_char)(code); } while (0); |
| 2518 | PUTCHAR(id, cp)do { *(cp)++ = (u_char)(id); } while (0); |
| 2519 | PUTSHORT(4, cp)do { *(cp)++ = (u_char) ((4) >> 8); *(cp)++ = (u_char) ( 4); } while (0); |
| 2520 | |
| 2521 | pipex_ppp_output(m, session, PPP_CCP0x80fd); |
| 2522 | |
| 2523 | return (0); |
| 2524 | } |
| 2525 | #endif |
| 2526 | /*********************************************************************** |
| 2527 | * Miscellaneous functions |
| 2528 | ***********************************************************************/ |
| 2529 | /* adapted from FreeBSD:src/usr.sbin/ppp/tcpmss.c */ |
| 2530 | /* |
| 2531 | * Copyright (c) 2000 Ruslan Ermilov and Brian Somers <brian@Awfulhak.org> |
| 2532 | * All rights reserved. |
| 2533 | * |
| 2534 | * Redistribution and use in source and binary forms, with or without |
| 2535 | * modification, are permitted provided that the following conditions |
| 2536 | * are met: |
| 2537 | * 1. Redistributions of source code must retain the above copyright |
| 2538 | * notice, this list of conditions and the following disclaimer. |
| 2539 | * 2. Redistributions in binary form must reproduce the above copyright |
| 2540 | * notice, this list of conditions and the following disclaimer in the |
| 2541 | * documentation and/or other materials provided with the distribution. |
| 2542 | * |
| 2543 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 2544 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 2545 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 2546 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 2547 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 2548 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 2549 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 2550 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 2551 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 2552 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 2553 | * SUCH DAMAGE. |
| 2554 | * |
| 2555 | * $FreeBSD: src/usr.sbin/ppp/tcpmss.c,v 1.1.4.3 2001/07/19 11:39:54 brian Exp $ |
| 2556 | */ |
| 2557 | #define TCP_OPTLEN_IN_SEGMENT12 12 /* timestamp option and padding */ |
| 2558 | #define MAXMSS(mtu)(mtu - sizeof(struct ip) - sizeof(struct tcphdr) - 12) (mtu - sizeof(struct ip) - sizeof(struct tcphdr) - \ |
| 2559 | TCP_OPTLEN_IN_SEGMENT12) |
| 2560 | /* |
| 2561 | * The following macro is used to update an internet checksum. "acc" is a |
| 2562 | * 32-bit accumulation of all the changes to the checksum (adding in old |
| 2563 | * 16-bit words and subtracting out new words), and "cksum" is the checksum |
| 2564 | * value to be updated. |
| 2565 | */ |
| 2566 | #define ADJUST_CHECKSUM(acc, cksum){ acc += cksum; if (acc < 0) { acc = -acc; acc = (acc >> 16) + (acc & 0xffff); acc += acc >> 16; cksum = (u_short ) ~acc; } else { acc = (acc >> 16) + (acc & 0xffff) ; acc += acc >> 16; cksum = (u_short) acc; } } { \ |
| 2567 | acc += cksum; \ |
| 2568 | if (acc < 0) { \ |
| 2569 | acc = -acc; \ |
| 2570 | acc = (acc >> 16) + (acc & 0xffff); \ |
| 2571 | acc += acc >> 16; \ |
| 2572 | cksum = (u_short) ~acc; \ |
| 2573 | } else { \ |
| 2574 | acc = (acc >> 16) + (acc & 0xffff); \ |
| 2575 | acc += acc >> 16; \ |
| 2576 | cksum = (u_short) acc; \ |
| 2577 | } \ |
| 2578 | } |
| 2579 | |
| 2580 | /* |
| 2581 | * Rewrite max-segment-size TCP option to avoid PMTU blackhole issues. |
| 2582 | * The mtu parameter should be the MTU bottleneck (as far as we know) |
| 2583 | * on the link between the source and the destination. |
| 2584 | */ |
| 2585 | Static struct mbuf * |
| 2586 | adjust_tcp_mss(struct mbuf *m0, int mtu) |
| 2587 | { |
| 2588 | int opt, optlen, acc, mss, maxmss, lpktp; |
| 2589 | struct ip *pip; |
| 2590 | struct tcphdr *th; |
| 2591 | u_char *pktp, *mssp; |
| 2592 | u_int16_t ip_off; |
| 2593 | |
| 2594 | lpktp = sizeof(struct ip) + sizeof(struct tcphdr) + PIPEX_TCP_OPTLEN40; |
| 2595 | lpktp = MIN(lpktp, m0->m_pkthdr.len)(((lpktp)<(m0->M_dat.MH.MH_pkthdr.len))?(lpktp):(m0-> M_dat.MH.MH_pkthdr.len)); |
| 2596 | |
| 2597 | PIPEX_PULLUP(m0, lpktp)if ((m0)->m_hdr.mh_len < (lpktp)) { if ((m0)->M_dat. MH.MH_pkthdr.len < (lpktp)) { ; m_freem(m0); (m0) = ((void *)0); } else { (m0) = m_pullup((m0), (lpktp)); (((m0) != ((void *)0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2597, "(m0) != NULL")); } }; |
| 2598 | if (m0 == NULL((void *)0)) |
| 2599 | goto drop; |
| 2600 | |
| 2601 | pktp = mtod(m0, char *)((char *)((m0)->m_hdr.mh_data)); |
| 2602 | pip = (struct ip *)pktp; |
| 2603 | ip_off = ntohs(pip->ip_off)(__uint16_t)(__builtin_constant_p(pip->ip_off) ? (__uint16_t )(((__uint16_t)(pip->ip_off) & 0xffU) << 8 | ((__uint16_t )(pip->ip_off) & 0xff00U) >> 8) : __swap16md(pip ->ip_off)); |
| 2604 | |
| 2605 | /* Non TCP or fragmented packet must not have a MSS option */ |
| 2606 | if (pip->ip_p != IPPROTO_TCP6 || |
| 2607 | (ip_off & IP_MF0x2000) != 0 || (ip_off & IP_OFFMASK0x1fff) != 0) |
| 2608 | goto handled; |
| 2609 | |
| 2610 | pktp += pip->ip_hl << 2; |
| 2611 | lpktp -= pip->ip_hl << 2; |
| 2612 | |
| 2613 | /* packet is broken */ |
| 2614 | if (sizeof(struct tcphdr) > lpktp) |
| 2615 | goto drop; |
| 2616 | th = (struct tcphdr *)pktp; |
| 2617 | |
| 2618 | /* |
| 2619 | * As RFC 973, a MSS field must only be sent in the initial |
| 2620 | * connection request(it must be with SYN). |
| 2621 | */ |
| 2622 | if ((th->th_flags & TH_SYN0x02) == 0) |
| 2623 | goto handled; |
| 2624 | |
| 2625 | lpktp = MIN(th->th_off << 4, lpktp)(((th->th_off << 4)<(lpktp))?(th->th_off << 4):(lpktp)); |
| 2626 | |
| 2627 | pktp += sizeof(struct tcphdr); |
| 2628 | lpktp -= sizeof(struct tcphdr); |
| 2629 | while (lpktp >= TCPOLEN_MAXSEG4) { |
| 2630 | GETCHAR(opt, pktp)do { (opt) = *(pktp)++; } while (0); |
| 2631 | switch (opt) { |
| 2632 | case TCPOPT_MAXSEG2: |
| 2633 | GETCHAR(optlen, pktp)do { (optlen) = *(pktp)++; } while (0); |
| 2634 | mssp = pktp; /* mss place holder */ |
| 2635 | GETSHORT(mss, pktp)do { (mss) = *(pktp)++ << 8; (mss) |= *(pktp)++; } while (0); |
| 2636 | maxmss = MAXMSS(mtu)(mtu - sizeof(struct ip) - sizeof(struct tcphdr) - 12); |
| 2637 | if (mss > maxmss) { |
| 2638 | PIPEX_DBG((NULL, LOG_DEBUG, |
| 2639 | "change tcp-mss %d => %d", mss, maxmss)); |
| 2640 | PUTSHORT(maxmss, mssp)do { *(mssp)++ = (u_char) ((maxmss) >> 8); *(mssp)++ = ( u_char) (maxmss); } while (0); |
| 2641 | acc = htons(mss)(__uint16_t)(__builtin_constant_p(mss) ? (__uint16_t)(((__uint16_t )(mss) & 0xffU) << 8 | ((__uint16_t)(mss) & 0xff00U ) >> 8) : __swap16md(mss)); |
| 2642 | acc -= htons(maxmss)(__uint16_t)(__builtin_constant_p(maxmss) ? (__uint16_t)(((__uint16_t )(maxmss) & 0xffU) << 8 | ((__uint16_t)(maxmss) & 0xff00U) >> 8) : __swap16md(maxmss)); |
| 2643 | ADJUST_CHECKSUM(acc, th->th_sum){ acc += th->th_sum; if (acc < 0) { acc = -acc; acc = ( acc >> 16) + (acc & 0xffff); acc += acc >> 16 ; th->th_sum = (u_short) ~acc; } else { acc = (acc >> 16) + (acc & 0xffff); acc += acc >> 16; th->th_sum = (u_short) acc; } }; |
| 2644 | } |
| 2645 | goto handled; |
| 2646 | /* NOTREACHED */ |
| 2647 | case TCPOPT_EOL0: |
| 2648 | goto handled; |
| 2649 | /* NOTREACHED */ |
| 2650 | case TCPOPT_NOP1: |
| 2651 | lpktp--; |
| 2652 | break; |
| 2653 | default: |
| 2654 | GETCHAR(optlen, pktp)do { (optlen) = *(pktp)++; } while (0); |
| 2655 | if (optlen < 2) /* packet is broken */ |
| 2656 | goto drop; |
| 2657 | pktp += optlen - 2; |
| 2658 | lpktp -= optlen; |
| 2659 | break; |
| 2660 | } |
| 2661 | } |
| 2662 | |
| 2663 | handled: |
| 2664 | return (m0); |
| 2665 | |
| 2666 | drop: |
| 2667 | m_freem(m0); |
| 2668 | return (NULL((void *)0)); |
| 2669 | } |
| 2670 | |
| 2671 | /* |
| 2672 | * Check whether a packet should reset idle timer |
| 2673 | * Returns 1 to don't reset timer (i.e. the packet is "idle" packet) |
| 2674 | */ |
| 2675 | Static struct mbuf * |
| 2676 | ip_is_idle_packet(struct mbuf *m0, int *ris_idle) |
| 2677 | { |
| 2678 | u_int16_t ip_off; |
| 2679 | const struct udphdr *uh; |
| 2680 | struct ip *pip; |
| 2681 | int len; |
| 2682 | |
| 2683 | /* pullup ip header */ |
| 2684 | len = sizeof(struct ip); |
| 2685 | PIPEX_PULLUP(m0, len)if ((m0)->m_hdr.mh_len < (len)) { if ((m0)->M_dat.MH .MH_pkthdr.len < (len)) { ; m_freem(m0); (m0) = ((void *)0 ); } else { (m0) = m_pullup((m0), (len)); (((m0) != ((void *) 0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2685, "(m0) != NULL")); } }; |
| 2686 | if (m0 == NULL((void *)0)) |
| 2687 | goto error; |
| 2688 | pip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
| 2689 | |
| 2690 | /* |
| 2691 | * the packet which fragmentations was not the idle packet. |
| 2692 | */ |
| 2693 | ip_off = ntohs(pip->ip_off)(__uint16_t)(__builtin_constant_p(pip->ip_off) ? (__uint16_t )(((__uint16_t)(pip->ip_off) & 0xffU) << 8 | ((__uint16_t )(pip->ip_off) & 0xff00U) >> 8) : __swap16md(pip ->ip_off)); |
| 2694 | if ((ip_off & IP_MF0x2000) || ((ip_off & IP_OFFMASK0x1fff) != 0)) |
| 2695 | goto is_active; |
| 2696 | |
| 2697 | switch (pip->ip_p) { |
| 2698 | case IPPROTO_IGMP2: |
| 2699 | goto is_active; |
| 2700 | case IPPROTO_ICMP1: |
| 2701 | len = pip->ip_hl * 4 + 8; |
| 2702 | PIPEX_PULLUP(m0, len)if ((m0)->m_hdr.mh_len < (len)) { if ((m0)->M_dat.MH .MH_pkthdr.len < (len)) { ; m_freem(m0); (m0) = ((void *)0 ); } else { (m0) = m_pullup((m0), (len)); (((m0) != ((void *) 0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2702, "(m0) != NULL")); } }; |
| 2703 | if (m0 == NULL((void *)0)) |
| 2704 | goto error; |
| 2705 | pip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
| 2706 | |
| 2707 | switch (((unsigned char *) pip)[pip->ip_hl * 4]) { |
| 2708 | case 0: /* Echo Reply */ |
| 2709 | case 8: /* Echo Request */ |
| 2710 | goto is_active; |
| 2711 | default: |
| 2712 | goto is_idle; |
| 2713 | } |
| 2714 | |
| 2715 | case IPPROTO_UDP17: |
| 2716 | case IPPROTO_TCP6: |
| 2717 | len = pip->ip_hl * 4 + sizeof(struct udphdr); |
| 2718 | PIPEX_PULLUP(m0, len)if ((m0)->m_hdr.mh_len < (len)) { if ((m0)->M_dat.MH .MH_pkthdr.len < (len)) { ; m_freem(m0); (m0) = ((void *)0 ); } else { (m0) = m_pullup((m0), (len)); (((m0) != ((void *) 0)) ? (void)0 : __assert("diagnostic ", "/usr/src/sys/net/pipex.c" , 2718, "(m0) != NULL")); } }; |
| 2719 | if (m0 == NULL((void *)0)) |
| 2720 | goto error; |
| 2721 | pip = mtod(m0, struct ip *)((struct ip *)((m0)->m_hdr.mh_data)); |
| 2722 | uh = (struct udphdr *)(mtod(m0, caddr_t)((caddr_t)((m0)->m_hdr.mh_data)) + pip->ip_hl * 4); |
| 2723 | |
| 2724 | switch (ntohs(uh->uh_sport)(__uint16_t)(__builtin_constant_p(uh->uh_sport) ? (__uint16_t )(((__uint16_t)(uh->uh_sport) & 0xffU) << 8 | (( __uint16_t)(uh->uh_sport) & 0xff00U) >> 8) : __swap16md (uh->uh_sport))) { |
| 2725 | case 53: /* DOMAIN */ |
| 2726 | case 67: /* BOOTPS */ |
| 2727 | case 68: /* BOOTPC */ |
| 2728 | case 123: /* NTP */ |
| 2729 | case 137: /* NETBIOS-NS */ |
| 2730 | case 520: /* RIP */ |
| 2731 | goto is_idle; |
| 2732 | } |
| 2733 | switch (ntohs(uh->uh_dport)(__uint16_t)(__builtin_constant_p(uh->uh_dport) ? (__uint16_t )(((__uint16_t)(uh->uh_dport) & 0xffU) << 8 | (( __uint16_t)(uh->uh_dport) & 0xff00U) >> 8) : __swap16md (uh->uh_dport))) { |
| 2734 | case 53: /* DOMAIN */ |
| 2735 | case 67: /* BOOTPS */ |
| 2736 | case 68: /* BOOTPC */ |
| 2737 | case 123: /* NTP */ |
| 2738 | case 137: /* NETBIOS-NS */ |
| 2739 | case 520: /* RIP */ |
| 2740 | goto is_idle; |
| 2741 | } |
| 2742 | goto is_active; |
| 2743 | default: |
| 2744 | goto is_active; |
| 2745 | } |
| 2746 | |
| 2747 | is_active: |
| 2748 | *ris_idle = 0; |
| 2749 | return (m0); |
| 2750 | |
| 2751 | is_idle: |
| 2752 | *ris_idle = 1; |
| 2753 | return (m0); |
| 2754 | |
| 2755 | error: |
| 2756 | return (NULL((void *)0)); |
| 2757 | } |
| 2758 | |
| 2759 | Static void |
| 2760 | pipex_session_log(struct pipex_session *session, int prio, const char *fmt, ...) |
| 2761 | { |
| 2762 | char logbuf[1024]; |
| 2763 | va_list ap; |
| 2764 | |
| 2765 | logpri(prio); |
| 2766 | if (session != NULL((void *)0)) { |
| 2767 | struct ifnet *ifp; |
| 2768 | |
| 2769 | ifp = if_get(session->ifindex); |
| 2770 | addlog("pipex: ppp=%d iface=%s protocol=%s id=%d ", |
| 2771 | session->ppp_id, |
| 2772 | ifp? ifp->if_xname : "Unknown", |
| 2773 | (session->protocol == PIPEX_PROTO_PPPOE3)? "PPPoE" : |
| 2774 | (session->protocol == PIPEX_PROTO_PPTP2)? "PPTP" : |
| 2775 | (session->protocol == PIPEX_PROTO_L2TP1) ? "L2TP" : |
| 2776 | "Unknown", session->session_id); |
| 2777 | if_put(ifp); |
| 2778 | } else |
| 2779 | addlog("pipex: "); |
| 2780 | |
| 2781 | va_start(ap, fmt)__builtin_va_start((ap), fmt); |
| 2782 | vsnprintf(logbuf, sizeof(logbuf), fmt, ap); |
| 2783 | va_end(ap)__builtin_va_end((ap)); |
| 2784 | addlog("%s\n", logbuf); |
| 2785 | } |
| 2786 | |
| 2787 | Static uint32_t |
| 2788 | pipex_sockaddr_hash_key(struct sockaddr *sa) |
| 2789 | { |
| 2790 | switch (sa->sa_family) { |
| 2791 | case AF_INET2: |
| 2792 | return ntohl(satosin(sa)->sin_addr.s_addr)(__uint32_t)(__builtin_constant_p(satosin(sa)->sin_addr.s_addr ) ? (__uint32_t)(((__uint32_t)(satosin(sa)->sin_addr.s_addr ) & 0xff) << 24 | ((__uint32_t)(satosin(sa)->sin_addr .s_addr) & 0xff00) << 8 | ((__uint32_t)(satosin(sa) ->sin_addr.s_addr) & 0xff0000) >> 8 | ((__uint32_t )(satosin(sa)->sin_addr.s_addr) & 0xff000000) >> 24) : __swap32md(satosin(sa)->sin_addr.s_addr)); |
| 2793 | case AF_INET624: |
| 2794 | return ntohl(satosin6(sa)->sin6_addr.s6_addr32[3])(__uint32_t)(__builtin_constant_p(satosin6(sa)->sin6_addr. __u6_addr.__u6_addr32[3]) ? (__uint32_t)(((__uint32_t)(satosin6 (sa)->sin6_addr.__u6_addr.__u6_addr32[3]) & 0xff) << 24 | ((__uint32_t)(satosin6(sa)->sin6_addr.__u6_addr.__u6_addr32 [3]) & 0xff00) << 8 | ((__uint32_t)(satosin6(sa)-> sin6_addr.__u6_addr.__u6_addr32[3]) & 0xff0000) >> 8 | ((__uint32_t)(satosin6(sa)->sin6_addr.__u6_addr.__u6_addr32 [3]) & 0xff000000) >> 24) : __swap32md(satosin6(sa) ->sin6_addr.__u6_addr.__u6_addr32[3])); |
| 2795 | } |
| 2796 | panic("pipex_sockaddr_hash_key: unknown address family"); |
| 2797 | return (0); |
| 2798 | } |
| 2799 | |
| 2800 | /* |
| 2801 | * Compare struct sockaddr_in{,6} with the address only. |
| 2802 | * The port number is not covered. |
| 2803 | */ |
| 2804 | Static int |
| 2805 | pipex_sockaddr_compar_addr(struct sockaddr *a, struct sockaddr *b) |
| 2806 | { |
| 2807 | int cmp; |
| 2808 | |
| 2809 | cmp = b->sa_family - a->sa_family; |
| 2810 | if (cmp != 0) |
| 2811 | return cmp; |
| 2812 | switch (a->sa_family) { |
| 2813 | case AF_INET2: |
| 2814 | return (satosin(b)->sin_addr.s_addr - |
| 2815 | satosin(a)->sin_addr.s_addr); |
| 2816 | case AF_INET624: |
| 2817 | cmp = (satosin6(b)->sin6_scope_id - satosin6(a)->sin6_scope_id); |
| 2818 | if (cmp != 0) |
| 2819 | return cmp; |
| 2820 | return (memcmp(&satosin6(a)->sin6_addr,__builtin_memcmp((&satosin6(a)->sin6_addr), (&satosin6 (b)->sin6_addr), (sizeof(struct in6_addr))) |
| 2821 | &satosin6(b)->sin6_addr,__builtin_memcmp((&satosin6(a)->sin6_addr), (&satosin6 (b)->sin6_addr), (sizeof(struct in6_addr))) |
| 2822 | sizeof(struct in6_addr))__builtin_memcmp((&satosin6(a)->sin6_addr), (&satosin6 (b)->sin6_addr), (sizeof(struct in6_addr)))); |
| 2823 | } |
| 2824 | panic("pipex_sockaddr_compar_addr: unknown address family"); |
| 2825 | |
| 2826 | return (-1); |
| 2827 | } |
| 2828 | |
| 2829 | int |
| 2830 | pipex_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, |
| 2831 | size_t newlen) |
| 2832 | { |
| 2833 | switch (name[0]) { |
| 2834 | case PIPEXCTL_ENABLE1: |
| 2835 | if (namelen != 1) |
| 2836 | return (ENOTDIR20); |
| 2837 | return (sysctl_int_bounded(oldp, oldlenp, newp, newlen, |
| 2838 | &pipex_enable, 0, 1)); |
| 2839 | default: |
| 2840 | return (ENOPROTOOPT42); |
| 2841 | } |
| 2842 | /* NOTREACHED */ |
| 2843 | } |