if_pppx.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104
  1. /* $OpenBSD: if_pppx.c,v 1.42 2015/07/18 15:51:16 mpi Exp $ */
  2. /*
  3. * Copyright (c) 2010 Claudio Jeker <claudio@openbsd.org>
  4. * Copyright (c) 2010 David Gwynne <dlg@openbsd.org>
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. /*-
  19. * Copyright (c) 2009 Internet Initiative Japan Inc.
  20. * All rights reserved.
  21. *
  22. * Redistribution and use in source and binary forms, with or without
  23. * modification, are permitted provided that the following conditions
  24. * are met:
  25. * 1. Redistributions of source code must retain the above copyright
  26. * notice, this list of conditions and the following disclaimer.
  27. * 2. Redistributions in binary form must reproduce the above copyright
  28. * notice, this list of conditions and the following disclaimer in the
  29. * documentation and/or other materials provided with the distribution.
  30. *
  31. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  32. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  34. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  35. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  36. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  37. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  39. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  40. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  41. * SUCH DAMAGE.
  42. */
  43. #include <sys/param.h>
  44. #include <sys/systm.h>
  45. #include <sys/buf.h>
  46. #include <sys/kernel.h>
  47. #include <sys/malloc.h>
  48. #include <sys/device.h>
  49. #include <sys/conf.h>
  50. #include <sys/queue.h>
  51. #include <sys/rwlock.h>
  52. #include <sys/pool.h>
  53. #include <sys/mbuf.h>
  54. #include <sys/errno.h>
  55. #include <sys/protosw.h>
  56. #include <sys/socket.h>
  57. #include <sys/ioctl.h>
  58. #include <sys/vnode.h>
  59. #include <sys/poll.h>
  60. #include <sys/selinfo.h>
  61. #include <net/if.h>
  62. #include <net/if_types.h>
  63. #include <net/netisr.h>
  64. #include <netinet/in.h>
  65. #include <netinet/if_ether.h>
  66. #include <net/if_dl.h>
  67. #include <netinet/in_var.h>
  68. #include <netinet/ip.h>
  69. #include <netinet/ip_var.h>
  70. #ifdef INET6
  71. #include <netinet6/in6_var.h>
  72. #include <netinet/ip6.h>
  73. #include <netinet6/nd6.h>
  74. #endif /* INET6 */
  75. #include "bpfilter.h"
  76. #if NBPFILTER > 0
  77. #include <net/bpf.h>
  78. #endif
  79. #include <net/ppp_defs.h>
  80. #include <net/ppp-comp.h>
  81. #include <crypto/arc4.h>
  82. #ifdef PIPEX
  83. #include <net/radix.h>
  84. #include <net/pipex.h>
  85. #include <net/pipex_local.h>
  86. #else
  87. #error PIPEX option not enabled
  88. #endif
  89. #ifdef PPPX_DEBUG
  90. #define PPPX_D_INIT (1<<0)
  91. int pppxdebug = 0;
  92. #define DPRINTF(_m, _p...) do { \
  93. if (ISSET(pppxdebug, (_m))) \
  94. printf(_p); \
  95. } while (0)
  96. #else
  97. #define DPRINTF(_m, _p...) /* _m, _p */
  98. #endif
  99. struct pppx_if;
  100. struct pppx_dev {
  101. LIST_ENTRY(pppx_dev) pxd_entry;
  102. int pxd_unit;
  103. /* kq shizz */
  104. struct selinfo pxd_rsel;
  105. struct mutex pxd_rsel_mtx;
  106. struct selinfo pxd_wsel;
  107. struct mutex pxd_wsel_mtx;
  108. /* queue of packets for userland to service - protected by splnet */
  109. struct ifqueue pxd_svcq;
  110. int pxd_waiting;
  111. LIST_HEAD(,pppx_if) pxd_pxis;
  112. };
  113. struct rwlock pppx_devs_lk = RWLOCK_INITIALIZER("pppxdevs");
  114. LIST_HEAD(, pppx_dev) pppx_devs = LIST_HEAD_INITIALIZER(pppx_devs);
  115. struct pool *pppx_if_pl;
  116. struct pppx_dev *pppx_dev_lookup(dev_t);
  117. struct pppx_dev *pppx_dev2pxd(dev_t);
  118. struct pppx_if_key {
  119. int pxik_session_id;
  120. int pxik_protocol;
  121. };
  122. int pppx_if_cmp(struct pppx_if *, struct pppx_if *);
  123. struct pppx_if {
  124. struct pppx_if_key pxi_key; /* must be first in the struct */
  125. RB_ENTRY(pppx_if) pxi_entry;
  126. LIST_ENTRY(pppx_if) pxi_list;
  127. int pxi_unit;
  128. struct ifnet pxi_if;
  129. struct pipex_session pxi_session;
  130. struct pipex_iface_context pxi_ifcontext;
  131. };
  132. struct rwlock pppx_ifs_lk = RWLOCK_INITIALIZER("pppxifs");
  133. RB_HEAD(pppx_ifs, pppx_if) pppx_ifs = RB_INITIALIZER(&pppx_ifs);
  134. RB_PROTOTYPE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);
  135. int pppx_if_next_unit(void);
  136. struct pppx_if *pppx_if_find(struct pppx_dev *, int, int);
  137. int pppx_add_session(struct pppx_dev *,
  138. struct pipex_session_req *);
  139. int pppx_del_session(struct pppx_dev *,
  140. struct pipex_session_close_req *);
  141. int pppx_set_session_descr(struct pppx_dev *,
  142. struct pipex_session_descr_req *);
  143. void pppx_if_destroy(struct pppx_dev *, struct pppx_if *);
  144. void pppx_if_start(struct ifnet *);
  145. int pppx_if_output(struct ifnet *, struct mbuf *,
  146. struct sockaddr *, struct rtentry *);
  147. int pppx_if_ioctl(struct ifnet *, u_long, caddr_t);
  148. void pppxattach(int);
  149. void filt_pppx_rdetach(struct knote *);
  150. int filt_pppx_read(struct knote *, long);
  151. struct filterops pppx_rd_filtops = {
  152. 1,
  153. NULL,
  154. filt_pppx_rdetach,
  155. filt_pppx_read
  156. };
  157. void filt_pppx_wdetach(struct knote *);
  158. int filt_pppx_write(struct knote *, long);
  159. struct filterops pppx_wr_filtops = {
  160. 1,
  161. NULL,
  162. filt_pppx_wdetach,
  163. filt_pppx_write
  164. };
  165. struct pppx_dev *
  166. pppx_dev_lookup(dev_t dev)
  167. {
  168. struct pppx_dev *pxd;
  169. int unit = minor(dev);
  170. /* must hold pppx_devs_lk */
  171. LIST_FOREACH(pxd, &pppx_devs, pxd_entry) {
  172. if (pxd->pxd_unit == unit)
  173. return (pxd);
  174. }
  175. return (NULL);
  176. }
  177. struct pppx_dev *
  178. pppx_dev2pxd(dev_t dev)
  179. {
  180. struct pppx_dev *pxd;
  181. rw_enter_read(&pppx_devs_lk);
  182. pxd = pppx_dev_lookup(dev);
  183. rw_exit_read(&pppx_devs_lk);
  184. return (pxd);
  185. }
  186. void
  187. pppxattach(int n)
  188. {
  189. pipex_init();
  190. }
  191. int
  192. pppxopen(dev_t dev, int flags, int mode, struct proc *p)
  193. {
  194. struct pppx_dev *pxd;
  195. int rv = 0;
  196. rv = rw_enter(&pppx_devs_lk, RW_WRITE | RW_INTR);
  197. if (rv != 0)
  198. return (rv);
  199. pxd = pppx_dev_lookup(dev);
  200. if (pxd != NULL) {
  201. rv = EBUSY;
  202. goto out;
  203. }
  204. if (LIST_EMPTY(&pppx_devs) && pppx_if_pl == NULL) {
  205. pppx_if_pl = malloc(sizeof(*pppx_if_pl), M_DEVBUF, M_WAITOK);
  206. pool_init(pppx_if_pl, sizeof(struct pppx_if), 0, 0, 0,
  207. "pppxif", &pool_allocator_nointr);
  208. }
  209. pxd = malloc(sizeof(*pxd), M_DEVBUF, M_WAITOK | M_ZERO);
  210. pxd->pxd_unit = minor(dev);
  211. mtx_init(&pxd->pxd_rsel_mtx, IPL_NET);
  212. mtx_init(&pxd->pxd_wsel_mtx, IPL_NET);
  213. LIST_INIT(&pxd->pxd_pxis);
  214. IFQ_SET_MAXLEN(&pxd->pxd_svcq, 128);
  215. LIST_INSERT_HEAD(&pppx_devs, pxd, pxd_entry);
  216. out:
  217. rw_exit(&pppx_devs_lk);
  218. return (rv);
  219. }
  220. int
  221. pppxread(dev_t dev, struct uio *uio, int ioflag)
  222. {
  223. struct pppx_dev *pxd = pppx_dev2pxd(dev);
  224. struct mbuf *m, *m0;
  225. int error = 0;
  226. int len, s;
  227. if (!pxd)
  228. return (ENXIO);
  229. s = splnet();
  230. for (;;) {
  231. IF_DEQUEUE(&pxd->pxd_svcq, m0);
  232. if (m0 != NULL)
  233. break;
  234. if (ISSET(ioflag, IO_NDELAY)) {
  235. splx(s);
  236. return (EWOULDBLOCK);
  237. }
  238. pxd->pxd_waiting = 1;
  239. error = tsleep(pxd, (PZERO + 1)|PCATCH, "pppxread", 0);
  240. if (error != 0) {
  241. splx(s);
  242. return (error);
  243. }
  244. }
  245. splx(s);
  246. while (m0 != NULL && uio->uio_resid > 0 && error == 0) {
  247. len = min(uio->uio_resid, m0->m_len);
  248. if (len != 0)
  249. error = uiomovei(mtod(m0, caddr_t), len, uio);
  250. m = m_free(m0);
  251. m0 = m;
  252. }
  253. m_freem(m0);
  254. return (error);
  255. }
  256. int
  257. pppxwrite(dev_t dev, struct uio *uio, int ioflag)
  258. {
  259. /* struct pppx_dev *pxd = pppx_dev2pxd(dev); */
  260. struct pppx_hdr *th;
  261. struct mbuf *top, **mp, *m;
  262. struct niqueue *ifq;
  263. int tlen, mlen;
  264. int error = 0;
  265. if (uio->uio_resid < sizeof(*th) || uio->uio_resid > MCLBYTES)
  266. return (EMSGSIZE);
  267. tlen = uio->uio_resid;
  268. MGETHDR(m, M_DONTWAIT, MT_DATA);
  269. if (m == NULL)
  270. return (ENOBUFS);
  271. mlen = MHLEN;
  272. if (uio->uio_resid >= MINCLSIZE) {
  273. MCLGET(m, M_DONTWAIT);
  274. if (!(m->m_flags & M_EXT)) {
  275. m_free(m);
  276. return (ENOBUFS);
  277. }
  278. mlen = MCLBYTES;
  279. }
  280. top = NULL;
  281. mp = &top;
  282. while (error == 0 && uio->uio_resid > 0) {
  283. m->m_len = min(mlen, uio->uio_resid);
  284. error = uiomovei(mtod (m, caddr_t), m->m_len, uio);
  285. *mp = m;
  286. mp = &m->m_next;
  287. if (error == 0 && uio->uio_resid > 0) {
  288. MGET(m, M_DONTWAIT, MT_DATA);
  289. if (m == NULL) {
  290. error = ENOBUFS;
  291. break;
  292. }
  293. mlen = MLEN;
  294. if (uio->uio_resid >= MINCLSIZE) {
  295. MCLGET(m, M_DONTWAIT);
  296. if (!(m->m_flags & M_EXT)) {
  297. error = ENOBUFS;
  298. m_free(m);
  299. break;
  300. }
  301. mlen = MCLBYTES;
  302. }
  303. }
  304. }
  305. if (error) {
  306. m_freem(top);
  307. return (error);
  308. }
  309. top->m_pkthdr.len = tlen;
  310. /* strip the tunnel header */
  311. th = mtod(top, struct pppx_hdr *);
  312. m_adj(top, sizeof(struct pppx_hdr));
  313. switch (ntohl(th->pppx_proto)) {
  314. case AF_INET:
  315. ifq = &ipintrq;
  316. break;
  317. #ifdef INET6
  318. case AF_INET6:
  319. ifq = &ip6intrq;
  320. break;
  321. #endif
  322. default:
  323. m_freem(top);
  324. return (EAFNOSUPPORT);
  325. }
  326. if (niq_enqueue(ifq, m) != 0)
  327. return (ENOBUFS);
  328. return (error);
  329. }
  330. int
  331. pppxioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
  332. {
  333. struct pppx_dev *pxd = pppx_dev2pxd(dev);
  334. int error = 0;
  335. switch (cmd) {
  336. case PIPEXSMODE:
  337. /*
  338. * npppd always enables on open, and only disables before
  339. * closing. we cheat and let open and close do that, so lie
  340. * to npppd.
  341. */
  342. break;
  343. case PIPEXGMODE:
  344. *(int *)addr = 1;
  345. break;
  346. case PIPEXASESSION:
  347. error = pppx_add_session(pxd,
  348. (struct pipex_session_req *)addr);
  349. break;
  350. case PIPEXDSESSION:
  351. error = pppx_del_session(pxd,
  352. (struct pipex_session_close_req *)addr);
  353. break;
  354. case PIPEXCSESSION:
  355. error = pipex_config_session(
  356. (struct pipex_session_config_req *)addr);
  357. break;
  358. case PIPEXGSTAT:
  359. error = pipex_get_stat((struct pipex_session_stat_req *)addr);
  360. break;
  361. case PIPEXGCLOSED:
  362. error = pipex_get_closed((struct pipex_session_list_req *)addr);
  363. break;
  364. case PIPEXSIFDESCR:
  365. error = pppx_set_session_descr(pxd,
  366. (struct pipex_session_descr_req *)addr);
  367. break;
  368. case FIONBIO:
  369. case FIOASYNC:
  370. case FIONREAD:
  371. return (0);
  372. default:
  373. error = ENOTTY;
  374. break;
  375. }
  376. return (error);
  377. }
  378. int
  379. pppxpoll(dev_t dev, int events, struct proc *p)
  380. {
  381. struct pppx_dev *pxd = pppx_dev2pxd(dev);
  382. int s, revents = 0;
  383. if (events & (POLLIN | POLLRDNORM)) {
  384. s = splnet();
  385. if (!IF_IS_EMPTY(&pxd->pxd_svcq))
  386. revents |= events & (POLLIN | POLLRDNORM);
  387. splx(s);
  388. }
  389. if (events & (POLLOUT | POLLWRNORM))
  390. revents |= events & (POLLOUT | POLLWRNORM);
  391. if (revents == 0) {
  392. if (events & (POLLIN | POLLRDNORM))
  393. selrecord(p, &pxd->pxd_rsel);
  394. }
  395. return (revents);
  396. }
  397. int
  398. pppxkqfilter(dev_t dev, struct knote *kn)
  399. {
  400. struct pppx_dev *pxd = pppx_dev2pxd(dev);
  401. struct mutex *mtx;
  402. struct klist *klist;
  403. switch (kn->kn_filter) {
  404. case EVFILT_READ:
  405. mtx = &pxd->pxd_rsel_mtx;
  406. klist = &pxd->pxd_rsel.si_note;
  407. kn->kn_fop = &pppx_rd_filtops;
  408. break;
  409. case EVFILT_WRITE:
  410. mtx = &pxd->pxd_wsel_mtx;
  411. klist = &pxd->pxd_wsel.si_note;
  412. kn->kn_fop = &pppx_wr_filtops;
  413. break;
  414. default:
  415. return (EINVAL);
  416. }
  417. kn->kn_hook = (caddr_t)pxd;
  418. mtx_enter(mtx);
  419. SLIST_INSERT_HEAD(klist, kn, kn_selnext);
  420. mtx_leave(mtx);
  421. return (0);
  422. }
  423. void
  424. filt_pppx_rdetach(struct knote *kn)
  425. {
  426. struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
  427. struct klist *klist = &pxd->pxd_rsel.si_note;
  428. if (ISSET(kn->kn_status, KN_DETACHED))
  429. return;
  430. mtx_enter(&pxd->pxd_rsel_mtx);
  431. SLIST_REMOVE(klist, kn, knote, kn_selnext);
  432. mtx_leave(&pxd->pxd_rsel_mtx);
  433. }
  434. int
  435. filt_pppx_read(struct knote *kn, long hint)
  436. {
  437. struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
  438. int s, event = 0;
  439. if (ISSET(kn->kn_status, KN_DETACHED)) {
  440. kn->kn_data = 0;
  441. return (1);
  442. }
  443. s = splnet();
  444. if (!IF_IS_EMPTY(&pxd->pxd_svcq)) {
  445. event = 1;
  446. kn->kn_data = IF_LEN(&pxd->pxd_svcq);
  447. }
  448. splx(s);
  449. return (event);
  450. }
  451. void
  452. filt_pppx_wdetach(struct knote *kn)
  453. {
  454. struct pppx_dev *pxd = (struct pppx_dev *)kn->kn_hook;
  455. struct klist *klist = &pxd->pxd_wsel.si_note;
  456. if (ISSET(kn->kn_status, KN_DETACHED))
  457. return;
  458. mtx_enter(&pxd->pxd_wsel_mtx);
  459. SLIST_REMOVE(klist, kn, knote, kn_selnext);
  460. mtx_leave(&pxd->pxd_wsel_mtx);
  461. }
  462. int
  463. filt_pppx_write(struct knote *kn, long hint)
  464. {
  465. /* We're always ready to accept a write. */
  466. return (1);
  467. }
  468. int
  469. pppxclose(dev_t dev, int flags, int mode, struct proc *p)
  470. {
  471. struct pppx_dev *pxd;
  472. struct pppx_if *pxi;
  473. int s;
  474. rw_enter_write(&pppx_devs_lk);
  475. pxd = pppx_dev_lookup(dev);
  476. /* XXX */
  477. while ((pxi = LIST_FIRST(&pxd->pxd_pxis)))
  478. pppx_if_destroy(pxd, pxi);
  479. LIST_REMOVE(pxd, pxd_entry);
  480. s = splnet();
  481. IF_PURGE(&pxd->pxd_svcq);
  482. splx(s);
  483. free(pxd, M_DEVBUF, 0);
  484. if (LIST_EMPTY(&pppx_devs)) {
  485. pool_destroy(pppx_if_pl);
  486. free(pppx_if_pl, M_DEVBUF, 0);
  487. pppx_if_pl = NULL;
  488. }
  489. rw_exit_write(&pppx_devs_lk);
  490. return (0);
  491. }
  492. int
  493. pppx_if_cmp(struct pppx_if *a, struct pppx_if *b)
  494. {
  495. return memcmp(&a->pxi_key, &b->pxi_key, sizeof(a->pxi_key));
  496. }
  497. int
  498. pppx_if_next_unit(void)
  499. {
  500. struct pppx_if *pxi;
  501. int unit = 0;
  502. rw_assert_wrlock(&pppx_ifs_lk);
  503. /* this is safe without splnet since we're not modifying it */
  504. do {
  505. int found = 0;
  506. RB_FOREACH(pxi, pppx_ifs, &pppx_ifs) {
  507. if (pxi->pxi_unit == unit) {
  508. found = 1;
  509. break;
  510. }
  511. }
  512. if (found == 0)
  513. break;
  514. unit++;
  515. } while (unit > 0);
  516. return (unit);
  517. }
  518. struct pppx_if *
  519. pppx_if_find(struct pppx_dev *pxd, int session_id, int protocol)
  520. {
  521. struct pppx_if *s, *p;
  522. s = malloc(sizeof(*s), M_DEVBUF, M_WAITOK | M_ZERO);
  523. s->pxi_key.pxik_session_id = session_id;
  524. s->pxi_key.pxik_protocol = protocol;
  525. rw_enter_read(&pppx_ifs_lk);
  526. p = RB_FIND(pppx_ifs, &pppx_ifs, s);
  527. rw_exit_read(&pppx_ifs_lk);
  528. free(s, M_DEVBUF, 0);
  529. return (p);
  530. }
  531. int
  532. pppx_add_session(struct pppx_dev *pxd, struct pipex_session_req *req)
  533. {
  534. struct pppx_if *pxi;
  535. struct pipex_session *session;
  536. struct pipex_hash_head *chain;
  537. struct ifnet *ifp;
  538. int unit, s, error = 0;
  539. struct in_ifaddr *ia;
  540. struct sockaddr_in ifaddr;
  541. #ifdef PIPEX_PPPOE
  542. struct ifnet *over_ifp = NULL;
  543. #endif
  544. switch (req->pr_protocol) {
  545. #ifdef PIPEX_PPPOE
  546. case PIPEX_PROTO_PPPOE:
  547. over_ifp = ifunit(req->pr_proto.pppoe.over_ifname);
  548. if (over_ifp == NULL)
  549. return (EINVAL);
  550. if (req->pr_peer_address.ss_family != AF_UNSPEC)
  551. return (EINVAL);
  552. break;
  553. #endif
  554. #ifdef PIPEX_PPTP
  555. case PIPEX_PROTO_PPTP:
  556. #endif
  557. #ifdef PIPEX_L2TP
  558. case PIPEX_PROTO_L2TP:
  559. #endif
  560. switch (req->pr_peer_address.ss_family) {
  561. case AF_INET:
  562. if (req->pr_peer_address.ss_len != sizeof(struct sockaddr_in))
  563. return (EINVAL);
  564. break;
  565. #ifdef INET6
  566. case AF_INET6:
  567. if (req->pr_peer_address.ss_len != sizeof(struct sockaddr_in6))
  568. return (EINVAL);
  569. break;
  570. #endif
  571. default:
  572. return (EPROTONOSUPPORT);
  573. }
  574. if (req->pr_peer_address.ss_family !=
  575. req->pr_local_address.ss_family ||
  576. req->pr_peer_address.ss_len !=
  577. req->pr_local_address.ss_len)
  578. return (EINVAL);
  579. break;
  580. default:
  581. return (EPROTONOSUPPORT);
  582. }
  583. pxi = pool_get(pppx_if_pl, PR_WAITOK | PR_ZERO);
  584. if (pxi == NULL)
  585. return (ENOMEM);
  586. session = &pxi->pxi_session;
  587. ifp = &pxi->pxi_if;
  588. /* fake a pipex interface context */
  589. session->pipex_iface = &pxi->pxi_ifcontext;
  590. session->pipex_iface->ifnet_this = ifp;
  591. session->pipex_iface->pipexmode = PIPEX_ENABLED;
  592. /* setup session */
  593. session->state = PIPEX_STATE_OPENED;
  594. session->protocol = req->pr_protocol;
  595. session->session_id = req->pr_session_id;
  596. session->peer_session_id = req->pr_peer_session_id;
  597. session->peer_mru = req->pr_peer_mru;
  598. session->timeout_sec = req->pr_timeout_sec;
  599. session->ppp_flags = req->pr_ppp_flags;
  600. session->ppp_id = req->pr_ppp_id;
  601. session->ip_forward = 1;
  602. session->ip_address.sin_family = AF_INET;
  603. session->ip_address.sin_len = sizeof(struct sockaddr_in);
  604. session->ip_address.sin_addr = req->pr_ip_address;
  605. session->ip_netmask.sin_family = AF_INET;
  606. session->ip_netmask.sin_len = sizeof(struct sockaddr_in);
  607. session->ip_netmask.sin_addr = req->pr_ip_netmask;
  608. if (session->ip_netmask.sin_addr.s_addr == 0L)
  609. session->ip_netmask.sin_addr.s_addr = 0xffffffffL;
  610. session->ip_address.sin_addr.s_addr &=
  611. session->ip_netmask.sin_addr.s_addr;
  612. if (req->pr_peer_address.ss_len > 0)
  613. memcpy(&session->peer, &req->pr_peer_address,
  614. MIN(req->pr_peer_address.ss_len, sizeof(session->peer)));
  615. if (req->pr_local_address.ss_len > 0)
  616. memcpy(&session->local, &req->pr_local_address,
  617. MIN(req->pr_local_address.ss_len, sizeof(session->local)));
  618. #ifdef PIPEX_PPPOE
  619. if (req->pr_protocol == PIPEX_PROTO_PPPOE)
  620. session->proto.pppoe.over_ifp = over_ifp;
  621. #endif
  622. #ifdef PIPEX_PPTP
  623. if (req->pr_protocol == PIPEX_PROTO_PPTP) {
  624. struct pipex_pptp_session *sess_pptp = &session->proto.pptp;
  625. sess_pptp->snd_gap = 0;
  626. sess_pptp->rcv_gap = 0;
  627. sess_pptp->snd_una = req->pr_proto.pptp.snd_una;
  628. sess_pptp->snd_nxt = req->pr_proto.pptp.snd_nxt;
  629. sess_pptp->rcv_nxt = req->pr_proto.pptp.rcv_nxt;
  630. sess_pptp->rcv_acked = req->pr_proto.pptp.rcv_acked;
  631. sess_pptp->winsz = req->pr_proto.pptp.winsz;
  632. sess_pptp->maxwinsz = req->pr_proto.pptp.maxwinsz;
  633. sess_pptp->peer_maxwinsz = req->pr_proto.pptp.peer_maxwinsz;
  634. /* last ack number */
  635. sess_pptp->ul_snd_una = sess_pptp->snd_una - 1;
  636. }
  637. #endif
  638. #ifdef PIPEX_L2TP
  639. if (req->pr_protocol == PIPEX_PROTO_L2TP) {
  640. struct pipex_l2tp_session *sess_l2tp = &session->proto.l2tp;
  641. /* session keys */
  642. sess_l2tp->tunnel_id = req->pr_proto.l2tp.tunnel_id;
  643. sess_l2tp->peer_tunnel_id = req->pr_proto.l2tp.peer_tunnel_id;
  644. /* protocol options */
  645. sess_l2tp->option_flags = req->pr_proto.l2tp.option_flags;
  646. /* initial state of dynamic context */
  647. sess_l2tp->ns_gap = sess_l2tp->nr_gap = 0;
  648. sess_l2tp->ns_nxt = req->pr_proto.l2tp.ns_nxt;
  649. sess_l2tp->nr_nxt = req->pr_proto.l2tp.nr_nxt;
  650. sess_l2tp->ns_una = req->pr_proto.l2tp.ns_una;
  651. sess_l2tp->nr_acked = req->pr_proto.l2tp.nr_acked;
  652. /* last ack number */
  653. sess_l2tp->ul_ns_una = sess_l2tp->ns_una - 1;
  654. }
  655. #endif
  656. #ifdef PIPEX_MPPE
  657. if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ACCEPTED) != 0)
  658. pipex_session_init_mppe_recv(session,
  659. req->pr_mppe_recv.stateless, req->pr_mppe_recv.keylenbits,
  660. req->pr_mppe_recv.master_key);
  661. if ((req->pr_ppp_flags & PIPEX_PPP_MPPE_ENABLED) != 0)
  662. pipex_session_init_mppe_send(session,
  663. req->pr_mppe_send.stateless, req->pr_mppe_send.keylenbits,
  664. req->pr_mppe_send.master_key);
  665. if (pipex_session_is_mppe_required(session)) {
  666. if (!pipex_session_is_mppe_enabled(session) ||
  667. !pipex_session_is_mppe_accepted(session)) {
  668. pool_put(pppx_if_pl, pxi);
  669. return (EINVAL);
  670. }
  671. }
  672. #endif
  673. /* try to set the interface up */
  674. rw_enter_write(&pppx_ifs_lk);
  675. unit = pppx_if_next_unit();
  676. if (unit < 0) {
  677. pool_put(pppx_if_pl, pxi);
  678. error = ENOMEM;
  679. goto out;
  680. }
  681. pxi->pxi_unit = unit;
  682. pxi->pxi_key.pxik_session_id = req->pr_session_id;
  683. pxi->pxi_key.pxik_protocol = req->pr_protocol;
  684. /* this is safe without splnet since we're not modifying it */
  685. if (RB_FIND(pppx_ifs, &pppx_ifs, pxi) != NULL) {
  686. pool_put(pppx_if_pl, pxi);
  687. error = EADDRINUSE;
  688. goto out;
  689. }
  690. snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", "pppx", unit);
  691. ifp->if_mtu = req->pr_peer_mru; /* XXX */
  692. ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST | IFF_UP;
  693. ifp->if_start = pppx_if_start;
  694. ifp->if_output = pppx_if_output;
  695. ifp->if_ioctl = pppx_if_ioctl;
  696. ifp->if_type = IFT_PPP;
  697. IFQ_SET_MAXLEN(&ifp->if_snd, 1);
  698. IFQ_SET_READY(&ifp->if_snd);
  699. ifp->if_softc = pxi;
  700. /* ifp->if_rdomain = req->pr_rdomain; */
  701. s = splnet();
  702. /* hook up pipex context */
  703. chain = PIPEX_ID_HASHTABLE(session->session_id);
  704. LIST_INSERT_HEAD(chain, session, id_chain);
  705. LIST_INSERT_HEAD(&pipex_session_list, session, session_list);
  706. switch (req->pr_protocol) {
  707. case PIPEX_PROTO_PPTP:
  708. case PIPEX_PROTO_L2TP:
  709. chain = PIPEX_PEER_ADDR_HASHTABLE(
  710. pipex_sockaddr_hash_key((struct sockaddr *)&session->peer));
  711. LIST_INSERT_HEAD(chain, session, peer_addr_chain);
  712. break;
  713. }
  714. /* if first session is added, start timer */
  715. if (LIST_NEXT(session, session_list) == NULL)
  716. pipex_timer_start();
  717. if_attach(ifp);
  718. if_addgroup(ifp, "pppx");
  719. if_alloc_sadl(ifp);
  720. #if NBPFILTER > 0
  721. bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
  722. #endif
  723. SET(ifp->if_flags, IFF_RUNNING);
  724. if (RB_INSERT(pppx_ifs, &pppx_ifs, pxi) != NULL)
  725. panic("pppx_ifs modified while lock was held");
  726. LIST_INSERT_HEAD(&pxd->pxd_pxis, pxi, pxi_list);
  727. /* XXX ipv6 support? how does the caller indicate it wants ipv6
  728. * instead of ipv4?
  729. */
  730. memset(&ifaddr, 0, sizeof(ifaddr));
  731. ifaddr.sin_family = AF_INET;
  732. ifaddr.sin_len = sizeof(ifaddr);
  733. ifaddr.sin_addr = req->pr_ip_srcaddr;
  734. ia = malloc(sizeof (*ia), M_IFADDR, M_WAITOK | M_ZERO);
  735. ia->ia_addr.sin_family = AF_INET;
  736. ia->ia_addr.sin_len = sizeof(struct sockaddr_in);
  737. ia->ia_addr.sin_addr = req->pr_ip_srcaddr;
  738. ia->ia_dstaddr.sin_family = AF_INET;
  739. ia->ia_dstaddr.sin_len = sizeof(struct sockaddr_in);
  740. ia->ia_dstaddr.sin_addr = req->pr_ip_address;
  741. ia->ia_sockmask.sin_family = AF_INET;
  742. ia->ia_sockmask.sin_len = sizeof(struct sockaddr_in);
  743. ia->ia_sockmask.sin_addr = req->pr_ip_netmask;
  744. ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
  745. ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
  746. ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
  747. ia->ia_ifa.ifa_ifp = ifp;
  748. ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
  749. error = in_ifinit(ifp, ia, &ifaddr, 1);
  750. if (error) {
  751. printf("pppx: unable to set addresses for %s, error=%d\n",
  752. ifp->if_xname, error);
  753. } else {
  754. dohooks(ifp->if_addrhooks, 0);
  755. }
  756. splx(s);
  757. out:
  758. rw_exit_write(&pppx_ifs_lk);
  759. return (error);
  760. }
  761. int
  762. pppx_del_session(struct pppx_dev *pxd, struct pipex_session_close_req *req)
  763. {
  764. struct pppx_if *pxi;
  765. pxi = pppx_if_find(pxd, req->pcr_session_id, req->pcr_protocol);
  766. if (pxi == NULL)
  767. return (EINVAL);
  768. req->pcr_stat = pxi->pxi_session.stat;
  769. pppx_if_destroy(pxd, pxi);
  770. return (0);
  771. }
  772. int
  773. pppx_set_session_descr(struct pppx_dev *pxd,
  774. struct pipex_session_descr_req *req)
  775. {
  776. struct pppx_if *pxi;
  777. pxi = pppx_if_find(pxd, req->pdr_session_id, req->pdr_protocol);
  778. if (pxi == NULL)
  779. return (EINVAL);
  780. (void)memset(pxi->pxi_if.if_description, 0, IFDESCRSIZE);
  781. strlcpy(pxi->pxi_if.if_description, req->pdr_descr, IFDESCRSIZE);
  782. return (0);
  783. }
  784. void
  785. pppx_if_destroy(struct pppx_dev *pxd, struct pppx_if *pxi)
  786. {
  787. struct ifnet *ifp;
  788. struct pipex_session *session;
  789. int s;
  790. session = &pxi->pxi_session;
  791. ifp = &pxi->pxi_if;
  792. s = splnet();
  793. LIST_REMOVE(session, id_chain);
  794. LIST_REMOVE(session, session_list);
  795. switch (session->protocol) {
  796. case PIPEX_PROTO_PPTP:
  797. case PIPEX_PROTO_L2TP:
  798. LIST_REMOVE((struct pipex_session *)session,
  799. peer_addr_chain);
  800. break;
  801. }
  802. /* if final session is destroyed, stop timer */
  803. if (LIST_EMPTY(&pipex_session_list))
  804. pipex_timer_stop();
  805. splx(s);
  806. if_detach(ifp);
  807. rw_enter_write(&pppx_ifs_lk);
  808. if (RB_REMOVE(pppx_ifs, &pppx_ifs, pxi) == NULL)
  809. panic("pppx_ifs modified while lock was held");
  810. LIST_REMOVE(pxi, pxi_list);
  811. rw_exit_write(&pppx_ifs_lk);
  812. pool_put(pppx_if_pl, pxi);
  813. }
  814. void
  815. pppx_if_start(struct ifnet *ifp)
  816. {
  817. struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
  818. struct mbuf *m;
  819. int proto, s;
  820. if (ISSET(ifp->if_flags, IFF_OACTIVE))
  821. return;
  822. if (!ISSET(ifp->if_flags, IFF_RUNNING))
  823. return;
  824. for (;;) {
  825. s = splnet();
  826. IFQ_DEQUEUE(&ifp->if_snd, m);
  827. splx(s);
  828. if (m == NULL)
  829. break;
  830. proto = *mtod(m, int *);
  831. m_adj(m, sizeof(proto));
  832. #if NBPFILTER > 0
  833. if (ifp->if_bpf) {
  834. switch (proto) {
  835. case PPP_IP:
  836. bpf_mtap_af(ifp->if_bpf, AF_INET, m,
  837. BPF_DIRECTION_OUT);
  838. break;
  839. case PPP_IPV6:
  840. bpf_mtap_af(ifp->if_bpf, AF_INET6, m,
  841. BPF_DIRECTION_OUT);
  842. break;
  843. }
  844. }
  845. #endif
  846. ifp->if_obytes += m->m_pkthdr.len;
  847. ifp->if_opackets++;
  848. pipex_ppp_output(m, &pxi->pxi_session, proto);
  849. }
  850. }
  851. int
  852. pppx_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
  853. struct rtentry *rt)
  854. {
  855. int error = 0;
  856. int proto;
  857. if (!ISSET(ifp->if_flags, IFF_UP)) {
  858. m_freem(m);
  859. error = ENETDOWN;
  860. goto out;
  861. }
  862. switch (dst->sa_family) {
  863. case AF_INET:
  864. proto = PPP_IP;
  865. break;
  866. default:
  867. m_freem(m);
  868. error = EPFNOSUPPORT;
  869. goto out;
  870. }
  871. M_PREPEND(m, sizeof(int), M_DONTWAIT);
  872. if (m == NULL) {
  873. error = ENOBUFS;
  874. goto out;
  875. }
  876. *mtod(m, int *) = proto;
  877. error = if_enqueue(ifp, m);
  878. out:
  879. if (error)
  880. ifp->if_oerrors++;
  881. return (error);
  882. }
  883. int
  884. pppx_if_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
  885. {
  886. struct pppx_if *pxi = (struct pppx_if *)ifp->if_softc;
  887. struct ifreq *ifr = (struct ifreq *)addr;
  888. struct ifaddr *ifa = (struct ifaddr *)addr;
  889. int error = 0;
  890. switch (cmd) {
  891. case SIOCSIFADDR:
  892. ifa->ifa_rtrequest = p2p_rtrequest;
  893. break;
  894. case SIOCSIFFLAGS:
  895. break;
  896. case SIOCADDMULTI:
  897. case SIOCDELMULTI:
  898. break;
  899. case SIOCSIFMTU:
  900. if (ifr->ifr_mtu < 512 ||
  901. ifr->ifr_mtu > pxi->pxi_session.peer_mru)
  902. error = EINVAL;
  903. else
  904. ifp->if_mtu = ifr->ifr_mtu;
  905. break;
  906. default:
  907. error = ENOTTY;
  908. break;
  909. }
  910. return (error);
  911. }
  912. RB_GENERATE(pppx_ifs, pppx_if, pxi_entry, pppx_if_cmp);