openl2tp.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*****************************************************************************
  2. * Copyright (C) 2006,2007,2008 Katalix Systems Ltd
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. *****************************************************************************/
  19. /* pppd plugin for interfacing to openl2tpd */
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <errno.h>
  24. #include "pppd.h"
  25. #include "pathnames.h"
  26. #include "fsm.h"
  27. #include "lcp.h"
  28. #include "ccp.h"
  29. #include "ipcp.h"
  30. #include <sys/stat.h>
  31. #include <net/if.h>
  32. #include <sys/ioctl.h>
  33. #include <sys/socket.h>
  34. #include <sys/un.h>
  35. #include <netinet/in.h>
  36. #include <signal.h>
  37. #include <linux/version.h>
  38. #include <linux/sockios.h>
  39. #ifndef aligned_u64
  40. /* should be defined in sys/types.h */
  41. #define aligned_u64 unsigned long long __attribute__((aligned(8)))
  42. #endif
  43. #include <linux/types.h>
  44. #include <linux/if_ether.h>
  45. #include <linux/ppp_defs.h>
  46. #include <linux/if_ppp.h>
  47. #include <linux/if_pppox.h>
  48. #include <linux/if_pppol2tp.h>
  49. #include "l2tp_event.h"
  50. extern int pppol2tp_tunnel_id;
  51. extern int pppol2tp_session_id;
  52. extern void (*pppol2tp_send_accm_hook)(int tunnel_id, int session_id,
  53. uint32_t send_accm, uint32_t recv_accm);
  54. extern void (*pppol2tp_ip_updown_hook)(int tunnel_id, int session_id, int up);
  55. const char pppd_version[] = VERSION;
  56. static int openl2tp_fd = -1;
  57. static void (*old_pppol2tp_send_accm_hook)(int tunnel_id, int session_id,
  58. uint32_t send_accm,
  59. uint32_t recv_accm) = NULL;
  60. static void (*old_pppol2tp_ip_updown_hook)(int tunnel_id, int session_id,
  61. int up) = NULL;
  62. static void (*old_multilink_join_hook)(void) = NULL;
  63. /*****************************************************************************
  64. * OpenL2TP interface.
  65. * We send a PPP_ACCM_IND to openl2tpd to report ACCM values and
  66. * SESSION_PPP_UPDOWN_IND to indicate when the PPP link comes up or
  67. * goes down.
  68. *****************************************************************************/
  69. static int openl2tp_client_create(void)
  70. {
  71. struct sockaddr_un addr;
  72. int result;
  73. if (openl2tp_fd < 0) {
  74. openl2tp_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
  75. if (openl2tp_fd < 0) {
  76. error("openl2tp connection create: %m");
  77. return -ENOTCONN;
  78. }
  79. addr.sun_family = AF_UNIX;
  80. strcpy(&addr.sun_path[0], OPENL2TP_EVENT_SOCKET_NAME);
  81. result = connect(openl2tp_fd, (struct sockaddr *) &addr,
  82. sizeof(addr));
  83. if (result < 0) {
  84. error("openl2tp connection connect: %m");
  85. return -ENOTCONN;
  86. }
  87. }
  88. return 0;
  89. }
  90. static void openl2tp_send_accm_ind(int tunnel_id, int session_id,
  91. uint32_t send_accm, uint32_t recv_accm)
  92. {
  93. int result;
  94. uint8_t buf[OPENL2TP_MSG_MAX_LEN];
  95. struct openl2tp_event_msg *msg = (void *) &buf[0];
  96. struct openl2tp_event_tlv *tlv;
  97. uint16_t tid = tunnel_id;
  98. uint16_t sid = session_id;
  99. struct openl2tp_tlv_ppp_accm accm;
  100. if (openl2tp_fd < 0) {
  101. result = openl2tp_client_create();
  102. if (result < 0) {
  103. goto out;
  104. }
  105. }
  106. accm.send_accm = send_accm;
  107. accm.recv_accm = recv_accm;
  108. msg->msg_signature = OPENL2TP_MSG_SIGNATURE;
  109. msg->msg_type = OPENL2TP_MSG_TYPE_PPP_ACCM_IND;
  110. msg->msg_len = 0;
  111. tlv = (void *) &msg->msg_data[msg->msg_len];
  112. tlv->tlv_type = OPENL2TP_TLV_TYPE_TUNNEL_ID;
  113. tlv->tlv_len = sizeof(tid);
  114. memcpy(&tlv->tlv_value[0], &tid, tlv->tlv_len);
  115. msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
  116. tlv = (void *) &msg->msg_data[msg->msg_len];
  117. tlv->tlv_type = OPENL2TP_TLV_TYPE_SESSION_ID;
  118. tlv->tlv_len = sizeof(sid);
  119. memcpy(&tlv->tlv_value[0], &sid, tlv->tlv_len);
  120. msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
  121. tlv = (void *) &msg->msg_data[msg->msg_len];
  122. tlv->tlv_type = OPENL2TP_TLV_TYPE_PPP_ACCM;
  123. tlv->tlv_len = sizeof(accm);
  124. memcpy(&tlv->tlv_value[0], &accm, tlv->tlv_len);
  125. msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
  126. result = send(openl2tp_fd, msg, sizeof(*msg) + msg->msg_len,
  127. MSG_NOSIGNAL);
  128. if (result < 0) {
  129. error("openl2tp send: %m");
  130. }
  131. if (result != (sizeof(*msg) + msg->msg_len)) {
  132. warn("openl2tp send: unexpected byte count %d, expected %d",
  133. result, sizeof(msg) + msg->msg_len);
  134. }
  135. dbglog("openl2tp send: sent PPP_ACCM_IND, %d bytes", result);
  136. out:
  137. if (old_pppol2tp_send_accm_hook != NULL) {
  138. (*old_pppol2tp_send_accm_hook)(tunnel_id, session_id,
  139. send_accm, recv_accm);
  140. }
  141. return;
  142. }
  143. static void openl2tp_ppp_updown_ind(int tunnel_id, int session_id, int up)
  144. {
  145. int result;
  146. uint8_t buf[OPENL2TP_MSG_MAX_LEN];
  147. struct openl2tp_event_msg *msg = (void *) &buf[0];
  148. struct openl2tp_event_tlv *tlv;
  149. uint16_t tid = tunnel_id;
  150. uint16_t sid = session_id;
  151. uint8_t state = up;
  152. int unit = ifunit;
  153. char *user_name = NULL;
  154. if (openl2tp_fd < 0) {
  155. result = openl2tp_client_create();
  156. if (result < 0) {
  157. goto out;
  158. }
  159. }
  160. if (peer_authname[0] != '\0') {
  161. user_name = strdup(peer_authname);
  162. }
  163. msg->msg_signature = OPENL2TP_MSG_SIGNATURE;
  164. msg->msg_type = OPENL2TP_MSG_TYPE_PPP_UPDOWN_IND;
  165. msg->msg_len = 0;
  166. tlv = (void *) &msg->msg_data[msg->msg_len];
  167. tlv->tlv_type = OPENL2TP_TLV_TYPE_TUNNEL_ID;
  168. tlv->tlv_len = sizeof(tid);
  169. memcpy(&tlv->tlv_value[0], &tid, tlv->tlv_len);
  170. msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
  171. tlv = (void *) &msg->msg_data[msg->msg_len];
  172. tlv->tlv_type = OPENL2TP_TLV_TYPE_SESSION_ID;
  173. tlv->tlv_len = sizeof(sid);
  174. memcpy(&tlv->tlv_value[0], &sid, tlv->tlv_len);
  175. msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
  176. tlv = (void *) &msg->msg_data[msg->msg_len];
  177. tlv->tlv_type = OPENL2TP_TLV_TYPE_PPP_STATE;
  178. tlv->tlv_len = sizeof(state);
  179. memcpy(&tlv->tlv_value[0], &state, tlv->tlv_len);
  180. msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
  181. tlv = (void *) &msg->msg_data[msg->msg_len];
  182. tlv->tlv_type = OPENL2TP_TLV_TYPE_PPP_UNIT;
  183. tlv->tlv_len = sizeof(unit);
  184. memcpy(&tlv->tlv_value[0], &unit, tlv->tlv_len);
  185. msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
  186. tlv = (void *) &msg->msg_data[msg->msg_len];
  187. tlv->tlv_type = OPENL2TP_TLV_TYPE_PPP_IFNAME;
  188. tlv->tlv_len = strlen(ifname) + 1;
  189. memcpy(&tlv->tlv_value[0], ifname, tlv->tlv_len);
  190. msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
  191. if (user_name != NULL) {
  192. tlv = (void *) &msg->msg_data[msg->msg_len];
  193. tlv->tlv_type = OPENL2TP_TLV_TYPE_PPP_USER_NAME;
  194. tlv->tlv_len = strlen(user_name) + 1;
  195. memcpy(&tlv->tlv_value[0], user_name, tlv->tlv_len);
  196. msg->msg_len += sizeof(*tlv) + ALIGN32(tlv->tlv_len);
  197. }
  198. result = send(openl2tp_fd, msg, sizeof(*msg) + msg->msg_len,
  199. MSG_NOSIGNAL);
  200. if (result < 0) {
  201. error("openl2tp send: %m");
  202. }
  203. if (result != (sizeof(*msg) + msg->msg_len)) {
  204. warn("openl2tp send: unexpected byte count %d, expected %d",
  205. result, sizeof(msg) + msg->msg_len);
  206. }
  207. dbglog("openl2tp send: sent PPP_UPDOWN_IND, %d bytes", result);
  208. out:
  209. if (old_pppol2tp_ip_updown_hook != NULL) {
  210. (*old_pppol2tp_ip_updown_hook)(tunnel_id, session_id, up);
  211. }
  212. return;
  213. }
  214. /*****************************************************************************
  215. * When a multilink interface is created, there are 2 cases to consider.
  216. *
  217. * 1. The new interface is the first of a multilink bundle (master).
  218. * 2. The new interface is being attached to an existing bundle.
  219. *
  220. * The first case is handled by existing code because the interface
  221. * generates ip-up events just like standard interfaces. But in the
  222. * second case, where the interface is added to an existing ppp
  223. * bundle, pppd does not do IP negotiation and so as a result, no
  224. * ip-up event is generated when the interface is created. Since
  225. * openl2tpd needs the SESSION_PPP_UPDOWN_IND for all interfaces of a
  226. * PPP bundle, we must fake the event.
  227. *
  228. * We use the ip_multilink_join_hook to hear when an interface joins a
  229. * multilink bundle.
  230. *****************************************************************************/
  231. static void openl2tp_multilink_join_ind(void)
  232. {
  233. if (doing_multilink && !multilink_master) {
  234. /* send event only if not master */
  235. openl2tp_ppp_updown_ind(pppol2tp_tunnel_id,
  236. pppol2tp_session_id, 1);
  237. }
  238. }
  239. /*****************************************************************************
  240. * Application init
  241. *****************************************************************************/
  242. void plugin_init(void)
  243. {
  244. old_pppol2tp_send_accm_hook = pppol2tp_send_accm_hook;
  245. pppol2tp_send_accm_hook = openl2tp_send_accm_ind;
  246. old_pppol2tp_ip_updown_hook = pppol2tp_ip_updown_hook;
  247. pppol2tp_ip_updown_hook = openl2tp_ppp_updown_ind;
  248. old_multilink_join_hook = multilink_join_hook;
  249. multilink_join_hook = openl2tp_multilink_join_ind;
  250. }