pppipcp.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:28k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /*
  2.  *  PPPIPCP.C -- negotiate IP parameters
  3.  *
  4.  * This implementation of PPP is declared to be in the public domain.
  5.  *
  6.  * Jan 91 Bill_Simpson@um.cc.umich.edu
  7.  * Computer Systems Consulting Services
  8.  *
  9.  * Acknowledgements and correction history may be found in PPP.C
  10.  */
  11. #include <stdio.h>
  12. #include <ctype.h>
  13. #include <time.h>
  14. #include "global.h"
  15. #include "mbuf.h"
  16. #include "iface.h"
  17. #include "slhc.h"
  18. #include "ppp.h"
  19. #include "pppfsm.h"
  20. #include "pppipcp.h"
  21. #include "cmdparse.h"
  22. #include "files.h"
  23. #include "trace.h"
  24. /* These defaults are defined in the PPP RFCs, and must not be changed */
  25. static struct ipcp_value_s ipcp_default = {
  26. FALSE, /* no need to negotiate defaults */
  27. 0L, /* no source address */
  28. 0L, /* no destination address */
  29. 0, /* no compression protocol */
  30. 0, /* no slots */
  31. 0 /* no slot compression */
  32. };
  33. /* for test purposes, accept anything we understand */
  34. static uint16 ipcp_negotiate = IPCP_N_ADDRESS | IPCP_N_COMPRESS;
  35. static byte_t option_length[] = {
  36.  0, /* unused */
  37. 10, /* address */
  38.  6 /* compression */
  39. };
  40. static int doipcp_local(int argc, char *argv[], void *p);
  41. static int doipcp_open(int argc, char *argv[], void *p);
  42. static int doipcp_pool(int argc, char *argv[], void *p);
  43. static int doipcp_remote(int argc, char *argv[], void *p);
  44. static int doipcp_address(int argc, char *argv[], void *p);
  45. static int doipcp_compress(int argc, char *argv[], void *p);
  46. static int doipcp_default(int argc, char *argv[], void *p);
  47. static void ipcp_option(struct mbuf **bpp,
  48. struct ipcp_value_s *value_p,
  49. byte_t o_type,
  50. byte_t o_length,
  51. struct mbuf **copy_bpp);
  52. static void ipcp_makeoptions(struct mbuf **bpp,
  53. struct ipcp_value_s *value_p,
  54. uint16 negotiating);
  55. static struct mbuf *ipcp_makereq(struct fsm_s *fsm_p);
  56. static int ipcp_check(struct mbuf **bpp,
  57. struct ipcp_s *ipcp_p,
  58. struct ipcp_side_s *side_p,
  59. struct option_hdr *option_p,
  60. int request);
  61. static int ipcp_request(struct fsm_s *fsm_p,
  62. struct config_hdr *config,
  63. struct mbuf **data);
  64. static int ipcp_ack(struct fsm_s *fsm_p,
  65. struct config_hdr *config,
  66. struct mbuf **data);
  67. static int ipcp_nak(struct fsm_s *fsm_p,
  68. struct config_hdr *config,
  69. struct mbuf **data);
  70. static int ipcp_reject(struct fsm_s *fsm_p,
  71. struct config_hdr *config,
  72. struct mbuf **data);
  73. static void ipcp_reset(struct fsm_s *fsm_p);
  74. static int32 ipcp_addr_idle(int32 addr);
  75. static int32 ipcp_lookuppeer(char *peerid);
  76. static int32 ipcp_poolnext(struct ipcp_s *ipcp_p);
  77. static void ipcp_starting(struct fsm_s *fsm_p);
  78. static void ipcp_stopping(struct fsm_s *fsm_p);
  79. static void ipcp_closing(struct fsm_s *fsm_p);
  80. static void ipcp_opening(struct fsm_s *fsm_p);
  81. static void ipcp_free(struct fsm_s *fsm_p);
  82. static struct fsm_constant_s ipcp_constants = {
  83. "IPcp",
  84. PPP_IPCP_PROTOCOL,
  85. 0x00FE, /* codes 1-7 recognized */
  86. IPcp,
  87. IPCP_REQ_TRY,
  88. IPCP_NAK_TRY,
  89. IPCP_TERM_TRY,
  90. IPCP_TIMEOUT * 1000L,
  91. ipcp_free,
  92. ipcp_reset,
  93. ipcp_starting,
  94. ipcp_opening,
  95. ipcp_closing,
  96. ipcp_stopping,
  97. ipcp_makereq,
  98. ipcp_request,
  99. ipcp_ack,
  100. ipcp_nak,
  101. ipcp_reject,
  102. };
  103. /************************************************************************/
  104. /* "ppp <iface> ipcp" subcommands */
  105. static struct cmds IPcpcmds[] = {
  106. "close", doppp_close, 0, 0, NULL,
  107. "listen", doppp_passive, 0, 0, NULL,
  108. "local", doipcp_local, 0, 0, NULL,
  109. "open", doipcp_open, 0, 0, NULL,
  110. "pool", doipcp_pool, 0, 0, NULL,
  111. "remote", doipcp_remote, 0, 0, NULL,
  112. "timeout", doppp_timeout, 0, 0, NULL,
  113. "try", doppp_try, 0, 0, NULL,
  114. NULL,
  115. };
  116. /* "ppp <iface> ipcp {local | remote}" subcommands */
  117. static struct cmds IPcpside_cmds[] = {
  118. "address", doipcp_address, 0, 0, NULL,
  119. "compress", doipcp_compress,0, 0, NULL,
  120. "default", doipcp_default, 0, 0, NULL,
  121. NULL,
  122. };
  123. int
  124. doppp_ipcp(argc,argv,p)
  125. int argc;
  126. char *argv[];
  127. void *p;
  128. {
  129. register struct iface *ifp = p;
  130. register struct ppp_s *ppp_p = ifp->edv;
  131. return subcmd(IPcpcmds, argc, argv, &(ppp_p->fsm[IPcp]));
  132. }
  133. static int
  134. doipcp_local(argc,argv,p)
  135. int argc;
  136. char *argv[];
  137. void *p;
  138. {
  139. struct fsm_s *fsm_p = p;
  140. struct ipcp_s *ipcp_p = fsm_p->pdv;
  141. return subcmd(IPcpside_cmds, argc, argv, &(ipcp_p->local));
  142. }
  143. static int
  144. doipcp_open(argc,argv,p)
  145. int argc;
  146. char *argv[];
  147. void *p;
  148. {
  149. struct fsm_s *fsm_p = p;
  150. doppp_active( argc, argv, p );
  151. if ( fsm_p->ppp_p->phase == pppREADY ) {
  152. fsm_start( fsm_p );
  153. }
  154. return 0;
  155. }
  156. /* Set a pool of peer addresses for PPP interface */
  157. static int
  158. doipcp_pool(argc,argv,p)
  159. int argc;
  160. char *argv[];
  161. void *p;
  162. {
  163. struct fsm_s *fsm_p = p;
  164. struct ipcp_s *ipcp_p = fsm_p->pdv;
  165. int32 pool_addr;
  166. int pool_cnt;
  167. if (argc < 2) {
  168. if ( ipcp_p->peer_min == 0L ) {
  169. printf("None");
  170. } else {
  171. printf("%s thru ", inet_ntoa(ipcp_p->peer_min));
  172. printf("%sn", inet_ntoa(ipcp_p->peer_max));
  173. }
  174. return 0;
  175. }
  176. if ((pool_addr = resolve(argv[1])) == 0L) {
  177. printf(Badhost,argv[1]);
  178. }
  179. /* May specify a consecutive range of addresses; otherwise assume 1 */
  180. if (argc < 3)
  181. pool_cnt = 1;
  182. else
  183. pool_cnt = (int)strtol( argv[2], NULL, 0 );
  184. if (pool_cnt <= 0) {
  185. printf("Pool count %s (%d) must be > 0n");
  186. return -1;
  187. }
  188. ipcp_p->peer_min = pool_addr;
  189. ipcp_p->peer_max = pool_addr + pool_cnt - 1;
  190. return 0;
  191. }
  192. static int
  193. doipcp_remote(argc,argv,p)
  194. int argc;
  195. char *argv[];
  196. void *p;
  197. {
  198. struct fsm_s *fsm_p = p;
  199. struct ipcp_s *ipcp_p = fsm_p->pdv;
  200. return subcmd(IPcpside_cmds, argc, argv, &(ipcp_p->remote));
  201. }
  202. /************************************************************************/
  203. /* Set addresses for PPP interface */
  204. static int
  205. doipcp_address(argc,argv,p)
  206. int argc;
  207. char *argv[];
  208. void *p;
  209. {
  210. struct ipcp_side_s *side_p = p;
  211. int32 x32;
  212. if (argc < 2) {
  213. printf("%sn", inet_ntoa(side_p->want.address));
  214. return 0;
  215. } else if ( stricmp(argv[1],"allow") == 0 ) {
  216. return bit16cmd( &(side_p->will_negotiate), IPCP_N_ADDRESS,
  217. "Allow Address", --argc, &argv[1] );
  218. }
  219. if ((x32 = resolve(argv[1])) == 0L) {
  220. printf(Badhost,argv[1]);
  221. }
  222. side_p->want.address = x32;
  223. side_p->want.negotiate |= IPCP_N_ADDRESS;
  224. return 0;
  225. }
  226. /* Set IP compression type for PPP interface */
  227. static int
  228. doipcp_compress(argc,argv,p)
  229. int argc;
  230. char *argv[];
  231. void *p;
  232. {
  233. struct ipcp_side_s *side_p = p;
  234. if (argc < 2) {
  235. if ( side_p->want.negotiate & IPCP_N_COMPRESS ) {
  236. switch ( side_p->want.compression ) {
  237. case PPP_COMPR_PROTOCOL:
  238. printf("TCP header compression enabled; "
  239. "Slots = %d, slot compress = %xn",
  240. side_p->want.slots,
  241. side_p->want.slot_compress);
  242. break;
  243. default:
  244. printf("0x%04xn", side_p->want.compression);
  245. break;
  246. };
  247. } else {
  248. printf("Nonen");
  249. }
  250. } else if ( stricmp(argv[1],"allow") == 0 ) {
  251. return bit16cmd( &(side_p->will_negotiate), IPCP_N_COMPRESS,
  252. "Allow Compression", --argc, &argv[1] );
  253. } else if ( stricmp(argv[1],"tcp") == 0
  254.  || stricmp(argv[1],"vj") == 0 ) {
  255. side_p->want.compression = PPP_COMPR_PROTOCOL;
  256. if ( argc >= 3 ) {
  257. side_p->want.slots = strtol(argv[2],NULL,0);
  258. if ( side_p->want.slots < 1 || side_p->want.slots > 255 ) {
  259. printf( "slots must be in range 1 to 255" );
  260. return 1;
  261. }
  262. } else {
  263. side_p->want.slots = IPCP_SLOT_DEFAULT;
  264. }
  265. if ( argc >= 4 ) {
  266. side_p->want.slot_compress = strtol(argv[3],NULL,0);
  267. } else {
  268. side_p->want.slot_compress = IPCP_SLOT_COMPRESS;
  269. }
  270. side_p->want.negotiate |= IPCP_N_COMPRESS;
  271. } else if (stricmp(argv[1],"none") == 0) {
  272. side_p->want.negotiate &= ~IPCP_N_COMPRESS;
  273. } else {
  274. printf("allow tcp nonen");
  275. return 1;
  276. }
  277. return 0;
  278. }
  279. static int
  280. doipcp_default(argc,argv,p)
  281. int argc;
  282. char *argv[];
  283. void *p;
  284. {
  285. struct ipcp_side_s *side_p = p;
  286. ASSIGN( side_p->want, ipcp_default );
  287. return 0;
  288. }
  289. /************************************************************************/
  290. /* E V E N T   P R O C E S S I N G */
  291. /************************************************************************/
  292. static void
  293. ipcp_option( bpp, value_p, o_type, o_length, copy_bpp )
  294. struct mbuf **bpp;
  295. struct ipcp_value_s *value_p;
  296. byte_t o_type;
  297. byte_t o_length;
  298. struct mbuf **copy_bpp;
  299. {
  300. struct mbuf *bp;
  301. register uint8 *cp;
  302. register int toss = o_length - OPTION_HDR_LEN;
  303. if ((bp = alloc_mbuf(o_length)) == NULL) {
  304. return;
  305. }
  306. cp = bp->data;
  307. *cp++ = o_type;
  308. *cp++ = o_length;
  309. switch ( o_type ) {
  310. case IPCP_ADDRESS:
  311. cp = put32(cp, value_p->address);
  312. cp = put32(cp, value_p->other);
  313. toss -= 8;
  314. #ifdef PPP_DEBUG_OPTIONS
  315. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  316. trace_log(PPPiface, "    making IP source address: %s",
  317. inet_ntoa(value_p->address));
  318. trace_log(PPPiface, "    making IP destination address %s",
  319. inet_ntoa(value_p->other));
  320. }
  321. #endif
  322. break;
  323. case IPCP_COMPRESS:
  324. cp = put16(cp, value_p->compression);
  325. toss -= 2;
  326. #ifdef PPP_DEBUG_OPTIONS
  327. if (PPPtrace & PPP_DEBUG_OPTIONS)
  328. trace_log(PPPiface, "    making IP compression 0x%04x",
  329. value_p->compression);
  330. #endif
  331. if ( value_p->compression == PPP_COMPR_PROTOCOL ) {
  332. *cp++ = value_p->slots - 1;
  333. *cp++ = value_p->slot_compress;
  334. toss -= 2;
  335. #ifdef PPP_DEBUG_OPTIONS
  336. if (PPPtrace & PPP_DEBUG_OPTIONS)
  337. trace_log(PPPiface, "    with IP compression slots %d, flag %x",
  338. value_p->slots,
  339. value_p->slot_compress);
  340. #endif
  341. }
  342. break;
  343. default:
  344. #ifdef PPP_DEBUG_OPTIONS
  345. if (PPPtrace & PPP_DEBUG_OPTIONS)
  346. trace_log(PPPiface, "    making unimplemented type %d", o_type);
  347. #endif
  348. break;
  349. };
  350. while ( toss-- > 0 ) {
  351. *cp++ = pullchar(copy_bpp);
  352. }
  353. bp->cnt += o_length;
  354. append(bpp, &bp);
  355. }
  356. /************************************************************************/
  357. /* Build a list of options */
  358. static void
  359. ipcp_makeoptions(bpp, value_p, negotiating)
  360. struct mbuf **bpp;
  361. struct ipcp_value_s *value_p;
  362. uint16 negotiating;
  363. {
  364. register int o_type;
  365. PPP_DEBUG_ROUTINES("ipcp_makeoptions()");
  366. for ( o_type = 1; o_type <= IPCP_OPTION_LIMIT; o_type++ ) {
  367. if (negotiating & (1 << o_type)) {
  368. ipcp_option( bpp, value_p,
  369. o_type, option_length[ o_type ], NULL);
  370. }
  371. }
  372. }
  373. /************************************************************************/
  374. /* Build a request to send to remote host */
  375. static struct mbuf *
  376. ipcp_makereq(fsm_p)
  377. struct fsm_s *fsm_p;
  378. {
  379. struct ipcp_s *ipcp_p = fsm_p->pdv;
  380. struct mbuf *req_bp = NULL;
  381. PPP_DEBUG_ROUTINES("ipcp_makereq()");
  382. ipcp_makeoptions( &req_bp, &(ipcp_p->local.work),
  383. ipcp_p->local.work.negotiate );
  384. return(req_bp);
  385. }
  386. /************************************************************************/
  387. /* Check the options, updating the working values.
  388.  * Returns -1 if ran out of data, ACK/NAK/REJ as appropriate.
  389.  */
  390. static int
  391. ipcp_check( bpp, ipcp_p, side_p, option_p, request )
  392. struct mbuf **bpp;
  393. struct ipcp_s *ipcp_p;
  394. struct ipcp_side_s *side_p;
  395. struct option_hdr *option_p;
  396. int request;
  397. {
  398. int toss = option_p->len - OPTION_HDR_LEN;
  399. int option_result = CONFIG_ACK; /* Assume good values */
  400. int test;
  401. switch(option_p->type) {
  402. case IPCP_ADDRESS:
  403. side_p->work.address = pull32(bpp);
  404. side_p->work.other = pull32(bpp);
  405. toss -= 8;
  406. #ifdef PPP_DEBUG_OPTIONS
  407. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  408. trace_log(PPPiface, "    checking IP source address: %s",
  409. inet_ntoa(side_p->work.address));
  410. trace_log(PPPiface, "    checking IP destination address %s",
  411. inet_ntoa(side_p->work.other));
  412. }
  413. #endif
  414. if ( !request ) {
  415. /* override any undesirable changes */
  416. if (ipcp_p->remote.want.address != 0L) {
  417. ipcp_p->local.work.other
  418. = ipcp_p->remote.want.address;
  419. }
  420. if (ipcp_p->local.want.address != 0L) {
  421. ipcp_p->local.work.address
  422. = ipcp_p->local.want.address;
  423. }
  424. break;
  425. }
  426. /* Ensure that addresses match */
  427. if (ipcp_p->remote.work.address == ipcp_p->remote.want.address) {
  428. if (ipcp_p->remote.want.address == 0L) {
  429. /* don't know address either */
  430. option_result = CONFIG_REJ;
  431. }
  432. } else if (ipcp_p->remote.want.address == 0L) {
  433. ipcp_p->local.work.other = ipcp_p->remote.work.address;
  434. } else {
  435. ipcp_p->remote.work.address = ipcp_p->remote.want.address;
  436. option_result = CONFIG_NAK;
  437. }
  438. if (ipcp_p->remote.work.other == ipcp_p->local.want.address) {
  439. if (ipcp_p->local.want.address == 0L) {
  440. /* don't know address either */
  441. option_result = CONFIG_REJ;
  442. }
  443. } else if (ipcp_p->local.want.address == 0L) {
  444. ipcp_p->local.work.address = ipcp_p->remote.work.other;
  445. } else {
  446. option_result = CONFIG_NAK;
  447. ipcp_p->remote.work.other = ipcp_p->local.want.address;
  448. }
  449. break;
  450. case IPCP_COMPRESS:
  451. side_p->work.compression = pull16(bpp);
  452. toss -= 2;
  453. #ifdef PPP_DEBUG_OPTIONS
  454. if (PPPtrace & PPP_DEBUG_OPTIONS)
  455. trace_log(PPPiface, "    checking IP compression 0x%04x",
  456. side_p->work.compression);
  457. #endif
  458. /* Check if requested type is acceptable */
  459. switch ( side_p->work.compression ) {
  460. case PPP_COMPR_PROTOCOL:
  461. if ( (test = pullchar(bpp)) == -1 ) {
  462. return -1;
  463. }
  464. if ( (side_p->work.slots = test + 1) < IPCP_SLOT_LO) {
  465. side_p->work.slots = IPCP_SLOT_LO;
  466. option_result = CONFIG_NAK;
  467. } else if (side_p->work.slots > IPCP_SLOT_HI) {
  468. side_p->work.slots = IPCP_SLOT_HI;
  469. option_result = CONFIG_NAK;
  470. }
  471. if ( (test = pullchar(bpp)) == -1 ) {
  472. return -1;
  473. }
  474. if ( (side_p->work.slot_compress = test) > 1 ) {
  475. side_p->work.slot_compress = 1;
  476. option_result = CONFIG_NAK;
  477. }
  478. toss -= 2;
  479. #ifdef PPP_DEBUG_OPTIONS
  480. if (PPPtrace & PPP_DEBUG_OPTIONS)
  481. trace_log(PPPiface, "    with IP compression slots %d, flag %x",
  482. side_p->work.slots,
  483. side_p->work.slot_compress);
  484. #endif
  485. break;
  486. default:
  487. if ( side_p->want.negotiate & IPCP_N_COMPRESS ) {
  488. side_p->work.compression = side_p->want.compression;
  489. side_p->work.slots = side_p->want.slots;
  490. side_p->work.slot_compress = side_p->want.slot_compress;
  491. } else {
  492. side_p->work.compression = PPP_COMPR_PROTOCOL;
  493. side_p->work.slots = IPCP_SLOT_DEFAULT;
  494. side_p->work.slot_compress = IPCP_SLOT_COMPRESS;
  495. }
  496. option_result = CONFIG_NAK;
  497. break;
  498. };
  499. break;
  500. default:
  501. option_result = CONFIG_REJ;
  502. break;
  503. };
  504. if (option_p->type > IPCP_OPTION_LIMIT
  505.  || !(side_p->will_negotiate & (1 << option_p->type))) {
  506. option_result = CONFIG_REJ;
  507. }
  508. if ( toss < 0 )
  509. return -1;
  510. if ( !request  &&  toss > 0 ) {
  511. /* toss extra bytes in option */
  512. while( toss-- > 0 ) {
  513. if ( pullchar(bpp) == -1 )
  514. return -1;
  515. }
  516. }
  517. return (option_result);
  518. }
  519. /************************************************************************/
  520. /* Check options requested by the remote host */
  521. static int
  522. ipcp_request(
  523. struct fsm_s *fsm_p,
  524. struct config_hdr *config,
  525. struct mbuf **data
  526. ){
  527. struct ipcp_s *ipcp_p = fsm_p->pdv;
  528. int32 signed_length = config->len;
  529. struct mbuf *reply_bp = NULL; /* reply packet */
  530. int reply_result = CONFIG_ACK; /* reply to request */
  531. uint16 desired; /* desired to negotiate */
  532. struct option_hdr option; /* option header storage */
  533. int option_result; /* option reply */
  534. PPP_DEBUG_ROUTINES("ipcp_request()");
  535. ipcp_p->remote.work.negotiate = FALSE; /* clear flags */
  536. /* Process options requested by remote host */
  537. while (signed_length > 0  &&  ntohopt(&option, data) != -1) {
  538. if ((signed_length -= option.len) < 0) {
  539. PPP_DEBUG_CHECKS("IPCP REQ: bad header length");
  540. free_p(data);
  541. free_p(&reply_bp);
  542. return -1;
  543. }
  544. if ( ( option_result = ipcp_check( data, ipcp_p,
  545. &(ipcp_p->remote), &option, TRUE ) ) == -1 ) {
  546. PPP_DEBUG_CHECKS("IPCP REQ: ran out of data");
  547. free_p(data);
  548. free_p(&reply_bp);
  549. return -1;
  550. }
  551. #ifdef PPP_DEBUG_OPTIONS
  552. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  553. trace_log(PPPiface, "IPCP REQ: result %s, option %d, length %d",
  554. fsmCodes[option_result],
  555. option.type,
  556. option.len);
  557. }
  558. #endif
  559. if ( option_result < reply_result ) {
  560. continue;
  561. } else if ( option_result > reply_result ) {
  562. /* Discard current list of replies */
  563. free_p(&reply_bp);
  564. reply_bp = NULL;
  565. reply_result = option_result;
  566. }
  567. /* remember that we processed option */
  568. if ( option_result != CONFIG_REJ
  569.  && option.type <= IPCP_OPTION_LIMIT ) {
  570. ipcp_p->remote.work.negotiate |= (1 << option.type);
  571. }
  572. /* Add option response to the return list */
  573. ipcp_option( &reply_bp, &(ipcp_p->remote.work),
  574. option.type, option.len, data );
  575. }
  576. /* Now check for any missing options which are desired */
  577. if ( fsm_p->retry_nak > 0
  578.  &&  (desired = ipcp_p->remote.want.negotiate
  579.        & ~ipcp_p->remote.work.negotiate) != 0 ) {
  580. switch ( reply_result ) {
  581. case CONFIG_ACK:
  582. free_p(&reply_bp);
  583. reply_bp = NULL;
  584. reply_result = CONFIG_NAK;
  585. /* fallthru */
  586. case CONFIG_NAK:
  587. ipcp_makeoptions( &reply_bp, &(ipcp_p->remote.want),
  588. desired );
  589. fsm_p->retry_nak--;
  590. break;
  591. case CONFIG_REJ:
  592. /* do nothing */
  593. break;
  594. };
  595. } else if ( reply_result == CONFIG_NAK ) {
  596. /* if too many NAKs, reject instead */
  597. if ( fsm_p->retry_nak > 0 )
  598. fsm_p->retry_nak--;
  599. else
  600. reply_result = CONFIG_REJ;
  601. }
  602. /* Send ACK/NAK/REJ to remote host */
  603. fsm_send(fsm_p, reply_result, config->id, &reply_bp);
  604. free_p(data);
  605. return (reply_result != CONFIG_ACK);
  606. }
  607. /************************************************************************/
  608. /* Process configuration ACK sent by remote host */
  609. static int
  610. ipcp_ack(
  611. struct fsm_s *fsm_p,
  612. struct config_hdr *config,
  613. struct mbuf **data
  614. ){
  615. struct mbuf *req_bp;
  616. int error = FALSE;
  617. PPP_DEBUG_ROUTINES("ipcp_ack()");
  618. /* ID field must match last request we sent */
  619. if (config->id != fsm_p->lastid) {
  620. PPP_DEBUG_CHECKS("IPCP ACK: wrong ID");
  621. free_p(data);
  622. return -1;
  623. }
  624. /* Get a copy of last request we sent */
  625. req_bp = ipcp_makereq(fsm_p);
  626. /* Overall buffer length should match */
  627. if (config->len != len_p(req_bp)) {
  628. PPP_DEBUG_CHECKS("IPCP ACK: buffer length mismatch");
  629. error = TRUE;
  630. } else {
  631. register int req_char;
  632. register int ack_char;
  633. /* Each byte should match */
  634. while ((req_char = pullchar(&req_bp)) != -1) {
  635. if ((ack_char = pullchar(data)) == -1
  636.  || ack_char != req_char ) {
  637. PPP_DEBUG_CHECKS("IPCP ACK: data mismatch");
  638. error = TRUE;
  639. break;
  640. }
  641. }
  642. }
  643. free_p(&req_bp);
  644. free_p(data);
  645. if (error) {
  646. return -1;
  647. }
  648. PPP_DEBUG_CHECKS("IPCP ACK: valid");
  649. return 0;
  650. }
  651. /************************************************************************/
  652. /* Process configuration NAK sent by remote host */
  653. static int
  654. ipcp_nak(
  655. struct fsm_s *fsm_p,
  656. struct config_hdr *config,
  657. struct mbuf **data
  658. ){
  659. struct ipcp_s *ipcp_p = fsm_p->pdv;
  660. struct ipcp_side_s *local_p = &(ipcp_p->local);
  661. int32 signed_length = config->len;
  662. struct option_hdr option;
  663. int last_option = 0;
  664. int result;
  665. PPP_DEBUG_ROUTINES("ipcp_nak()");
  666. /* ID field must match last request we sent */
  667. if (config->id != fsm_p->lastid) {
  668. PPP_DEBUG_CHECKS("IPCP NAK: wrong ID");
  669. free_p(data);
  670. return -1;
  671. }
  672. /* First, process in order.  Then, process extra "important" options */
  673. while (signed_length > 0  &&  ntohopt(&option, data) != -1) {
  674. if ((signed_length -= option.len) < 0) {
  675. PPP_DEBUG_CHECKS("IPCP NAK: bad header length");
  676. free_p(data);
  677. return -1;
  678. }
  679. if ( option.type > IPCP_OPTION_LIMIT ) {
  680. PPP_DEBUG_CHECKS("IPCP NAK: option out of range");
  681. } else if ( option.type < last_option
  682.  || !(local_p->work.negotiate & (1 << option.type)) ) {
  683. if (local_p->work.negotiate & (1 << option.type)) {
  684. PPP_DEBUG_CHECKS("IPCP NAK: option out of order");
  685. free_p(data);
  686. return -1; /* was requested */
  687. }
  688. local_p->work.negotiate |= (1 << option.type);
  689. last_option = IPCP_OPTION_LIMIT + 1;
  690. } else {
  691. last_option = option.type;
  692. }
  693. if ( ( result = ipcp_check( data, ipcp_p,
  694. local_p, &option, FALSE ) ) == -1 ) {
  695. PPP_DEBUG_CHECKS("IPCP NAK: ran out of data");
  696. free_p(data);
  697. return -1;
  698. }
  699. /* update the negotiation status */
  700. if ( result == CONFIG_REJ
  701.   && option.type <= IPCP_OPTION_LIMIT ) {
  702. local_p->work.negotiate &= ~(1 << option.type);
  703. }
  704. }
  705. PPP_DEBUG_CHECKS("IPCP NAK: valid");
  706. free_p(data);
  707. return 0;
  708. }
  709. /************************************************************************/
  710. /* Process configuration reject sent by remote host */
  711. static int
  712. ipcp_reject(
  713. struct fsm_s *fsm_p,
  714. struct config_hdr *config,
  715. struct mbuf **data
  716. ){
  717. struct ipcp_s *ipcp_p = fsm_p->pdv;
  718. struct ipcp_side_s *local_p = &(ipcp_p->local);
  719. int32 signed_length = config->len;
  720. struct option_hdr option;
  721. int last_option = 0;
  722. PPP_DEBUG_ROUTINES("ipcp_reject()");
  723. /* ID field must match last request we sent */
  724. if (config->id != fsm_p->lastid) {
  725. PPP_DEBUG_CHECKS("IPCP REJ: wrong ID");
  726. free_p(data);
  727. return -1;
  728. }
  729. /* Process in order, checking for errors */
  730. while (signed_length > 0  &&  ntohopt(&option, data) != -1) {
  731. register int k;
  732. if ((signed_length -= option.len) < 0) {
  733. PPP_DEBUG_CHECKS("IPCP REJ: bad header length");
  734. free_p(data);
  735. return -1;
  736. }
  737. if ( option.type > IPCP_OPTION_LIMIT ) {
  738. PPP_DEBUG_CHECKS("IPCP REJ: option out of range");
  739. } else if (option.type < last_option
  740.  || !(local_p->work.negotiate & (1 << option.type))) {
  741. PPP_DEBUG_CHECKS("IPCP REJ: option out of order");
  742. free_p(data);
  743. return -1;
  744. }
  745. for ( k = option.len - OPTION_HDR_LEN; k-- > 0; ) {
  746. if ( pullchar(data) == -1 ) {
  747. PPP_DEBUG_CHECKS("IPCP REJ: ran out of data");
  748. free_p(data);
  749. return -1;
  750. }
  751. }
  752. last_option = option.type;
  753. if ( option.type <= IPCP_OPTION_LIMIT ) {
  754. local_p->work.negotiate &= ~(1 << option.type);
  755. }
  756. }
  757. PPP_DEBUG_CHECKS("IPCP REJ: valid");
  758. free_p(data);
  759. return 0;
  760. }
  761. /************************************************************************/
  762. /* I N I T I A L I Z A T I O N */
  763. /************************************************************************/
  764. /* Reset configuration options before request */
  765. static void
  766. ipcp_reset(fsm_p)
  767. struct fsm_s *fsm_p;
  768. {
  769. struct ipcp_s *ipcp_p = fsm_p->pdv;
  770. PPP_DEBUG_ROUTINES("ipcp_reset()");
  771. ASSIGN( ipcp_p->local.work, ipcp_p->local.want );
  772. ipcp_p->local.work.other = ipcp_p->remote.want.address;
  773. ipcp_p->local.will_negotiate |= ipcp_p->local.want.negotiate;
  774. ipcp_p->remote.work.negotiate = FALSE;
  775. ipcp_p->remote.will_negotiate |= ipcp_p->remote.want.negotiate;
  776. }
  777. /************************************************************************/
  778. /* After termination */
  779. static void
  780. ipcp_stopping(fsm_p)
  781. struct fsm_s *fsm_p;
  782. {
  783. PPP_DEBUG_ROUTINES("ipcp_stopping()");
  784. }
  785. /************************************************************************/
  786. /* Close IPCP */
  787. static void
  788. ipcp_closing(fsm_p)
  789. struct fsm_s *fsm_p;
  790. {
  791. struct ipcp_s *ipcp_p =  fsm_p->pdv;
  792. /* free old slhc configuration, if any */
  793. slhc_free( ipcp_p->slhcp );
  794. ipcp_p->slhcp = NULL;
  795. #ifdef notdef
  796. if (PPPtrace > 1)
  797. trace_log(PPPiface,"%s PPP/IPCP Drop route to peer (%s)",
  798. ifp->name,
  799. inet_ntoa(ipcp_p->local.work.other);
  800. rt_drop(ipcp_p->local.work.other, (unsigned int)32);
  801. #endif
  802. }
  803. /************************************************************************/
  804. /* configuration negotiation complete */
  805. static void
  806. ipcp_opening(fsm_p)
  807. struct fsm_s *fsm_p;
  808. {
  809. struct ipcp_s *ipcp_p =  fsm_p->pdv;
  810. struct iface *ifp =  fsm_p->ppp_p->iface;
  811. int32 address = ipcp_p->local.work.address;
  812. int rslots = 0;
  813. int tslots = 0;
  814. /* Set our IP address to reflect negotiated option */
  815. if (address != ifp->addr) {
  816. /* address not the same as last time */
  817. if (Ip_addr == 0L) {
  818. /* no global address */
  819. Ip_addr = address;
  820. } else if ( Ip_addr == ifp->addr ) {
  821. /* global was same as local; must be replaced */
  822. /* !!! TO DO: reset tcp connections */
  823. Ip_addr = address;
  824. }
  825. ifp->addr = address;
  826. if (PPPtrace > 1)
  827. trace_log(PPPiface,"%s PPP/IPCP Setting new IP address: %s",
  828. ifp->name,
  829. inet_ntoa(address));
  830. }
  831. #ifdef notdef
  832. rt_add(ipcp_p->local.work.other, (unsigned int)32, (int32)0,
  833. ifp, (int32)1, (int32)0, (char)1);
  834. if (PPPtrace > 1)
  835. trace_log(PPPiface,"%s PPP/IPCP Add route to peer (%s)",
  836. ifp->name,
  837. inet_ntoa(ipcp_p->local.work.other);
  838. #endif
  839. /* free old slhc configuration, if any */
  840. slhc_free( ipcp_p->slhcp );
  841. ipcp_p->slhcp = NULL;
  842. if (ipcp_p->local.work.negotiate & IPCP_N_COMPRESS) {
  843. rslots = ipcp_p->local.work.slots;
  844. }
  845. if (ipcp_p->remote.work.negotiate & IPCP_N_COMPRESS) {
  846. tslots = ipcp_p->remote.work.slots;
  847. }
  848. if ( rslots != 0 || tslots != 0 ) {
  849. ipcp_p->slhcp = slhc_init( rslots, tslots );
  850. if (PPPtrace > 1)
  851. trace_log(PPPiface,"%s PPP/IPCP Compression enabled;"
  852. " Recv slots = %d, flag = %x;"
  853. " Xmit slots = %d, flag = %x",
  854. ifp->name,
  855. rslots,
  856. ipcp_p->local.work.slot_compress,
  857. tslots,
  858. ipcp_p->remote.work.slot_compress);
  859. }
  860. }
  861. /************************************************************************/
  862. /* Check the address against all other assigned addresses */
  863. static int32
  864. ipcp_addr_idle(addr)
  865. int32 addr;
  866. {
  867. struct iface *ifp;
  868. /* Check if peer IP address is already in use on another interface */
  869. /* !!! need to look at *remote* address, not local! */
  870. for (ifp=Ifaces; ifp != NULL; ifp = ifp->next) {
  871. if (ifp->addr == addr)
  872. return 0L;
  873. }
  874. return addr;
  875. }
  876. /************************************************************************/
  877. /* Assign the next unused address from a pool */
  878. static int32
  879. ipcp_poolnext(ipcp_p)
  880. struct ipcp_s *ipcp_p;
  881. {
  882. int32 i = 1L + ipcp_p->peer_max - ipcp_p->peer_min;
  883. int32 nextaddr = 0L;
  884. while ( i-- > 0  &&  nextaddr == 0L ) {
  885. if (++ipcp_p->local.want.other < ipcp_p->peer_min
  886.  || ipcp_p->local.want.other > ipcp_p->peer_max)
  887. ipcp_p->local.want.other = ipcp_p->peer_min;
  888. nextaddr = ipcp_addr_idle(ipcp_p->local.want.other);
  889. }
  890. return(nextaddr);
  891. }
  892. /************************************************************************/
  893. /* Check if we have a specific IP address to assign to remote peer host */
  894. /* !!! TO DO: subnet mask, and routing */
  895. static int32
  896. ipcp_lookuppeer(peerid)
  897. char *peerid;
  898. {
  899. char *buf;
  900. int32 peer_addr = 0L;
  901. if (peerid == NULL)
  902. return 0L;
  903. if ( (buf = userlookup( peerid, NULL, NULL,
  904. NULL, &peer_addr )) != NULL ) {
  905. free(buf);
  906. }
  907. return(peer_addr);
  908. }
  909. /************************************************************************/
  910. /* Prepare to begin configuration exchange */
  911. static void
  912. ipcp_starting(fsm_p)
  913. struct fsm_s *fsm_p;
  914. {
  915. struct ipcp_s *ipcp_p = fsm_p->pdv;
  916. PPP_DEBUG_ROUTINES("ipcp_starting()");
  917. /* If not already set, and we know the name of the peer,
  918.  * look in login file for an address
  919.  */
  920. if ( ipcp_p->remote.want.address == 0L ){
  921. ipcp_p->remote.want.address
  922. = ipcp_lookuppeer(fsm_p->ppp_p->peername);
  923. }
  924. /* If available, get next address from PPP pool */
  925. if ((ipcp_p->remote.want.address == 0L)
  926.  && (ipcp_p->peer_min != 0L)) {
  927. ipcp_p->remote.want.address = ipcp_poolnext(ipcp_p);
  928. }
  929. ipcp_p->local.want.address = fsm_p->ppp_p->iface->addr;
  930. }
  931. /************************************************************************/
  932. static void
  933. ipcp_free(fsm_p)
  934. struct fsm_s *fsm_p;
  935. {
  936. struct ipcp_s *ipcp_p = fsm_p->pdv;
  937. slhc_free( ipcp_p->slhcp );
  938. }
  939. /* Initialize configuration structure */
  940. void
  941. ipcp_init(ppp_p)
  942. struct ppp_s *ppp_p;
  943. {
  944. struct fsm_s *fsm_p = &(ppp_p->fsm[IPcp]);
  945. struct ipcp_s *ipcp_p;
  946. PPPtrace = ppp_p->trace;
  947. PPPiface = ppp_p->iface;
  948. PPP_DEBUG_ROUTINES("ipcp_init()");
  949. fsm_p->ppp_p = ppp_p;
  950. fsm_p->pdc = &ipcp_constants;
  951. fsm_p->pdv =
  952. ipcp_p = callocw(1,sizeof(struct ipcp_s));
  953. /* Set option parameters to first request defaults */
  954. ASSIGN( ipcp_p->local.want, ipcp_default );
  955. ipcp_p->local.will_negotiate = ipcp_negotiate;
  956. ASSIGN( ipcp_p->remote.want, ipcp_default );
  957. ASSIGN( ipcp_p->remote.work, ipcp_default);
  958. ipcp_p->remote.will_negotiate = ipcp_negotiate;
  959. fsm_init(fsm_p);
  960. }