| File: | src/usr.sbin/npppd/npppd/../pppoe/pppoe_session.c |
| Warning: | line 111, column 6 Access to field 'state' results in a dereference of a null pointer (loaded from variable '_this') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: pppoe_session.c,v 1.12 2021/03/29 03:54:40 yasuoka 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 | /**@file | |||
| 30 | * Session management of PPPoE protocol | |||
| 31 | * $Id: pppoe_session.c,v 1.12 2021/03/29 03:54:40 yasuoka Exp $ | |||
| 32 | */ | |||
| 33 | ||||
| 34 | #include <sys/types.h> | |||
| 35 | #include <sys/socket.h> | |||
| 36 | #include <sys/uio.h> | |||
| 37 | #include <netinet/in.h> | |||
| 38 | #include <net/if.h> | |||
| 39 | #if defined(__NetBSD__) | |||
| 40 | #include <net/if_ether.h> | |||
| 41 | #else | |||
| 42 | #include <netinet/if_ether.h> | |||
| 43 | #endif | |||
| 44 | #include <net/if_dl.h> | |||
| 45 | #include <time.h> | |||
| 46 | #include <string.h> | |||
| 47 | #include <stdlib.h> | |||
| 48 | #include <stdio.h> | |||
| 49 | #include <event.h> | |||
| 50 | #include <syslog.h> | |||
| 51 | #include <stdarg.h> | |||
| 52 | ||||
| 53 | #include "hash.h" | |||
| 54 | #include "slist.h" | |||
| 55 | #include "debugutil.h" | |||
| 56 | #include "bytebuf.h" | |||
| 57 | #include "pppoe.h" | |||
| 58 | #include "pppoe_local.h" | |||
| 59 | ||||
| 60 | #include "npppd.h" | |||
| 61 | #include "ppp.h" | |||
| 62 | ||||
| 63 | #ifdef PPPOE_SESSION_DEBUG | |||
| 64 | #define PPPOE_SESSION_ASSERT(x) ASSERT(x)((void)0); | |||
| 65 | #define PPPOE_SESSION_DBG(x) pppoe_session_log x | |||
| 66 | #else | |||
| 67 | #define PPPOE_SESSION_ASSERT(x) | |||
| 68 | #define PPPOE_SESSION_DBG(x) | |||
| 69 | #endif | |||
| 70 | ||||
| 71 | #define pppoed_listener_this(sess)((pppoed_listener *)slist_get(&(sess)->pppoed->listener , (sess)->listener_index)) \ | |||
| 72 | ((pppoed_listener *)slist_get(&(sess)->pppoed->listener, \ | |||
| 73 | (sess)->listener_index)) | |||
| 74 | ||||
| 75 | static void pppoe_session_log (pppoe_session *, int, const char *, ...) __printflike(3,4)__attribute__((__format__ (__printf__, 3, 4))); | |||
| 76 | static int pppoe_session_send_PADS (pppoe_session *, struct pppoe_tlv *, | |||
| 77 | struct pppoe_tlv *); | |||
| 78 | static int pppoe_session_send_PADT (pppoe_session *); | |||
| 79 | static int pppoe_session_ppp_output (npppd_ppp *, u_char *, int, int); | |||
| 80 | static void pppoe_session_close_by_ppp(npppd_ppp *); | |||
| 81 | static int pppoe_session_bind_ppp (pppoe_session *); | |||
| 82 | static void pppoe_session_dispose_event(int, short, void *); | |||
| 83 | ||||
| 84 | /* Initialize PPPoE session context */ | |||
| 85 | int | |||
| 86 | pppoe_session_init(pppoe_session *_this, pppoed *_pppoed, int idx, | |||
| 87 | int session_id, u_char *ether_addr) | |||
| 88 | { | |||
| 89 | memset(_this, 0, sizeof(pppoe_session)); | |||
| 90 | ||||
| 91 | _this->pppoed = _pppoed; | |||
| 92 | _this->session_id = session_id; | |||
| 93 | _this->listener_index = idx; | |||
| 94 | memcpy(_this->ether_addr, ether_addr, ETHER_ADDR_LEN6); | |||
| 95 | ||||
| 96 | memcpy(_this->ehdr.ether_dhost, ether_addr, ETHER_ADDR_LEN6); | |||
| 97 | memcpy(_this->ehdr.ether_shost, pppoe_session_sock_ether_addr(_this)((pppoed_listener *)slist_get(&(_this)->pppoed->listener , (_this)->listener_index))->ether_addr, | |||
| 98 | ETHER_ADDR_LEN6); | |||
| 99 | ||||
| 100 | evtimer_set(&_this->ev_disposing, pppoe_session_dispose_event, _this)event_set(&_this->ev_disposing, -1, 0, pppoe_session_dispose_event , _this); | |||
| 101 | ||||
| 102 | return 0; | |||
| 103 | } | |||
| 104 | ||||
| 105 | /* Disconnect PPPoE session */ | |||
| 106 | void | |||
| 107 | pppoe_session_disconnect(pppoe_session *_this) | |||
| 108 | { | |||
| 109 | struct timeval tv; | |||
| 110 | ||||
| 111 | if (_this->state != PPPOE_SESSION_STATE_DISPOSING2) { | |||
| ||||
| 112 | pppoe_session_send_PADT(_this); | |||
| 113 | ||||
| 114 | /* free process should be par event */ | |||
| 115 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; | |||
| 116 | evtimer_add(&_this->ev_disposing, &tv)event_add(&_this->ev_disposing, &tv); | |||
| 117 | _this->state = PPPOE_SESSION_STATE_DISPOSING2; | |||
| 118 | } | |||
| 119 | if (_this->ppp != NULL((void *)0)) | |||
| 120 | ppp_phy_downed(_this->ppp); | |||
| 121 | } | |||
| 122 | ||||
| 123 | /* Stop PPPoE session */ | |||
| 124 | void | |||
| 125 | pppoe_session_stop(pppoe_session *_this) | |||
| 126 | { | |||
| 127 | if (_this->state != PPPOE_SESSION_STATE_DISPOSING2) | |||
| 128 | pppoe_session_disconnect(_this); | |||
| 129 | ||||
| 130 | } | |||
| 131 | ||||
| 132 | /* Finish PPPoE session */ | |||
| 133 | void | |||
| 134 | pppoe_session_fini(pppoe_session *_this) | |||
| 135 | { | |||
| 136 | evtimer_del(&_this->ev_disposing)event_del(&_this->ev_disposing); | |||
| 137 | } | |||
| 138 | ||||
| 139 | /* call back function from event(3) */ | |||
| 140 | static void | |||
| 141 | pppoe_session_dispose_event(int fd, short ev, void *ctx) | |||
| 142 | { | |||
| 143 | pppoe_session *_this; | |||
| 144 | ||||
| 145 | _this = ctx; | |||
| 146 | pppoed_pppoe_session_close_notify(_this->pppoed, _this); | |||
| 147 | } | |||
| 148 | ||||
| 149 | /* | |||
| 150 | * I/O | |||
| 151 | */ | |||
| 152 | void | |||
| 153 | pppoe_session_input(pppoe_session *_this, u_char *pkt, int lpkt) | |||
| 154 | { | |||
| 155 | int rval; | |||
| 156 | npppd_ppp *ppp; | |||
| 157 | ||||
| 158 | ppp = _this->ppp; | |||
| 159 | if (_this->ppp == NULL((void *)0)) | |||
| 160 | return; | |||
| 161 | ||||
| 162 | if (_this->state != PPPOE_SESSION_STATE_RUNNING1) | |||
| 163 | return; | |||
| 164 | ||||
| 165 | rval = ppp->recv_packet(ppp, pkt, lpkt, 0); | |||
| 166 | if (_this->ppp == NULL((void *)0)) /* ppp is freed */ | |||
| 167 | return; | |||
| 168 | ||||
| 169 | if (rval == 2) { | |||
| 170 | /* | |||
| 171 | * Quit this function before statistics counter | |||
| 172 | * is processed when the packet will be processed by | |||
| 173 | * PIPEX. Because current NPPPD PPPOE implementation | |||
| 174 | * is receiving all packet from BPF even though the | |||
| 175 | * PIPEX will process it. | |||
| 176 | */ | |||
| 177 | } else if (rval != 0) { | |||
| 178 | ppp->ierrors++; | |||
| 179 | } else { | |||
| 180 | ppp->ipackets++; | |||
| 181 | ppp->ibytes += lpkt; | |||
| 182 | } | |||
| 183 | ||||
| 184 | return; | |||
| 185 | } | |||
| 186 | ||||
| 187 | static int | |||
| 188 | pppoe_session_output(pppoe_session *_this, int is_disc, u_char *pkt, | |||
| 189 | int lpkt) | |||
| 190 | { | |||
| 191 | int sz, niov, tlen; | |||
| 192 | struct iovec iov[4]; | |||
| 193 | struct pppoe_header pppoe0, *pppoe; | |||
| 194 | char pad[ETHERMIN(64 - ((6 * 2) + 2) - 4)]; | |||
| 195 | ||||
| 196 | ||||
| 197 | niov = 0; | |||
| 198 | tlen = 0; | |||
| 199 | iov[niov].iov_base = &_this->ehdr; | |||
| 200 | iov[niov++].iov_len = sizeof(_this->ehdr); | |||
| 201 | ||||
| 202 | if (is_disc) { | |||
| 203 | _this->ehdr.ether_type = htons(ETHERTYPE_PPPOEDISC)(__uint16_t)(__builtin_constant_p(0x8863) ? (__uint16_t)(((__uint16_t )(0x8863) & 0xffU) << 8 | ((__uint16_t)(0x8863) & 0xff00U) >> 8) : __swap16md(0x8863)); | |||
| 204 | iov[niov].iov_base = pkt; | |||
| 205 | iov[niov++].iov_len = lpkt; | |||
| 206 | pppoe = (struct pppoe_header *)pkt; | |||
| 207 | pppoe->length = htons(lpkt - sizeof(pppoe0))(__uint16_t)(__builtin_constant_p(lpkt - sizeof(pppoe0)) ? (__uint16_t )(((__uint16_t)(lpkt - sizeof(pppoe0)) & 0xffU) << 8 | ((__uint16_t)(lpkt - sizeof(pppoe0)) & 0xff00U) >> 8) : __swap16md(lpkt - sizeof(pppoe0))); | |||
| 208 | tlen += lpkt; | |||
| 209 | } else { | |||
| 210 | _this->ehdr.ether_type = htons(ETHERTYPE_PPPOE)(__uint16_t)(__builtin_constant_p(0x8864) ? (__uint16_t)(((__uint16_t )(0x8864) & 0xffU) << 8 | ((__uint16_t)(0x8864) & 0xff00U) >> 8) : __swap16md(0x8864)); | |||
| 211 | pppoe0.ver = PPPOE_RFC2516_VER0x01; | |||
| 212 | pppoe0.type = PPPOE_RFC2516_TYPE0x01; | |||
| 213 | pppoe0.code = 0; | |||
| 214 | pppoe0.session_id = htons(_this->session_id)(__uint16_t)(__builtin_constant_p(_this->session_id) ? (__uint16_t )(((__uint16_t)(_this->session_id) & 0xffU) << 8 | ((__uint16_t)(_this->session_id) & 0xff00U) >> 8) : __swap16md(_this->session_id)); | |||
| 215 | pppoe0.length = htons(lpkt)(__uint16_t)(__builtin_constant_p(lpkt) ? (__uint16_t)(((__uint16_t )(lpkt) & 0xffU) << 8 | ((__uint16_t)(lpkt) & 0xff00U ) >> 8) : __swap16md(lpkt)); | |||
| 216 | iov[niov].iov_base = &pppoe0; | |||
| 217 | iov[niov++].iov_len = sizeof(pppoe0); | |||
| 218 | tlen += sizeof(pppoe0); | |||
| 219 | iov[niov].iov_base = pkt; | |||
| 220 | iov[niov++].iov_len = lpkt; | |||
| 221 | tlen += lpkt; | |||
| 222 | } | |||
| 223 | if (tlen < ETHERMIN(64 - ((6 * 2) + 2) - 4)) { | |||
| 224 | memset(pad, 0, ETHERMIN(64 - ((6 * 2) + 2) - 4) - tlen); | |||
| 225 | iov[niov].iov_base = pad; | |||
| 226 | iov[niov++].iov_len = ETHERMIN(64 - ((6 * 2) + 2) - 4) - tlen; | |||
| 227 | } | |||
| 228 | ||||
| 229 | sz = writev(pppoe_session_sock_bpf(_this)((pppoed_listener *)slist_get(&(_this)->pppoed->listener , (_this)->listener_index))->bpf, iov, niov); | |||
| 230 | ||||
| 231 | return (sz > 0)? 0 : -1; | |||
| 232 | } | |||
| 233 | ||||
| 234 | static int | |||
| 235 | pppoe_session_send_PADT(pppoe_session *_this) | |||
| 236 | { | |||
| 237 | u_char bufspace[2048]; | |||
| 238 | bytebuffer *buf; | |||
| 239 | struct pppoe_header pppoe; | |||
| 240 | int rval = 0; | |||
| 241 | struct pppoe_tlv tlv; | |||
| 242 | ||||
| 243 | if ((buf = bytebuffer_wrap(bufspace, sizeof(bufspace))) == NULL((void *)0)) { | |||
| 244 | pppoe_session_log(_this, LOG_ERR3, | |||
| 245 | "bytebuffer_wrap() failed on %s(): %m", __func__); | |||
| 246 | return -1; | |||
| 247 | } | |||
| 248 | bytebuffer_clear(buf); | |||
| 249 | ||||
| 250 | /* | |||
| 251 | * PPPoE Header | |||
| 252 | */ | |||
| 253 | memset(&pppoe, 0, sizeof(pppoe)); | |||
| 254 | pppoe.ver = PPPOE_RFC2516_VER0x01; | |||
| 255 | pppoe.type = PPPOE_RFC2516_TYPE0x01; | |||
| 256 | pppoe.code = PPPOE_CODE_PADT0xa7; | |||
| 257 | pppoe.session_id = htons(_this->session_id)(__uint16_t)(__builtin_constant_p(_this->session_id) ? (__uint16_t )(((__uint16_t)(_this->session_id) & 0xffU) << 8 | ((__uint16_t)(_this->session_id) & 0xff00U) >> 8) : __swap16md(_this->session_id)); | |||
| 258 | bytebuffer_put(buf, &pppoe, sizeof(pppoe)); | |||
| 259 | ||||
| 260 | /* | |||
| 261 | * Tag - End-of-List | |||
| 262 | */ | |||
| 263 | tlv.type = htons(PPPOE_TAG_END_OF_LIST)(__uint16_t)(__builtin_constant_p(0x0000) ? (__uint16_t)(((__uint16_t )(0x0000) & 0xffU) << 8 | ((__uint16_t)(0x0000) & 0xff00U) >> 8) : __swap16md(0x0000)); | |||
| 264 | tlv.length = 0; | |||
| 265 | bytebuffer_put(buf, &tlv, sizeof(tlv)); | |||
| 266 | tlv.type = htons(PPPOE_TAG_END_OF_LIST)(__uint16_t)(__builtin_constant_p(0x0000) ? (__uint16_t)(((__uint16_t )(0x0000) & 0xffU) << 8 | ((__uint16_t)(0x0000) & 0xff00U) >> 8) : __swap16md(0x0000)); | |||
| 267 | tlv.length = 0; | |||
| 268 | bytebuffer_put(buf, &tlv, sizeof(tlv)); | |||
| 269 | ||||
| 270 | bytebuffer_flip(buf); | |||
| 271 | if (pppoe_session_output(_this, 1, bytebuffer_pointer(buf), | |||
| 272 | bytebuffer_remaining(buf)) != 0) { | |||
| 273 | pppoe_session_log(_this, LOG_ERR3, "pppoed_output failed: %m"); | |||
| 274 | rval = 1; | |||
| 275 | } | |||
| 276 | pppoe_session_log(_this, LOG_INFO6, "SendPADT"); | |||
| 277 | ||||
| 278 | bytebuffer_unwrap(buf); | |||
| 279 | bytebuffer_destroy(buf); | |||
| 280 | ||||
| 281 | return rval; | |||
| 282 | } | |||
| 283 | ||||
| 284 | /* send PADS */ | |||
| 285 | static int | |||
| 286 | pppoe_session_send_PADS(pppoe_session *_this, struct pppoe_tlv *hostuniq, | |||
| 287 | struct pppoe_tlv *service_name) | |||
| 288 | { | |||
| 289 | int rval, len; | |||
| 290 | u_char bufspace[2048], msgbuf[80]; | |||
| 291 | bytebuffer *buf; | |||
| 292 | struct pppoe_header pppoe; | |||
| 293 | struct pppoe_tlv tlv; | |||
| 294 | ||||
| 295 | if ((buf = bytebuffer_wrap(bufspace, sizeof(bufspace))) == NULL((void *)0)) { | |||
| 296 | pppoe_session_log(_this, LOG_ERR3, | |||
| 297 | "bytebuffer_wrap() failed on %s(): %m", __func__); | |||
| 298 | return -1; | |||
| 299 | } | |||
| 300 | bytebuffer_clear(buf); | |||
| 301 | ||||
| 302 | /* | |||
| 303 | * PPPoE Header | |||
| 304 | */ | |||
| 305 | memset(&pppoe, 0, sizeof(pppoe)); | |||
| 306 | pppoe.ver = PPPOE_RFC2516_VER0x01; | |||
| 307 | pppoe.type = PPPOE_RFC2516_TYPE0x01; | |||
| 308 | pppoe.code = PPPOE_CODE_PADS0x65; | |||
| 309 | pppoe.session_id = htons(_this->session_id)(__uint16_t)(__builtin_constant_p(_this->session_id) ? (__uint16_t )(((__uint16_t)(_this->session_id) & 0xffU) << 8 | ((__uint16_t)(_this->session_id) & 0xff00U) >> 8) : __swap16md(_this->session_id)); | |||
| 310 | bytebuffer_put(buf, &pppoe, sizeof(pppoe)); | |||
| 311 | ||||
| 312 | /* | |||
| 313 | * Tag - Service-Name | |||
| 314 | */ | |||
| 315 | msgbuf[0] = '\0'; | |||
| 316 | if (service_name != NULL((void *)0)) { | |||
| 317 | tlv.type = htons(PPPOE_TAG_SERVICE_NAME)(__uint16_t)(__builtin_constant_p(0x0101) ? (__uint16_t)(((__uint16_t )(0x0101) & 0xffU) << 8 | ((__uint16_t)(0x0101) & 0xff00U) >> 8) : __swap16md(0x0101)); | |||
| 318 | tlv.length = htons(service_name->length)(__uint16_t)(__builtin_constant_p(service_name->length) ? ( __uint16_t)(((__uint16_t)(service_name->length) & 0xffU ) << 8 | ((__uint16_t)(service_name->length) & 0xff00U ) >> 8) : __swap16md(service_name->length)); | |||
| 319 | bytebuffer_put(buf, &tlv, sizeof(tlv)); | |||
| 320 | ||||
| 321 | len = service_name->length; | |||
| 322 | if (len > 0) { | |||
| 323 | bytebuffer_put(buf, service_name->value, len); | |||
| 324 | strlcpy(msgbuf, service_name->value, | |||
| 325 | MINIMUM(len + 1, sizeof(msgbuf))(((len + 1) < (sizeof(msgbuf))) ? (len + 1) : (sizeof(msgbuf )))); | |||
| 326 | } | |||
| 327 | } | |||
| 328 | ||||
| 329 | /* | |||
| 330 | * Tag - Host-Uniq | |||
| 331 | */ | |||
| 332 | if (hostuniq != NULL((void *)0)) { | |||
| 333 | tlv.type = htons(PPPOE_TAG_HOST_UNIQ)(__uint16_t)(__builtin_constant_p(0x0103) ? (__uint16_t)(((__uint16_t )(0x0103) & 0xffU) << 8 | ((__uint16_t)(0x0103) & 0xff00U) >> 8) : __swap16md(0x0103)); | |||
| 334 | tlv.length = htons(hostuniq->length)(__uint16_t)(__builtin_constant_p(hostuniq->length) ? (__uint16_t )(((__uint16_t)(hostuniq->length) & 0xffU) << 8 | ((__uint16_t)(hostuniq->length) & 0xff00U) >> 8 ) : __swap16md(hostuniq->length)); | |||
| 335 | bytebuffer_put(buf, &tlv, sizeof(tlv)); | |||
| 336 | bytebuffer_put(buf, hostuniq->value, hostuniq->length); | |||
| 337 | } | |||
| 338 | tlv.type = htons(PPPOE_TAG_END_OF_LIST)(__uint16_t)(__builtin_constant_p(0x0000) ? (__uint16_t)(((__uint16_t )(0x0000) & 0xffU) << 8 | ((__uint16_t)(0x0000) & 0xff00U) >> 8) : __swap16md(0x0000)); | |||
| 339 | tlv.length = 0; | |||
| 340 | bytebuffer_put(buf, &tlv, sizeof(tlv)); | |||
| 341 | ||||
| 342 | bytebuffer_flip(buf); | |||
| 343 | rval = 0; | |||
| 344 | if (pppoe_session_output(_this, 1, bytebuffer_pointer(buf), | |||
| 345 | bytebuffer_remaining(buf)) != 0) { | |||
| 346 | pppoe_session_log(_this, LOG_ERR3, "pppoed_output failed: %m"); | |||
| 347 | rval = 1; | |||
| 348 | } | |||
| 349 | pppoe_session_log(_this, LOG_INFO6, "SendPADS serviceName=%s " | |||
| 350 | "hostUniq=%s", msgbuf, | |||
| 351 | hostuniq? pppoed_tlv_value_string(hostuniq) : "none"); | |||
| 352 | ||||
| 353 | bytebuffer_unwrap(buf); | |||
| 354 | bytebuffer_destroy(buf); | |||
| 355 | ||||
| 356 | return rval; | |||
| 357 | } | |||
| 358 | ||||
| 359 | /* process PADR from the peer */ | |||
| 360 | int | |||
| 361 | pppoe_session_recv_PADR(pppoe_session *_this, slist *tag_list) | |||
| 362 | { | |||
| 363 | pppoed *pppoed0 = _this->pppoed; | |||
| 364 | struct pppoe_tlv *tlv, *hostuniq, *service_name, *ac_cookie; | |||
| 365 | ||||
| 366 | service_name = NULL((void *)0); | |||
| 367 | hostuniq = NULL((void *)0); | |||
| 368 | ac_cookie = NULL((void *)0); | |||
| 369 | for (slist_itr_first(tag_list); slist_itr_has_next(tag_list); ) { | |||
| 370 | tlv = slist_itr_next(tag_list); | |||
| 371 | if (tlv->type == PPPOE_TAG_HOST_UNIQ0x0103) | |||
| 372 | hostuniq = tlv; | |||
| 373 | if (tlv->type == PPPOE_TAG_SERVICE_NAME0x0101) | |||
| 374 | service_name = tlv; | |||
| 375 | if (tlv->type == PPPOE_TAG_AC_COOKIE0x0104) | |||
| 376 | ac_cookie = tlv; | |||
| 377 | } | |||
| 378 | ||||
| 379 | if (ac_cookie) { | |||
| 380 | /* avoid a session which has already has cookie. */ | |||
| 381 | if (hash_lookup(pppoed0->acookie_hash, | |||
| 382 | (void *)ac_cookie->value) != NULL((void *)0)) | |||
| 383 | goto fail; | |||
| 384 | ||||
| 385 | _this->acookie = *(uint32_t *)(ac_cookie->value); | |||
| 386 | hash_insert(pppoed0->acookie_hash, | |||
| 387 | (void *)(intptr_t)_this->acookie, _this); | |||
| 388 | } | |||
| 389 | ||||
| 390 | if (pppoe_session_send_PADS(_this, hostuniq, service_name) != 0) | |||
| 391 | goto fail; | |||
| 392 | ||||
| 393 | if (pppoe_session_bind_ppp(_this) != 0) | |||
| 394 | goto fail; | |||
| 395 | ||||
| 396 | _this->state = PPPOE_SESSION_STATE_RUNNING1; | |||
| 397 | return 0; | |||
| 398 | fail: | |||
| 399 | return -1; | |||
| 400 | } | |||
| 401 | ||||
| 402 | /* process PADT from the peer */ | |||
| 403 | int | |||
| 404 | pppoe_session_recv_PADT(pppoe_session *_this, slist *tag_list) | |||
| 405 | { | |||
| 406 | pppoe_session_log(_this, LOG_INFO6, "RecvPADT"); | |||
| 407 | ||||
| 408 | pppoe_session_stop(_this); | |||
| 409 | _this->state = PPPOE_SESSION_STATE_DISPOSING2; | |||
| 410 | ||||
| 411 | return 0; | |||
| 412 | } | |||
| 413 | ||||
| 414 | /* | |||
| 415 | * Log | |||
| 416 | */ | |||
| 417 | static void | |||
| 418 | pppoe_session_log(pppoe_session *_this, int prio, const char *fmt, ...) | |||
| 419 | { | |||
| 420 | char logbuf[BUFSIZ1024]; | |||
| 421 | va_list ap; | |||
| 422 | ||||
| 423 | PPPOE_SESSION_ASSERT(_this != NULL); | |||
| 424 | va_start(ap, fmt)__builtin_va_start((ap), fmt); | |||
| 425 | #ifdef PPPOED_MULTIPLE | |||
| 426 | snprintf(logbuf, sizeof(logbuf), "pppoed id=%u session=%d %s", | |||
| 427 | _this->pppoed->id, _this->session_id, fmt); | |||
| 428 | #else | |||
| 429 | snprintf(logbuf, sizeof(logbuf), "pppoed if=%s session=%d %s", | |||
| 430 | pppoe_session_listen_ifname(_this)((pppoed_listener *)slist_get(&(_this)->pppoed->listener , (_this)->listener_index))->listen_ifname, _this->session_id, fmt); | |||
| 431 | #endif | |||
| 432 | vlog_printf(prio, logbuf, ap); | |||
| 433 | va_end(ap)__builtin_va_end((ap)); | |||
| 434 | } | |||
| 435 | ||||
| 436 | /* | |||
| 437 | * PPP | |||
| 438 | */ | |||
| 439 | static int | |||
| 440 | pppoe_session_ppp_output(npppd_ppp *ppp, u_char *pkt, int lpkt, int flag) | |||
| 441 | { | |||
| 442 | int rval; | |||
| 443 | pppoe_session *_this; | |||
| 444 | ||||
| 445 | _this = ppp->phy_context; | |||
| 446 | ||||
| 447 | rval = pppoe_session_output(_this, 0, pkt, lpkt); | |||
| 448 | ||||
| 449 | if (_this->ppp == NULL((void *)0)) /* ppp is freed */ | |||
| 450 | return 0; | |||
| 451 | ||||
| 452 | if (rval != 0) { | |||
| 453 | ppp->oerrors++; | |||
| 454 | } else { | |||
| 455 | ppp->opackets++; | |||
| 456 | ppp->obytes += lpkt; | |||
| 457 | } | |||
| 458 | ||||
| 459 | return 0; | |||
| 460 | } | |||
| 461 | ||||
| 462 | static void | |||
| 463 | pppoe_session_close_by_ppp(npppd_ppp *ppp) | |||
| 464 | { | |||
| 465 | pppoe_session *_this; | |||
| 466 | ||||
| 467 | _this = ppp->phy_context; | |||
| ||||
| 468 | PPPOE_SESSION_ASSERT(_this != NULL); | |||
| 469 | if (_this != NULL((void *)0)) | |||
| 470 | /* do this before pptp_call_disconnect() */ | |||
| 471 | _this->ppp = NULL((void *)0); | |||
| 472 | ||||
| 473 | pppoe_session_disconnect(_this); | |||
| 474 | } | |||
| 475 | ||||
| 476 | /* bind for PPP */ | |||
| 477 | static int | |||
| 478 | pppoe_session_bind_ppp(pppoe_session *_this) | |||
| 479 | { | |||
| 480 | int len; | |||
| 481 | npppd_ppp *ppp; | |||
| 482 | struct sockaddr_dl sdl; | |||
| 483 | ||||
| 484 | ppp = NULL((void *)0); | |||
| 485 | if ((ppp = ppp_create()) == NULL((void *)0)) | |||
| 486 | goto fail; | |||
| 487 | ||||
| 488 | PPPOE_SESSION_ASSERT(_this->ppp == NULL); | |||
| 489 | ||||
| 490 | if (_this->ppp != NULL((void *)0)) | |||
| 491 | return -1; | |||
| 492 | ||||
| 493 | _this->ppp = ppp; | |||
| 494 | ||||
| 495 | ppp->tunnel_type = NPPPD_TUNNEL_PPPOE3; | |||
| 496 | ppp->tunnel_session_id = _this->session_id; | |||
| 497 | ppp->phy_context = _this; | |||
| 498 | ppp->send_packet = pppoe_session_ppp_output; | |||
| 499 | ppp->phy_close = pppoe_session_close_by_ppp; | |||
| 500 | ||||
| 501 | strlcpy(ppp->phy_label, PPPOE_SESSION_LISTENER_TUN_NAME(_this)((pppoed_listener *)slist_get(&(_this)->pppoed->listener , (_this)->listener_index))->tun_name, | |||
| 502 | sizeof(ppp->phy_label)); | |||
| 503 | ||||
| 504 | memset(&sdl, 0, sizeof(sdl)); | |||
| 505 | sdl.sdl_len = sizeof(sdl); | |||
| 506 | sdl.sdl_family = AF_LINK18; | |||
| 507 | sdl.sdl_index = if_nametoindex(pppoe_session_listen_ifname(_this)((pppoed_listener *)slist_get(&(_this)->pppoed->listener , (_this)->listener_index))->listen_ifname); | |||
| 508 | len = strlen(pppoe_session_listen_ifname(_this)((pppoed_listener *)slist_get(&(_this)->pppoed->listener , (_this)->listener_index))->listen_ifname); | |||
| 509 | memcpy(sdl.sdl_data, pppoe_session_listen_ifname(_this)((pppoed_listener *)slist_get(&(_this)->pppoed->listener , (_this)->listener_index))->listen_ifname, len); | |||
| 510 | sdl.sdl_nlen = len; | |||
| 511 | sdl.sdl_alen = ETHER_ADDR_LEN6; | |||
| 512 | memcpy(sdl.sdl_data + len, _this->ether_addr, ETHER_ADDR_LEN6); | |||
| 513 | ||||
| 514 | memcpy(&ppp->phy_info.peer_dl, &sdl, sizeof(sdl)); | |||
| 515 | ||||
| 516 | if (ppp_init(npppd_get_npppd(), ppp) != 0) | |||
| 517 | goto fail; | |||
| 518 | ppp->has_acf = 0; | |||
| 519 | ||||
| 520 | ||||
| 521 | pppoe_session_log(_this, LOG_NOTICE5, "logtype=PPPBind ppp=%d", ppp->id); | |||
| 522 | ppp_start(ppp); | |||
| 523 | ||||
| 524 | return 0; | |||
| 525 | fail: | |||
| 526 | pppoe_session_log(_this, LOG_ERR3, "failed binding ppp"); | |||
| 527 | ||||
| 528 | if (ppp != NULL((void *)0)) | |||
| 529 | ppp_destroy(ppp); | |||
| 530 | _this->ppp = NULL((void *)0); | |||
| 531 | ||||
| 532 | return 1; | |||
| 533 | } |