BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * ipcp.c - PPP IP Control Protocol. |
||
3 | * |
||
4 | * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. |
||
5 | * |
||
6 | * Redistribution and use in source and binary forms, with or without |
||
7 | * modification, are permitted provided that the following conditions |
||
8 | * are met: |
||
9 | * |
||
10 | * 1. Redistributions of source code must retain the above copyright |
||
11 | * notice, this list of conditions and the following disclaimer. |
||
12 | * |
||
13 | * 2. Redistributions in binary form must reproduce the above copyright |
||
14 | * notice, this list of conditions and the following disclaimer in |
||
15 | * the documentation and/or other materials provided with the |
||
16 | * distribution. |
||
17 | * |
||
18 | * 3. The name "Carnegie Mellon University" must not be used to |
||
19 | * endorse or promote products derived from this software without |
||
20 | * prior written permission. For permission or any legal |
||
21 | * details, please contact |
||
22 | * Office of Technology Transfer |
||
23 | * Carnegie Mellon University |
||
24 | * 5000 Forbes Avenue |
||
25 | * Pittsburgh, PA 15213-3890 |
||
26 | * (412) 268-4387, fax: (412) 268-7395 |
||
27 | * tech-transfer@andrew.cmu.edu |
||
28 | * |
||
29 | * 4. Redistributions of any form whatsoever must retain the following |
||
30 | * acknowledgment: |
||
31 | * "This product includes software developed by Computing Services |
||
32 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." |
||
33 | * |
||
34 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO |
||
35 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
||
36 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE |
||
37 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||
38 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN |
||
39 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
||
40 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||
41 | */ |
||
42 | |||
43 | #include "netif/ppp/ppp_opts.h" |
||
44 | #if PPP_SUPPORT && PPP_IPV4_SUPPORT /* don't build if not configured for use in lwipopts.h */ |
||
45 | |||
46 | /* |
||
47 | * @todo: |
||
48 | */ |
||
49 | |||
50 | #if 0 /* UNUSED */ |
||
51 | #include <stdio.h> |
||
52 | #include <string.h> |
||
53 | #include <stdlib.h> |
||
54 | #include <netdb.h> |
||
55 | #include <sys/param.h> |
||
56 | #include <sys/types.h> |
||
57 | #include <sys/socket.h> |
||
58 | #include <netinet/in.h> |
||
59 | #include <arpa/inet.h> |
||
60 | #endif /* UNUSED */ |
||
61 | |||
62 | #include "netif/ppp/ppp_impl.h" |
||
63 | |||
64 | #include "netif/ppp/fsm.h" |
||
65 | #include "netif/ppp/ipcp.h" |
||
66 | |||
67 | #if 0 /* UNUSED */ |
||
68 | /* global vars */ |
||
69 | u32_t netmask = 0; /* IP netmask to set on interface */ |
||
70 | #endif /* UNUSED */ |
||
71 | |||
72 | #if 0 /* UNUSED */ |
||
73 | bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */ |
||
74 | #endif /* UNUSED */ |
||
75 | |||
76 | #if 0 /* moved to ppp_settings */ |
||
77 | bool noremoteip = 0; /* Let him have no IP address */ |
||
78 | #endif /* moved to ppp_setting */ |
||
79 | |||
80 | #if 0 /* UNUSED */ |
||
81 | /* Hook for a plugin to know when IP protocol has come up */ |
||
82 | void (*ip_up_hook) (void) = NULL; |
||
83 | |||
84 | /* Hook for a plugin to know when IP protocol has come down */ |
||
85 | void (*ip_down_hook) (void) = NULL; |
||
86 | |||
87 | /* Hook for a plugin to choose the remote IP address */ |
||
88 | void (*ip_choose_hook) (u32_t *) = NULL; |
||
89 | #endif /* UNUSED */ |
||
90 | |||
91 | #if PPP_NOTIFY |
||
92 | /* Notifiers for when IPCP goes up and down */ |
||
93 | struct notifier *ip_up_notifier = NULL; |
||
94 | struct notifier *ip_down_notifier = NULL; |
||
95 | #endif /* PPP_NOTIFY */ |
||
96 | |||
97 | /* local vars */ |
||
98 | #if 0 /* moved to ppp_pcb */ |
||
99 | static int default_route_set[NUM_PPP]; /* Have set up a default route */ |
||
100 | static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */ |
||
101 | static int ipcp_is_up; /* have called np_up() */ |
||
102 | static int ipcp_is_open; /* haven't called np_finished() */ |
||
103 | static bool ask_for_local; /* request our address from peer */ |
||
104 | #endif /* moved to ppp_pcb */ |
||
105 | #if 0 /* UNUSED */ |
||
106 | static char vj_value[8]; /* string form of vj option value */ |
||
107 | static char netmask_str[20]; /* string form of netmask value */ |
||
108 | #endif /* UNUSED */ |
||
109 | |||
110 | /* |
||
111 | * Callbacks for fsm code. (CI = Configuration Information) |
||
112 | */ |
||
113 | static void ipcp_resetci(fsm *f); /* Reset our CI */ |
||
114 | static int ipcp_cilen(fsm *f); /* Return length of our CI */ |
||
115 | static void ipcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */ |
||
116 | static int ipcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ |
||
117 | static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject);/* Peer nak'd our CI */ |
||
118 | static int ipcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ |
||
119 | static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */ |
||
120 | static void ipcp_up(fsm *f); /* We're UP */ |
||
121 | static void ipcp_down(fsm *f); /* We're DOWN */ |
||
122 | static void ipcp_finished(fsm *f); /* Don't need lower layer */ |
||
123 | |||
124 | static const fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ |
||
125 | ipcp_resetci, /* Reset our Configuration Information */ |
||
126 | ipcp_cilen, /* Length of our Configuration Information */ |
||
127 | ipcp_addci, /* Add our Configuration Information */ |
||
128 | ipcp_ackci, /* ACK our Configuration Information */ |
||
129 | ipcp_nakci, /* NAK our Configuration Information */ |
||
130 | ipcp_rejci, /* Reject our Configuration Information */ |
||
131 | ipcp_reqci, /* Request peer's Configuration Information */ |
||
132 | ipcp_up, /* Called when fsm reaches OPENED state */ |
||
133 | ipcp_down, /* Called when fsm leaves OPENED state */ |
||
134 | NULL, /* Called when we want the lower layer up */ |
||
135 | ipcp_finished, /* Called when we want the lower layer down */ |
||
136 | NULL, /* Called when Protocol-Reject received */ |
||
137 | NULL, /* Retransmission is necessary */ |
||
138 | NULL, /* Called to handle protocol-specific codes */ |
||
139 | "IPCP" /* String name of protocol */ |
||
140 | }; |
||
141 | |||
142 | /* |
||
143 | * Command-line options. |
||
144 | */ |
||
145 | #if PPP_OPTIONS |
||
146 | static int setvjslots (char **); |
||
147 | static int setdnsaddr (char **); |
||
148 | static int setwinsaddr (char **); |
||
149 | static int setnetmask (char **); |
||
150 | int setipaddr (char *, char **, int); |
||
151 | |||
152 | static void printipaddr (option_t *, void (*)(void *, char *,...),void *); |
||
153 | |||
154 | static option_t ipcp_option_list[] = { |
||
155 | { "noip", o_bool, &ipcp_protent.enabled_flag, |
||
156 | "Disable IP and IPCP" }, |
||
157 | { "-ip", o_bool, &ipcp_protent.enabled_flag, |
||
158 | "Disable IP and IPCP", OPT_ALIAS }, |
||
159 | |||
160 | { "novj", o_bool, &ipcp_wantoptions[0].neg_vj, |
||
161 | "Disable VJ compression", OPT_A2CLR, &ipcp_allowoptions[0].neg_vj }, |
||
162 | { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj, |
||
163 | "Disable VJ compression", OPT_ALIAS | OPT_A2CLR, |
||
164 | &ipcp_allowoptions[0].neg_vj }, |
||
165 | |||
166 | { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag, |
||
167 | "Disable VJ connection-ID compression", OPT_A2CLR, |
||
168 | &ipcp_allowoptions[0].cflag }, |
||
169 | { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag, |
||
170 | "Disable VJ connection-ID compression", OPT_ALIAS | OPT_A2CLR, |
||
171 | &ipcp_allowoptions[0].cflag }, |
||
172 | |||
173 | { "vj-max-slots", o_special, (void *)setvjslots, |
||
174 | "Set maximum VJ header slots", |
||
175 | OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value }, |
||
176 | |||
177 | { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local, |
||
178 | "Accept peer's address for us", 1 }, |
||
179 | { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote, |
||
180 | "Accept peer's address for it", 1 }, |
||
181 | |||
182 | { "ipparam", o_string, &ipparam, |
||
183 | "Set ip script parameter", OPT_PRIO }, |
||
184 | |||
185 | { "noipdefault", o_bool, &disable_defaultip, |
||
186 | "Don't use name for default IP adrs", 1 }, |
||
187 | |||
188 | { "ms-dns", 1, (void *)setdnsaddr, |
||
189 | "DNS address for the peer's use" }, |
||
190 | { "ms-wins", 1, (void *)setwinsaddr, |
||
191 | "Nameserver for SMB over TCP/IP for peer" }, |
||
192 | |||
193 | { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime, |
||
194 | "Set timeout for IPCP", OPT_PRIO }, |
||
195 | { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits, |
||
196 | "Set max #xmits for term-reqs", OPT_PRIO }, |
||
197 | { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits, |
||
198 | "Set max #xmits for conf-reqs", OPT_PRIO }, |
||
199 | { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops, |
||
200 | "Set max #conf-naks for IPCP", OPT_PRIO }, |
||
201 | |||
202 | { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route, |
||
203 | "Add default route", OPT_ENABLE|1, &ipcp_allowoptions[0].default_route }, |
||
204 | { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route, |
||
205 | "disable defaultroute option", OPT_A2CLR, |
||
206 | &ipcp_wantoptions[0].default_route }, |
||
207 | { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route, |
||
208 | "disable defaultroute option", OPT_ALIAS | OPT_A2CLR, |
||
209 | &ipcp_wantoptions[0].default_route }, |
||
210 | |||
211 | { "replacedefaultroute", o_bool, |
||
212 | &ipcp_wantoptions[0].replace_default_route, |
||
213 | "Replace default route", 1 |
||
214 | }, |
||
215 | { "noreplacedefaultroute", o_bool, |
||
216 | &ipcp_allowoptions[0].replace_default_route, |
||
217 | "Never replace default route", OPT_A2COPY, |
||
218 | &ipcp_wantoptions[0].replace_default_route }, |
||
219 | { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp, |
||
220 | "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp }, |
||
221 | { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, |
||
222 | "disable proxyarp option", OPT_A2CLR, |
||
223 | &ipcp_wantoptions[0].proxy_arp }, |
||
224 | { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, |
||
225 | "disable proxyarp option", OPT_ALIAS | OPT_A2CLR, |
||
226 | &ipcp_wantoptions[0].proxy_arp }, |
||
227 | |||
228 | { "usepeerdns", o_bool, &usepeerdns, |
||
229 | "Ask peer for DNS address(es)", 1 }, |
||
230 | |||
231 | { "netmask", o_special, (void *)setnetmask, |
||
232 | "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str }, |
||
233 | |||
234 | { "ipcp-no-addresses", o_bool, &ipcp_wantoptions[0].old_addrs, |
||
235 | "Disable old-style IP-Addresses usage", OPT_A2CLR, |
||
236 | &ipcp_allowoptions[0].old_addrs }, |
||
237 | { "ipcp-no-address", o_bool, &ipcp_wantoptions[0].neg_addr, |
||
238 | "Disable IP-Address usage", OPT_A2CLR, |
||
239 | &ipcp_allowoptions[0].neg_addr }, |
||
240 | |||
241 | { "noremoteip", o_bool, &noremoteip, |
||
242 | "Allow peer to have no IP address", 1 }, |
||
243 | |||
244 | { "nosendip", o_bool, &ipcp_wantoptions[0].neg_addr, |
||
245 | "Don't send our IP address to peer", OPT_A2CLR, |
||
246 | &ipcp_wantoptions[0].old_addrs}, |
||
247 | |||
248 | { "IP addresses", o_wild, (void *) &setipaddr, |
||
249 | "set local and remote IP addresses", |
||
250 | OPT_NOARG | OPT_A2PRINTER, (void *) &printipaddr }, |
||
251 | |||
252 | { NULL } |
||
253 | }; |
||
254 | #endif /* PPP_OPTIONS */ |
||
255 | |||
256 | /* |
||
257 | * Protocol entry points from main code. |
||
258 | */ |
||
259 | static void ipcp_init(ppp_pcb *pcb); |
||
260 | static void ipcp_open(ppp_pcb *pcb); |
||
261 | static void ipcp_close(ppp_pcb *pcb, const char *reason); |
||
262 | static void ipcp_lowerup(ppp_pcb *pcb); |
||
263 | static void ipcp_lowerdown(ppp_pcb *pcb); |
||
264 | static void ipcp_input(ppp_pcb *pcb, u_char *p, int len); |
||
265 | static void ipcp_protrej(ppp_pcb *pcb); |
||
266 | #if PRINTPKT_SUPPORT |
||
267 | static int ipcp_printpkt(const u_char *p, int plen, |
||
268 | void (*printer) (void *, const char *, ...), void *arg); |
||
269 | #endif /* PRINTPKT_SUPPORT */ |
||
270 | #if PPP_OPTIONS |
||
271 | static void ip_check_options (void); |
||
272 | #endif /* PPP_OPTIONS */ |
||
273 | #if DEMAND_SUPPORT |
||
274 | static int ip_demand_conf (int); |
||
275 | static int ip_active_pkt (u_char *, int); |
||
276 | #endif /* DEMAND_SUPPORT */ |
||
277 | #if 0 /* UNUSED */ |
||
278 | static void create_resolv (u32_t, u32_t); |
||
279 | #endif /* UNUSED */ |
||
280 | |||
281 | const struct protent ipcp_protent = { |
||
282 | PPP_IPCP, |
||
283 | ipcp_init, |
||
284 | ipcp_input, |
||
285 | ipcp_protrej, |
||
286 | ipcp_lowerup, |
||
287 | ipcp_lowerdown, |
||
288 | ipcp_open, |
||
289 | ipcp_close, |
||
290 | #if PRINTPKT_SUPPORT |
||
291 | ipcp_printpkt, |
||
292 | #endif /* PRINTPKT_SUPPORT */ |
||
293 | #if PPP_DATAINPUT |
||
294 | NULL, |
||
295 | #endif /* PPP_DATAINPUT */ |
||
296 | #if PRINTPKT_SUPPORT |
||
297 | "IPCP", |
||
298 | "IP", |
||
299 | #endif /* PRINTPKT_SUPPORT */ |
||
300 | #if PPP_OPTIONS |
||
301 | ipcp_option_list, |
||
302 | ip_check_options, |
||
303 | #endif /* PPP_OPTIONS */ |
||
304 | #if DEMAND_SUPPORT |
||
305 | ip_demand_conf, |
||
306 | ip_active_pkt |
||
307 | #endif /* DEMAND_SUPPORT */ |
||
308 | }; |
||
309 | |||
310 | static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute); |
||
311 | |||
312 | /* |
||
313 | * Lengths of configuration options. |
||
314 | */ |
||
315 | #define CILEN_VOID 2 |
||
316 | #define CILEN_COMPRESS 4 /* min length for compression protocol opt. */ |
||
317 | #define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */ |
||
318 | #define CILEN_ADDR 6 /* new-style single address option */ |
||
319 | #define CILEN_ADDRS 10 /* old-style dual address option */ |
||
320 | |||
321 | |||
322 | #define CODENAME(x) ((x) == CONFACK ? "ACK" : \ |
||
323 | (x) == CONFNAK ? "NAK" : "REJ") |
||
324 | |||
325 | #if 0 /* UNUSED, already defined by lwIP */ |
||
326 | /* |
||
327 | * Make a string representation of a network IP address. |
||
328 | */ |
||
329 | char * |
||
330 | ip_ntoa(ipaddr) |
||
331 | u32_t ipaddr; |
||
332 | { |
||
333 | static char b[64]; |
||
334 | |||
335 | slprintf(b, sizeof(b), "%I", ipaddr); |
||
336 | return b; |
||
337 | } |
||
338 | #endif /* UNUSED, already defined by lwIP */ |
||
339 | |||
340 | /* |
||
341 | * Option parsing. |
||
342 | */ |
||
343 | #if PPP_OPTIONS |
||
344 | /* |
||
345 | * setvjslots - set maximum number of connection slots for VJ compression |
||
346 | */ |
||
347 | static int |
||
348 | setvjslots(argv) |
||
349 | char **argv; |
||
350 | { |
||
351 | int value; |
||
352 | |||
353 | if (!int_option(*argv, &value)) |
||
354 | return 0; |
||
355 | |||
356 | if (value < 2 || value > 16) { |
||
357 | option_error("vj-max-slots value must be between 2 and 16"); |
||
358 | return 0; |
||
359 | } |
||
360 | ipcp_wantoptions [0].maxslotindex = |
||
361 | ipcp_allowoptions[0].maxslotindex = value - 1; |
||
362 | slprintf(vj_value, sizeof(vj_value), "%d", value); |
||
363 | return 1; |
||
364 | } |
||
365 | |||
366 | /* |
||
367 | * setdnsaddr - set the dns address(es) |
||
368 | */ |
||
369 | static int |
||
370 | setdnsaddr(argv) |
||
371 | char **argv; |
||
372 | { |
||
373 | u32_t dns; |
||
374 | struct hostent *hp; |
||
375 | |||
376 | dns = inet_addr(*argv); |
||
377 | if (dns == (u32_t) -1) { |
||
378 | if ((hp = gethostbyname(*argv)) == NULL) { |
||
379 | option_error("invalid address parameter '%s' for ms-dns option", |
||
380 | *argv); |
||
381 | return 0; |
||
382 | } |
||
383 | dns = *(u32_t *)hp->h_addr; |
||
384 | } |
||
385 | |||
386 | /* We take the last 2 values given, the 2nd-last as the primary |
||
387 | and the last as the secondary. If only one is given it |
||
388 | becomes both primary and secondary. */ |
||
389 | if (ipcp_allowoptions[0].dnsaddr[1] == 0) |
||
390 | ipcp_allowoptions[0].dnsaddr[0] = dns; |
||
391 | else |
||
392 | ipcp_allowoptions[0].dnsaddr[0] = ipcp_allowoptions[0].dnsaddr[1]; |
||
393 | |||
394 | /* always set the secondary address value. */ |
||
395 | ipcp_allowoptions[0].dnsaddr[1] = dns; |
||
396 | |||
397 | return (1); |
||
398 | } |
||
399 | |||
400 | /* |
||
401 | * setwinsaddr - set the wins address(es) |
||
402 | * This is primrarly used with the Samba package under UNIX or for pointing |
||
403 | * the caller to the existing WINS server on a Windows NT platform. |
||
404 | */ |
||
405 | static int |
||
406 | setwinsaddr(argv) |
||
407 | char **argv; |
||
408 | { |
||
409 | u32_t wins; |
||
410 | struct hostent *hp; |
||
411 | |||
412 | wins = inet_addr(*argv); |
||
413 | if (wins == (u32_t) -1) { |
||
414 | if ((hp = gethostbyname(*argv)) == NULL) { |
||
415 | option_error("invalid address parameter '%s' for ms-wins option", |
||
416 | *argv); |
||
417 | return 0; |
||
418 | } |
||
419 | wins = *(u32_t *)hp->h_addr; |
||
420 | } |
||
421 | |||
422 | /* We take the last 2 values given, the 2nd-last as the primary |
||
423 | and the last as the secondary. If only one is given it |
||
424 | becomes both primary and secondary. */ |
||
425 | if (ipcp_allowoptions[0].winsaddr[1] == 0) |
||
426 | ipcp_allowoptions[0].winsaddr[0] = wins; |
||
427 | else |
||
428 | ipcp_allowoptions[0].winsaddr[0] = ipcp_allowoptions[0].winsaddr[1]; |
||
429 | |||
430 | /* always set the secondary address value. */ |
||
431 | ipcp_allowoptions[0].winsaddr[1] = wins; |
||
432 | |||
433 | return (1); |
||
434 | } |
||
435 | |||
436 | /* |
||
437 | * setipaddr - Set the IP address |
||
438 | * If doit is 0, the call is to check whether this option is |
||
439 | * potentially an IP address specification. |
||
440 | * Not static so that plugins can call it to set the addresses |
||
441 | */ |
||
442 | int |
||
443 | setipaddr(arg, argv, doit) |
||
444 | char *arg; |
||
445 | char **argv; |
||
446 | int doit; |
||
447 | { |
||
448 | struct hostent *hp; |
||
449 | char *colon; |
||
450 | u32_t local, remote; |
||
451 | ipcp_options *wo = &ipcp_wantoptions[0]; |
||
452 | static int prio_local = 0, prio_remote = 0; |
||
453 | |||
454 | /* |
||
455 | * IP address pair separated by ":". |
||
456 | */ |
||
457 | if ((colon = strchr(arg, ':')) == NULL) |
||
458 | return 0; |
||
459 | if (!doit) |
||
460 | return 1; |
||
461 | |||
462 | /* |
||
463 | * If colon first character, then no local addr. |
||
464 | */ |
||
465 | if (colon != arg && option_priority >= prio_local) { |
||
466 | *colon = '\0'; |
||
467 | if ((local = inet_addr(arg)) == (u32_t) -1) { |
||
468 | if ((hp = gethostbyname(arg)) == NULL) { |
||
469 | option_error("unknown host: %s", arg); |
||
470 | return 0; |
||
471 | } |
||
472 | local = *(u32_t *)hp->h_addr; |
||
473 | } |
||
474 | if (bad_ip_adrs(local)) { |
||
475 | option_error("bad local IP address %s", ip_ntoa(local)); |
||
476 | return 0; |
||
477 | } |
||
478 | if (local != 0) |
||
479 | wo->ouraddr = local; |
||
480 | *colon = ':'; |
||
481 | prio_local = option_priority; |
||
482 | } |
||
483 | |||
484 | /* |
||
485 | * If colon last character, then no remote addr. |
||
486 | */ |
||
487 | if (*++colon != '\0' && option_priority >= prio_remote) { |
||
488 | if ((remote = inet_addr(colon)) == (u32_t) -1) { |
||
489 | if ((hp = gethostbyname(colon)) == NULL) { |
||
490 | option_error("unknown host: %s", colon); |
||
491 | return 0; |
||
492 | } |
||
493 | remote = *(u32_t *)hp->h_addr; |
||
494 | if (remote_name[0] == 0) |
||
495 | strlcpy(remote_name, colon, sizeof(remote_name)); |
||
496 | } |
||
497 | if (bad_ip_adrs(remote)) { |
||
498 | option_error("bad remote IP address %s", ip_ntoa(remote)); |
||
499 | return 0; |
||
500 | } |
||
501 | if (remote != 0) |
||
502 | wo->hisaddr = remote; |
||
503 | prio_remote = option_priority; |
||
504 | } |
||
505 | |||
506 | return 1; |
||
507 | } |
||
508 | |||
509 | static void |
||
510 | printipaddr(opt, printer, arg) |
||
511 | option_t *opt; |
||
512 | void (*printer) (void *, char *, ...); |
||
513 | void *arg; |
||
514 | { |
||
515 | ipcp_options *wo = &ipcp_wantoptions[0]; |
||
516 | |||
517 | if (wo->ouraddr != 0) |
||
518 | printer(arg, "%I", wo->ouraddr); |
||
519 | printer(arg, ":"); |
||
520 | if (wo->hisaddr != 0) |
||
521 | printer(arg, "%I", wo->hisaddr); |
||
522 | } |
||
523 | |||
524 | /* |
||
525 | * setnetmask - set the netmask to be used on the interface. |
||
526 | */ |
||
527 | static int |
||
528 | setnetmask(argv) |
||
529 | char **argv; |
||
530 | { |
||
531 | u32_t mask; |
||
532 | int n; |
||
533 | char *p; |
||
534 | |||
535 | /* |
||
536 | * Unfortunately, if we use inet_addr, we can't tell whether |
||
537 | * a result of all 1s is an error or a valid 255.255.255.255. |
||
538 | */ |
||
539 | p = *argv; |
||
540 | n = parse_dotted_ip(p, &mask); |
||
541 | |||
542 | mask = lwip_htonl(mask); |
||
543 | |||
544 | if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) { |
||
545 | option_error("invalid netmask value '%s'", *argv); |
||
546 | return 0; |
||
547 | } |
||
548 | |||
549 | netmask = mask; |
||
550 | slprintf(netmask_str, sizeof(netmask_str), "%I", mask); |
||
551 | |||
552 | return (1); |
||
553 | } |
||
554 | |||
555 | int |
||
556 | parse_dotted_ip(p, vp) |
||
557 | char *p; |
||
558 | u32_t *vp; |
||
559 | { |
||
560 | int n; |
||
561 | u32_t v, b; |
||
562 | char *endp, *p0 = p; |
||
563 | |||
564 | v = 0; |
||
565 | for (n = 3;; --n) { |
||
566 | b = strtoul(p, &endp, 0); |
||
567 | if (endp == p) |
||
568 | return 0; |
||
569 | if (b > 255) { |
||
570 | if (n < 3) |
||
571 | return 0; |
||
572 | /* accept e.g. 0xffffff00 */ |
||
573 | *vp = b; |
||
574 | return endp - p0; |
||
575 | } |
||
576 | v |= b << (n * 8); |
||
577 | p = endp; |
||
578 | if (n == 0) |
||
579 | break; |
||
580 | if (*p != '.') |
||
581 | return 0; |
||
582 | ++p; |
||
583 | } |
||
584 | *vp = v; |
||
585 | return p - p0; |
||
586 | } |
||
587 | #endif /* PPP_OPTIONS */ |
||
588 | |||
589 | /* |
||
590 | * ipcp_init - Initialize IPCP. |
||
591 | */ |
||
592 | static void ipcp_init(ppp_pcb *pcb) { |
||
593 | fsm *f = &pcb->ipcp_fsm; |
||
594 | |||
595 | ipcp_options *wo = &pcb->ipcp_wantoptions; |
||
596 | ipcp_options *ao = &pcb->ipcp_allowoptions; |
||
597 | |||
598 | f->pcb = pcb; |
||
599 | f->protocol = PPP_IPCP; |
||
600 | f->callbacks = &ipcp_callbacks; |
||
601 | fsm_init(f); |
||
602 | |||
603 | /* |
||
604 | * Some 3G modems use repeated IPCP NAKs as a way of stalling |
||
605 | * until they can contact a server on the network, so we increase |
||
606 | * the default number of NAKs we accept before we start treating |
||
607 | * them as rejects. |
||
608 | */ |
||
609 | f->maxnakloops = 100; |
||
610 | |||
611 | #if 0 /* Not necessary, everything is cleared in ppp_new() */ |
||
612 | memset(wo, 0, sizeof(*wo)); |
||
613 | memset(ao, 0, sizeof(*ao)); |
||
614 | #endif /* 0 */ |
||
615 | |||
616 | wo->neg_addr = wo->old_addrs = 1; |
||
617 | #if VJ_SUPPORT |
||
618 | wo->neg_vj = 1; |
||
619 | wo->vj_protocol = IPCP_VJ_COMP; |
||
620 | wo->maxslotindex = MAX_STATES - 1; /* really max index */ |
||
621 | wo->cflag = 1; |
||
622 | #endif /* VJ_SUPPORT */ |
||
623 | |||
624 | #if 0 /* UNUSED */ |
||
625 | /* wanting default route by default */ |
||
626 | wo->default_route = 1; |
||
627 | #endif /* UNUSED */ |
||
628 | |||
629 | ao->neg_addr = ao->old_addrs = 1; |
||
630 | #if VJ_SUPPORT |
||
631 | /* max slots and slot-id compression are currently hardwired in */ |
||
632 | /* ppp_if.c to 16 and 1, this needs to be changed (among other */ |
||
633 | /* things) gmc */ |
||
634 | |||
635 | ao->neg_vj = 1; |
||
636 | ao->maxslotindex = MAX_STATES - 1; |
||
637 | ao->cflag = 1; |
||
638 | #endif /* #if VJ_SUPPORT */ |
||
639 | |||
640 | #if 0 /* UNUSED */ |
||
641 | /* |
||
642 | * XXX These control whether the user may use the proxyarp |
||
643 | * and defaultroute options. |
||
644 | */ |
||
645 | ao->proxy_arp = 1; |
||
646 | ao->default_route = 1; |
||
647 | #endif /* UNUSED */ |
||
648 | } |
||
649 | |||
650 | |||
651 | /* |
||
652 | * ipcp_open - IPCP is allowed to come up. |
||
653 | */ |
||
654 | static void ipcp_open(ppp_pcb *pcb) { |
||
655 | fsm *f = &pcb->ipcp_fsm; |
||
656 | fsm_open(f); |
||
657 | pcb->ipcp_is_open = 1; |
||
658 | } |
||
659 | |||
660 | |||
661 | /* |
||
662 | * ipcp_close - Take IPCP down. |
||
663 | */ |
||
664 | static void ipcp_close(ppp_pcb *pcb, const char *reason) { |
||
665 | fsm *f = &pcb->ipcp_fsm; |
||
666 | fsm_close(f, reason); |
||
667 | } |
||
668 | |||
669 | |||
670 | /* |
||
671 | * ipcp_lowerup - The lower layer is up. |
||
672 | */ |
||
673 | static void ipcp_lowerup(ppp_pcb *pcb) { |
||
674 | fsm *f = &pcb->ipcp_fsm; |
||
675 | fsm_lowerup(f); |
||
676 | } |
||
677 | |||
678 | |||
679 | /* |
||
680 | * ipcp_lowerdown - The lower layer is down. |
||
681 | */ |
||
682 | static void ipcp_lowerdown(ppp_pcb *pcb) { |
||
683 | fsm *f = &pcb->ipcp_fsm; |
||
684 | fsm_lowerdown(f); |
||
685 | } |
||
686 | |||
687 | |||
688 | /* |
||
689 | * ipcp_input - Input IPCP packet. |
||
690 | */ |
||
691 | static void ipcp_input(ppp_pcb *pcb, u_char *p, int len) { |
||
692 | fsm *f = &pcb->ipcp_fsm; |
||
693 | fsm_input(f, p, len); |
||
694 | } |
||
695 | |||
696 | |||
697 | /* |
||
698 | * ipcp_protrej - A Protocol-Reject was received for IPCP. |
||
699 | * |
||
700 | * Pretend the lower layer went down, so we shut up. |
||
701 | */ |
||
702 | static void ipcp_protrej(ppp_pcb *pcb) { |
||
703 | fsm *f = &pcb->ipcp_fsm; |
||
704 | fsm_lowerdown(f); |
||
705 | } |
||
706 | |||
707 | |||
708 | /* |
||
709 | * ipcp_resetci - Reset our CI. |
||
710 | * Called by fsm_sconfreq, Send Configure Request. |
||
711 | */ |
||
712 | static void ipcp_resetci(fsm *f) { |
||
713 | ppp_pcb *pcb = f->pcb; |
||
714 | ipcp_options *wo = &pcb->ipcp_wantoptions; |
||
715 | ipcp_options *go = &pcb->ipcp_gotoptions; |
||
716 | ipcp_options *ao = &pcb->ipcp_allowoptions; |
||
717 | |||
718 | wo->req_addr = (wo->neg_addr || wo->old_addrs) && |
||
719 | (ao->neg_addr || ao->old_addrs); |
||
720 | if (wo->ouraddr == 0) |
||
721 | wo->accept_local = 1; |
||
722 | if (wo->hisaddr == 0) |
||
723 | wo->accept_remote = 1; |
||
724 | #if LWIP_DNS |
||
725 | wo->req_dns1 = wo->req_dns2 = pcb->settings.usepeerdns; /* Request DNS addresses from the peer */ |
||
726 | #endif /* LWIP_DNS */ |
||
727 | *go = *wo; |
||
728 | if (!pcb->ask_for_local) |
||
729 | go->ouraddr = 0; |
||
730 | #if 0 /* UNUSED */ |
||
731 | if (ip_choose_hook) { |
||
732 | ip_choose_hook(&wo->hisaddr); |
||
733 | if (wo->hisaddr) { |
||
734 | wo->accept_remote = 0; |
||
735 | } |
||
736 | } |
||
737 | #endif /* UNUSED */ |
||
738 | BZERO(&pcb->ipcp_hisoptions, sizeof(ipcp_options)); |
||
739 | } |
||
740 | |||
741 | |||
742 | /* |
||
743 | * ipcp_cilen - Return length of our CI. |
||
744 | * Called by fsm_sconfreq, Send Configure Request. |
||
745 | */ |
||
746 | static int ipcp_cilen(fsm *f) { |
||
747 | ppp_pcb *pcb = f->pcb; |
||
748 | ipcp_options *go = &pcb->ipcp_gotoptions; |
||
749 | #if VJ_SUPPORT |
||
750 | ipcp_options *wo = &pcb->ipcp_wantoptions; |
||
751 | #endif /* VJ_SUPPORT */ |
||
752 | ipcp_options *ho = &pcb->ipcp_hisoptions; |
||
753 | |||
754 | #define LENCIADDRS(neg) (neg ? CILEN_ADDRS : 0) |
||
755 | #if VJ_SUPPORT |
||
756 | #define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) |
||
757 | #endif /* VJ_SUPPORT */ |
||
758 | #define LENCIADDR(neg) (neg ? CILEN_ADDR : 0) |
||
759 | #if LWIP_DNS |
||
760 | #define LENCIDNS(neg) LENCIADDR(neg) |
||
761 | #endif /* LWIP_DNS */ |
||
762 | #if 0 /* UNUSED - WINS */ |
||
763 | #define LENCIWINS(neg) LENCIADDR(neg) |
||
764 | #endif /* UNUSED - WINS */ |
||
765 | |||
766 | /* |
||
767 | * First see if we want to change our options to the old |
||
768 | * forms because we have received old forms from the peer. |
||
769 | */ |
||
770 | if (go->neg_addr && go->old_addrs && !ho->neg_addr && ho->old_addrs) |
||
771 | go->neg_addr = 0; |
||
772 | |||
773 | #if VJ_SUPPORT |
||
774 | if (wo->neg_vj && !go->neg_vj && !go->old_vj) { |
||
775 | /* try an older style of VJ negotiation */ |
||
776 | /* use the old style only if the peer did */ |
||
777 | if (ho->neg_vj && ho->old_vj) { |
||
778 | go->neg_vj = 1; |
||
779 | go->old_vj = 1; |
||
780 | go->vj_protocol = ho->vj_protocol; |
||
781 | } |
||
782 | } |
||
783 | #endif /* VJ_SUPPORT */ |
||
784 | |||
785 | return (LENCIADDRS(!go->neg_addr && go->old_addrs) + |
||
786 | #if VJ_SUPPORT |
||
787 | LENCIVJ(go->neg_vj, go->old_vj) + |
||
788 | #endif /* VJ_SUPPORT */ |
||
789 | LENCIADDR(go->neg_addr) + |
||
790 | #if LWIP_DNS |
||
791 | LENCIDNS(go->req_dns1) + |
||
792 | LENCIDNS(go->req_dns2) + |
||
793 | #endif /* LWIP_DNS */ |
||
794 | #if 0 /* UNUSED - WINS */ |
||
795 | LENCIWINS(go->winsaddr[0]) + |
||
796 | LENCIWINS(go->winsaddr[1]) + |
||
797 | #endif /* UNUSED - WINS */ |
||
798 | 0); |
||
799 | } |
||
800 | |||
801 | |||
802 | /* |
||
803 | * ipcp_addci - Add our desired CIs to a packet. |
||
804 | * Called by fsm_sconfreq, Send Configure Request. |
||
805 | */ |
||
806 | static void ipcp_addci(fsm *f, u_char *ucp, int *lenp) { |
||
807 | ppp_pcb *pcb = f->pcb; |
||
808 | ipcp_options *go = &pcb->ipcp_gotoptions; |
||
809 | int len = *lenp; |
||
810 | |||
811 | #define ADDCIADDRS(opt, neg, val1, val2) \ |
||
812 | if (neg) { \ |
||
813 | if (len >= CILEN_ADDRS) { \ |
||
814 | u32_t l; \ |
||
815 | PUTCHAR(opt, ucp); \ |
||
816 | PUTCHAR(CILEN_ADDRS, ucp); \ |
||
817 | l = lwip_ntohl(val1); \ |
||
818 | PUTLONG(l, ucp); \ |
||
819 | l = lwip_ntohl(val2); \ |
||
820 | PUTLONG(l, ucp); \ |
||
821 | len -= CILEN_ADDRS; \ |
||
822 | } else \ |
||
823 | go->old_addrs = 0; \ |
||
824 | } |
||
825 | |||
826 | #if VJ_SUPPORT |
||
827 | #define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \ |
||
828 | if (neg) { \ |
||
829 | int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ |
||
830 | if (len >= vjlen) { \ |
||
831 | PUTCHAR(opt, ucp); \ |
||
832 | PUTCHAR(vjlen, ucp); \ |
||
833 | PUTSHORT(val, ucp); \ |
||
834 | if (!old) { \ |
||
835 | PUTCHAR(maxslotindex, ucp); \ |
||
836 | PUTCHAR(cflag, ucp); \ |
||
837 | } \ |
||
838 | len -= vjlen; \ |
||
839 | } else \ |
||
840 | neg = 0; \ |
||
841 | } |
||
842 | #endif /* VJ_SUPPORT */ |
||
843 | |||
844 | #define ADDCIADDR(opt, neg, val) \ |
||
845 | if (neg) { \ |
||
846 | if (len >= CILEN_ADDR) { \ |
||
847 | u32_t l; \ |
||
848 | PUTCHAR(opt, ucp); \ |
||
849 | PUTCHAR(CILEN_ADDR, ucp); \ |
||
850 | l = lwip_ntohl(val); \ |
||
851 | PUTLONG(l, ucp); \ |
||
852 | len -= CILEN_ADDR; \ |
||
853 | } else \ |
||
854 | neg = 0; \ |
||
855 | } |
||
856 | |||
857 | #if LWIP_DNS |
||
858 | #define ADDCIDNS(opt, neg, addr) \ |
||
859 | if (neg) { \ |
||
860 | if (len >= CILEN_ADDR) { \ |
||
861 | u32_t l; \ |
||
862 | PUTCHAR(opt, ucp); \ |
||
863 | PUTCHAR(CILEN_ADDR, ucp); \ |
||
864 | l = lwip_ntohl(addr); \ |
||
865 | PUTLONG(l, ucp); \ |
||
866 | len -= CILEN_ADDR; \ |
||
867 | } else \ |
||
868 | neg = 0; \ |
||
869 | } |
||
870 | #endif /* LWIP_DNS */ |
||
871 | |||
872 | #if 0 /* UNUSED - WINS */ |
||
873 | #define ADDCIWINS(opt, addr) \ |
||
874 | if (addr) { \ |
||
875 | if (len >= CILEN_ADDR) { \ |
||
876 | u32_t l; \ |
||
877 | PUTCHAR(opt, ucp); \ |
||
878 | PUTCHAR(CILEN_ADDR, ucp); \ |
||
879 | l = lwip_ntohl(addr); \ |
||
880 | PUTLONG(l, ucp); \ |
||
881 | len -= CILEN_ADDR; \ |
||
882 | } else \ |
||
883 | addr = 0; \ |
||
884 | } |
||
885 | #endif /* UNUSED - WINS */ |
||
886 | |||
887 | ADDCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, |
||
888 | go->hisaddr); |
||
889 | |||
890 | #if VJ_SUPPORT |
||
891 | ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, |
||
892 | go->maxslotindex, go->cflag); |
||
893 | #endif /* VJ_SUPPORT */ |
||
894 | |||
895 | ADDCIADDR(CI_ADDR, go->neg_addr, go->ouraddr); |
||
896 | |||
897 | #if LWIP_DNS |
||
898 | ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); |
||
899 | |||
900 | ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); |
||
901 | #endif /* LWIP_DNS */ |
||
902 | |||
903 | #if 0 /* UNUSED - WINS */ |
||
904 | ADDCIWINS(CI_MS_WINS1, go->winsaddr[0]); |
||
905 | |||
906 | ADDCIWINS(CI_MS_WINS2, go->winsaddr[1]); |
||
907 | #endif /* UNUSED - WINS */ |
||
908 | |||
909 | *lenp -= len; |
||
910 | } |
||
911 | |||
912 | |||
913 | /* |
||
914 | * ipcp_ackci - Ack our CIs. |
||
915 | * Called by fsm_rconfack, Receive Configure ACK. |
||
916 | * |
||
917 | * Returns: |
||
918 | * 0 - Ack was bad. |
||
919 | * 1 - Ack was good. |
||
920 | */ |
||
921 | static int ipcp_ackci(fsm *f, u_char *p, int len) { |
||
922 | ppp_pcb *pcb = f->pcb; |
||
923 | ipcp_options *go = &pcb->ipcp_gotoptions; |
||
924 | u_short cilen, citype; |
||
925 | u32_t cilong; |
||
926 | #if VJ_SUPPORT |
||
927 | u_short cishort; |
||
928 | u_char cimaxslotindex, cicflag; |
||
929 | #endif /* VJ_SUPPORT */ |
||
930 | |||
931 | /* |
||
932 | * CIs must be in exactly the same order that we sent... |
||
933 | * Check packet length and CI length at each step. |
||
934 | * If we find any deviations, then this packet is bad. |
||
935 | */ |
||
936 | |||
937 | #define ACKCIADDRS(opt, neg, val1, val2) \ |
||
938 | if (neg) { \ |
||
939 | u32_t l; \ |
||
940 | if ((len -= CILEN_ADDRS) < 0) \ |
||
941 | goto bad; \ |
||
942 | GETCHAR(citype, p); \ |
||
943 | GETCHAR(cilen, p); \ |
||
944 | if (cilen != CILEN_ADDRS || \ |
||
945 | citype != opt) \ |
||
946 | goto bad; \ |
||
947 | GETLONG(l, p); \ |
||
948 | cilong = lwip_htonl(l); \ |
||
949 | if (val1 != cilong) \ |
||
950 | goto bad; \ |
||
951 | GETLONG(l, p); \ |
||
952 | cilong = lwip_htonl(l); \ |
||
953 | if (val2 != cilong) \ |
||
954 | goto bad; \ |
||
955 | } |
||
956 | |||
957 | #if VJ_SUPPORT |
||
958 | #define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \ |
||
959 | if (neg) { \ |
||
960 | int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ |
||
961 | if ((len -= vjlen) < 0) \ |
||
962 | goto bad; \ |
||
963 | GETCHAR(citype, p); \ |
||
964 | GETCHAR(cilen, p); \ |
||
965 | if (cilen != vjlen || \ |
||
966 | citype != opt) \ |
||
967 | goto bad; \ |
||
968 | GETSHORT(cishort, p); \ |
||
969 | if (cishort != val) \ |
||
970 | goto bad; \ |
||
971 | if (!old) { \ |
||
972 | GETCHAR(cimaxslotindex, p); \ |
||
973 | if (cimaxslotindex != maxslotindex) \ |
||
974 | goto bad; \ |
||
975 | GETCHAR(cicflag, p); \ |
||
976 | if (cicflag != cflag) \ |
||
977 | goto bad; \ |
||
978 | } \ |
||
979 | } |
||
980 | #endif /* VJ_SUPPORT */ |
||
981 | |||
982 | #define ACKCIADDR(opt, neg, val) \ |
||
983 | if (neg) { \ |
||
984 | u32_t l; \ |
||
985 | if ((len -= CILEN_ADDR) < 0) \ |
||
986 | goto bad; \ |
||
987 | GETCHAR(citype, p); \ |
||
988 | GETCHAR(cilen, p); \ |
||
989 | if (cilen != CILEN_ADDR || \ |
||
990 | citype != opt) \ |
||
991 | goto bad; \ |
||
992 | GETLONG(l, p); \ |
||
993 | cilong = lwip_htonl(l); \ |
||
994 | if (val != cilong) \ |
||
995 | goto bad; \ |
||
996 | } |
||
997 | |||
998 | #if LWIP_DNS |
||
999 | #define ACKCIDNS(opt, neg, addr) \ |
||
1000 | if (neg) { \ |
||
1001 | u32_t l; \ |
||
1002 | if ((len -= CILEN_ADDR) < 0) \ |
||
1003 | goto bad; \ |
||
1004 | GETCHAR(citype, p); \ |
||
1005 | GETCHAR(cilen, p); \ |
||
1006 | if (cilen != CILEN_ADDR || citype != opt) \ |
||
1007 | goto bad; \ |
||
1008 | GETLONG(l, p); \ |
||
1009 | cilong = lwip_htonl(l); \ |
||
1010 | if (addr != cilong) \ |
||
1011 | goto bad; \ |
||
1012 | } |
||
1013 | #endif /* LWIP_DNS */ |
||
1014 | |||
1015 | #if 0 /* UNUSED - WINS */ |
||
1016 | #define ACKCIWINS(opt, addr) \ |
||
1017 | if (addr) { \ |
||
1018 | u32_t l; \ |
||
1019 | if ((len -= CILEN_ADDR) < 0) \ |
||
1020 | goto bad; \ |
||
1021 | GETCHAR(citype, p); \ |
||
1022 | GETCHAR(cilen, p); \ |
||
1023 | if (cilen != CILEN_ADDR || citype != opt) \ |
||
1024 | goto bad; \ |
||
1025 | GETLONG(l, p); \ |
||
1026 | cilong = lwip_htonl(l); \ |
||
1027 | if (addr != cilong) \ |
||
1028 | goto bad; \ |
||
1029 | } |
||
1030 | #endif /* UNUSED - WINS */ |
||
1031 | |||
1032 | ACKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, |
||
1033 | go->hisaddr); |
||
1034 | |||
1035 | #if VJ_SUPPORT |
||
1036 | ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, |
||
1037 | go->maxslotindex, go->cflag); |
||
1038 | #endif /* VJ_SUPPORT */ |
||
1039 | |||
1040 | ACKCIADDR(CI_ADDR, go->neg_addr, go->ouraddr); |
||
1041 | |||
1042 | #if LWIP_DNS |
||
1043 | ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); |
||
1044 | |||
1045 | ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); |
||
1046 | #endif /* LWIP_DNS */ |
||
1047 | |||
1048 | #if 0 /* UNUSED - WINS */ |
||
1049 | ACKCIWINS(CI_MS_WINS1, go->winsaddr[0]); |
||
1050 | |||
1051 | ACKCIWINS(CI_MS_WINS2, go->winsaddr[1]); |
||
1052 | #endif /* UNUSED - WINS */ |
||
1053 | |||
1054 | /* |
||
1055 | * If there are any remaining CIs, then this packet is bad. |
||
1056 | */ |
||
1057 | if (len != 0) |
||
1058 | goto bad; |
||
1059 | return (1); |
||
1060 | |||
1061 | bad: |
||
1062 | IPCPDEBUG(("ipcp_ackci: received bad Ack!")); |
||
1063 | return (0); |
||
1064 | } |
||
1065 | |||
1066 | /* |
||
1067 | * ipcp_nakci - Peer has sent a NAK for some of our CIs. |
||
1068 | * This should not modify any state if the Nak is bad |
||
1069 | * or if IPCP is in the OPENED state. |
||
1070 | * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. |
||
1071 | * |
||
1072 | * Returns: |
||
1073 | * 0 - Nak was bad. |
||
1074 | * 1 - Nak was good. |
||
1075 | */ |
||
1076 | static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { |
||
1077 | ppp_pcb *pcb = f->pcb; |
||
1078 | ipcp_options *go = &pcb->ipcp_gotoptions; |
||
1079 | u_char citype, cilen, *next; |
||
1080 | #if VJ_SUPPORT |
||
1081 | u_char cimaxslotindex, cicflag; |
||
1082 | u_short cishort; |
||
1083 | #endif /* VJ_SUPPORT */ |
||
1084 | u32_t ciaddr1, ciaddr2, l; |
||
1085 | #if LWIP_DNS |
||
1086 | u32_t cidnsaddr; |
||
1087 | #endif /* LWIP_DNS */ |
||
1088 | ipcp_options no; /* options we've seen Naks for */ |
||
1089 | ipcp_options try_; /* options to request next time */ |
||
1090 | |||
1091 | BZERO(&no, sizeof(no)); |
||
1092 | try_ = *go; |
||
1093 | |||
1094 | /* |
||
1095 | * Any Nak'd CIs must be in exactly the same order that we sent. |
||
1096 | * Check packet length and CI length at each step. |
||
1097 | * If we find any deviations, then this packet is bad. |
||
1098 | */ |
||
1099 | #define NAKCIADDRS(opt, neg, code) \ |
||
1100 | if ((neg) && \ |
||
1101 | (cilen = p[1]) == CILEN_ADDRS && \ |
||
1102 | len >= cilen && \ |
||
1103 | p[0] == opt) { \ |
||
1104 | len -= cilen; \ |
||
1105 | INCPTR(2, p); \ |
||
1106 | GETLONG(l, p); \ |
||
1107 | ciaddr1 = lwip_htonl(l); \ |
||
1108 | GETLONG(l, p); \ |
||
1109 | ciaddr2 = lwip_htonl(l); \ |
||
1110 | no.old_addrs = 1; \ |
||
1111 | code \ |
||
1112 | } |
||
1113 | |||
1114 | #if VJ_SUPPORT |
||
1115 | #define NAKCIVJ(opt, neg, code) \ |
||
1116 | if (go->neg && \ |
||
1117 | ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \ |
||
1118 | len >= cilen && \ |
||
1119 | p[0] == opt) { \ |
||
1120 | len -= cilen; \ |
||
1121 | INCPTR(2, p); \ |
||
1122 | GETSHORT(cishort, p); \ |
||
1123 | no.neg = 1; \ |
||
1124 | code \ |
||
1125 | } |
||
1126 | #endif /* VJ_SUPPORT */ |
||
1127 | |||
1128 | #define NAKCIADDR(opt, neg, code) \ |
||
1129 | if (go->neg && \ |
||
1130 | (cilen = p[1]) == CILEN_ADDR && \ |
||
1131 | len >= cilen && \ |
||
1132 | p[0] == opt) { \ |
||
1133 | len -= cilen; \ |
||
1134 | INCPTR(2, p); \ |
||
1135 | GETLONG(l, p); \ |
||
1136 | ciaddr1 = lwip_htonl(l); \ |
||
1137 | no.neg = 1; \ |
||
1138 | code \ |
||
1139 | } |
||
1140 | |||
1141 | #if LWIP_DNS |
||
1142 | #define NAKCIDNS(opt, neg, code) \ |
||
1143 | if (go->neg && \ |
||
1144 | ((cilen = p[1]) == CILEN_ADDR) && \ |
||
1145 | len >= cilen && \ |
||
1146 | p[0] == opt) { \ |
||
1147 | len -= cilen; \ |
||
1148 | INCPTR(2, p); \ |
||
1149 | GETLONG(l, p); \ |
||
1150 | cidnsaddr = lwip_htonl(l); \ |
||
1151 | no.neg = 1; \ |
||
1152 | code \ |
||
1153 | } |
||
1154 | #endif /* LWIP_DNS */ |
||
1155 | |||
1156 | /* |
||
1157 | * Accept the peer's idea of {our,his} address, if different |
||
1158 | * from our idea, only if the accept_{local,remote} flag is set. |
||
1159 | */ |
||
1160 | NAKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, |
||
1161 | if (treat_as_reject) { |
||
1162 | try_.old_addrs = 0; |
||
1163 | } else { |
||
1164 | if (go->accept_local && ciaddr1) { |
||
1165 | /* take his idea of our address */ |
||
1166 | try_.ouraddr = ciaddr1; |
||
1167 | } |
||
1168 | if (go->accept_remote && ciaddr2) { |
||
1169 | /* take his idea of his address */ |
||
1170 | try_.hisaddr = ciaddr2; |
||
1171 | } |
||
1172 | } |
||
1173 | ); |
||
1174 | |||
1175 | #if VJ_SUPPORT |
||
1176 | /* |
||
1177 | * Accept the peer's value of maxslotindex provided that it |
||
1178 | * is less than what we asked for. Turn off slot-ID compression |
||
1179 | * if the peer wants. Send old-style compress-type option if |
||
1180 | * the peer wants. |
||
1181 | */ |
||
1182 | NAKCIVJ(CI_COMPRESSTYPE, neg_vj, |
||
1183 | if (treat_as_reject) { |
||
1184 | try_.neg_vj = 0; |
||
1185 | } else if (cilen == CILEN_VJ) { |
||
1186 | GETCHAR(cimaxslotindex, p); |
||
1187 | GETCHAR(cicflag, p); |
||
1188 | if (cishort == IPCP_VJ_COMP) { |
||
1189 | try_.old_vj = 0; |
||
1190 | if (cimaxslotindex < go->maxslotindex) |
||
1191 | try_.maxslotindex = cimaxslotindex; |
||
1192 | if (!cicflag) |
||
1193 | try_.cflag = 0; |
||
1194 | } else { |
||
1195 | try_.neg_vj = 0; |
||
1196 | } |
||
1197 | } else { |
||
1198 | if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) { |
||
1199 | try_.old_vj = 1; |
||
1200 | try_.vj_protocol = cishort; |
||
1201 | } else { |
||
1202 | try_.neg_vj = 0; |
||
1203 | } |
||
1204 | } |
||
1205 | ); |
||
1206 | #endif /* VJ_SUPPORT */ |
||
1207 | |||
1208 | NAKCIADDR(CI_ADDR, neg_addr, |
||
1209 | if (treat_as_reject) { |
||
1210 | try_.neg_addr = 0; |
||
1211 | try_.old_addrs = 0; |
||
1212 | } else if (go->accept_local && ciaddr1) { |
||
1213 | /* take his idea of our address */ |
||
1214 | try_.ouraddr = ciaddr1; |
||
1215 | } |
||
1216 | ); |
||
1217 | |||
1218 | #if LWIP_DNS |
||
1219 | NAKCIDNS(CI_MS_DNS1, req_dns1, |
||
1220 | if (treat_as_reject) { |
||
1221 | try_.req_dns1 = 0; |
||
1222 | } else { |
||
1223 | try_.dnsaddr[0] = cidnsaddr; |
||
1224 | } |
||
1225 | ); |
||
1226 | |||
1227 | NAKCIDNS(CI_MS_DNS2, req_dns2, |
||
1228 | if (treat_as_reject) { |
||
1229 | try_.req_dns2 = 0; |
||
1230 | } else { |
||
1231 | try_.dnsaddr[1] = cidnsaddr; |
||
1232 | } |
||
1233 | ); |
||
1234 | #endif /* #if LWIP_DNS */ |
||
1235 | |||
1236 | /* |
||
1237 | * There may be remaining CIs, if the peer is requesting negotiation |
||
1238 | * on an option that we didn't include in our request packet. |
||
1239 | * If they want to negotiate about IP addresses, we comply. |
||
1240 | * If they want us to ask for compression, we refuse. |
||
1241 | * If they want us to ask for ms-dns, we do that, since some |
||
1242 | * peers get huffy if we don't. |
||
1243 | */ |
||
1244 | while (len >= CILEN_VOID) { |
||
1245 | GETCHAR(citype, p); |
||
1246 | GETCHAR(cilen, p); |
||
1247 | if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) |
||
1248 | goto bad; |
||
1249 | next = p + cilen - 2; |
||
1250 | |||
1251 | switch (citype) { |
||
1252 | #if VJ_SUPPORT |
||
1253 | case CI_COMPRESSTYPE: |
||
1254 | if (go->neg_vj || no.neg_vj || |
||
1255 | (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) |
||
1256 | goto bad; |
||
1257 | no.neg_vj = 1; |
||
1258 | break; |
||
1259 | #endif /* VJ_SUPPORT */ |
||
1260 | case CI_ADDRS: |
||
1261 | if ((!go->neg_addr && go->old_addrs) || no.old_addrs |
||
1262 | || cilen != CILEN_ADDRS) |
||
1263 | goto bad; |
||
1264 | try_.neg_addr = 0; |
||
1265 | GETLONG(l, p); |
||
1266 | ciaddr1 = lwip_htonl(l); |
||
1267 | if (ciaddr1 && go->accept_local) |
||
1268 | try_.ouraddr = ciaddr1; |
||
1269 | GETLONG(l, p); |
||
1270 | ciaddr2 = lwip_htonl(l); |
||
1271 | if (ciaddr2 && go->accept_remote) |
||
1272 | try_.hisaddr = ciaddr2; |
||
1273 | no.old_addrs = 1; |
||
1274 | break; |
||
1275 | case CI_ADDR: |
||
1276 | if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) |
||
1277 | goto bad; |
||
1278 | try_.old_addrs = 0; |
||
1279 | GETLONG(l, p); |
||
1280 | ciaddr1 = lwip_htonl(l); |
||
1281 | if (ciaddr1 && go->accept_local) |
||
1282 | try_.ouraddr = ciaddr1; |
||
1283 | if (try_.ouraddr != 0) |
||
1284 | try_.neg_addr = 1; |
||
1285 | no.neg_addr = 1; |
||
1286 | break; |
||
1287 | #if LWIP_DNS |
||
1288 | case CI_MS_DNS1: |
||
1289 | if (go->req_dns1 || no.req_dns1 || cilen != CILEN_ADDR) |
||
1290 | goto bad; |
||
1291 | GETLONG(l, p); |
||
1292 | try_.dnsaddr[0] = lwip_htonl(l); |
||
1293 | try_.req_dns1 = 1; |
||
1294 | no.req_dns1 = 1; |
||
1295 | break; |
||
1296 | case CI_MS_DNS2: |
||
1297 | if (go->req_dns2 || no.req_dns2 || cilen != CILEN_ADDR) |
||
1298 | goto bad; |
||
1299 | GETLONG(l, p); |
||
1300 | try_.dnsaddr[1] = lwip_htonl(l); |
||
1301 | try_.req_dns2 = 1; |
||
1302 | no.req_dns2 = 1; |
||
1303 | break; |
||
1304 | #endif /* LWIP_DNS */ |
||
1305 | #if 0 /* UNUSED - WINS */ |
||
1306 | case CI_MS_WINS1: |
||
1307 | case CI_MS_WINS2: |
||
1308 | if (cilen != CILEN_ADDR) |
||
1309 | goto bad; |
||
1310 | GETLONG(l, p); |
||
1311 | ciaddr1 = lwip_htonl(l); |
||
1312 | if (ciaddr1) |
||
1313 | try_.winsaddr[citype == CI_MS_WINS2] = ciaddr1; |
||
1314 | break; |
||
1315 | #endif /* UNUSED - WINS */ |
||
1316 | default: |
||
1317 | break; |
||
1318 | } |
||
1319 | p = next; |
||
1320 | } |
||
1321 | |||
1322 | /* |
||
1323 | * OK, the Nak is good. Now we can update state. |
||
1324 | * If there are any remaining options, we ignore them. |
||
1325 | */ |
||
1326 | if (f->state != PPP_FSM_OPENED) |
||
1327 | *go = try_; |
||
1328 | |||
1329 | return 1; |
||
1330 | |||
1331 | bad: |
||
1332 | IPCPDEBUG(("ipcp_nakci: received bad Nak!")); |
||
1333 | return 0; |
||
1334 | } |
||
1335 | |||
1336 | |||
1337 | /* |
||
1338 | * ipcp_rejci - Reject some of our CIs. |
||
1339 | * Callback from fsm_rconfnakrej. |
||
1340 | */ |
||
1341 | static int ipcp_rejci(fsm *f, u_char *p, int len) { |
||
1342 | ppp_pcb *pcb = f->pcb; |
||
1343 | ipcp_options *go = &pcb->ipcp_gotoptions; |
||
1344 | u_char cilen; |
||
1345 | #if VJ_SUPPORT |
||
1346 | u_char cimaxslotindex, ciflag; |
||
1347 | u_short cishort; |
||
1348 | #endif /* VJ_SUPPORT */ |
||
1349 | u32_t cilong; |
||
1350 | ipcp_options try_; /* options to request next time */ |
||
1351 | |||
1352 | try_ = *go; |
||
1353 | /* |
||
1354 | * Any Rejected CIs must be in exactly the same order that we sent. |
||
1355 | * Check packet length and CI length at each step. |
||
1356 | * If we find any deviations, then this packet is bad. |
||
1357 | */ |
||
1358 | #define REJCIADDRS(opt, neg, val1, val2) \ |
||
1359 | if ((neg) && \ |
||
1360 | (cilen = p[1]) == CILEN_ADDRS && \ |
||
1361 | len >= cilen && \ |
||
1362 | p[0] == opt) { \ |
||
1363 | u32_t l; \ |
||
1364 | len -= cilen; \ |
||
1365 | INCPTR(2, p); \ |
||
1366 | GETLONG(l, p); \ |
||
1367 | cilong = lwip_htonl(l); \ |
||
1368 | /* Check rejected value. */ \ |
||
1369 | if (cilong != val1) \ |
||
1370 | goto bad; \ |
||
1371 | GETLONG(l, p); \ |
||
1372 | cilong = lwip_htonl(l); \ |
||
1373 | /* Check rejected value. */ \ |
||
1374 | if (cilong != val2) \ |
||
1375 | goto bad; \ |
||
1376 | try_.old_addrs = 0; \ |
||
1377 | } |
||
1378 | |||
1379 | #if VJ_SUPPORT |
||
1380 | #define REJCIVJ(opt, neg, val, old, maxslot, cflag) \ |
||
1381 | if (go->neg && \ |
||
1382 | p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \ |
||
1383 | len >= p[1] && \ |
||
1384 | p[0] == opt) { \ |
||
1385 | len -= p[1]; \ |
||
1386 | INCPTR(2, p); \ |
||
1387 | GETSHORT(cishort, p); \ |
||
1388 | /* Check rejected value. */ \ |
||
1389 | if (cishort != val) \ |
||
1390 | goto bad; \ |
||
1391 | if (!old) { \ |
||
1392 | GETCHAR(cimaxslotindex, p); \ |
||
1393 | if (cimaxslotindex != maxslot) \ |
||
1394 | goto bad; \ |
||
1395 | GETCHAR(ciflag, p); \ |
||
1396 | if (ciflag != cflag) \ |
||
1397 | goto bad; \ |
||
1398 | } \ |
||
1399 | try_.neg = 0; \ |
||
1400 | } |
||
1401 | #endif /* VJ_SUPPORT */ |
||
1402 | |||
1403 | #define REJCIADDR(opt, neg, val) \ |
||
1404 | if (go->neg && \ |
||
1405 | (cilen = p[1]) == CILEN_ADDR && \ |
||
1406 | len >= cilen && \ |
||
1407 | p[0] == opt) { \ |
||
1408 | u32_t l; \ |
||
1409 | len -= cilen; \ |
||
1410 | INCPTR(2, p); \ |
||
1411 | GETLONG(l, p); \ |
||
1412 | cilong = lwip_htonl(l); \ |
||
1413 | /* Check rejected value. */ \ |
||
1414 | if (cilong != val) \ |
||
1415 | goto bad; \ |
||
1416 | try_.neg = 0; \ |
||
1417 | } |
||
1418 | |||
1419 | #if LWIP_DNS |
||
1420 | #define REJCIDNS(opt, neg, dnsaddr) \ |
||
1421 | if (go->neg && \ |
||
1422 | ((cilen = p[1]) == CILEN_ADDR) && \ |
||
1423 | len >= cilen && \ |
||
1424 | p[0] == opt) { \ |
||
1425 | u32_t l; \ |
||
1426 | len -= cilen; \ |
||
1427 | INCPTR(2, p); \ |
||
1428 | GETLONG(l, p); \ |
||
1429 | cilong = lwip_htonl(l); \ |
||
1430 | /* Check rejected value. */ \ |
||
1431 | if (cilong != dnsaddr) \ |
||
1432 | goto bad; \ |
||
1433 | try_.neg = 0; \ |
||
1434 | } |
||
1435 | #endif /* LWIP_DNS */ |
||
1436 | |||
1437 | #if 0 /* UNUSED - WINS */ |
||
1438 | #define REJCIWINS(opt, addr) \ |
||
1439 | if (addr && \ |
||
1440 | ((cilen = p[1]) == CILEN_ADDR) && \ |
||
1441 | len >= cilen && \ |
||
1442 | p[0] == opt) { \ |
||
1443 | u32_t l; \ |
||
1444 | len -= cilen; \ |
||
1445 | INCPTR(2, p); \ |
||
1446 | GETLONG(l, p); \ |
||
1447 | cilong = lwip_htonl(l); \ |
||
1448 | /* Check rejected value. */ \ |
||
1449 | if (cilong != addr) \ |
||
1450 | goto bad; \ |
||
1451 | try_.winsaddr[opt == CI_MS_WINS2] = 0; \ |
||
1452 | } |
||
1453 | #endif /* UNUSED - WINS */ |
||
1454 | |||
1455 | REJCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, |
||
1456 | go->ouraddr, go->hisaddr); |
||
1457 | |||
1458 | #if VJ_SUPPORT |
||
1459 | REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj, |
||
1460 | go->maxslotindex, go->cflag); |
||
1461 | #endif /* VJ_SUPPORT */ |
||
1462 | |||
1463 | REJCIADDR(CI_ADDR, neg_addr, go->ouraddr); |
||
1464 | |||
1465 | #if LWIP_DNS |
||
1466 | REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]); |
||
1467 | |||
1468 | REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]); |
||
1469 | #endif /* LWIP_DNS */ |
||
1470 | |||
1471 | #if 0 /* UNUSED - WINS */ |
||
1472 | REJCIWINS(CI_MS_WINS1, go->winsaddr[0]); |
||
1473 | |||
1474 | REJCIWINS(CI_MS_WINS2, go->winsaddr[1]); |
||
1475 | #endif /* UNUSED - WINS */ |
||
1476 | |||
1477 | /* |
||
1478 | * If there are any remaining CIs, then this packet is bad. |
||
1479 | */ |
||
1480 | if (len != 0) |
||
1481 | goto bad; |
||
1482 | /* |
||
1483 | * Now we can update state. |
||
1484 | */ |
||
1485 | if (f->state != PPP_FSM_OPENED) |
||
1486 | *go = try_; |
||
1487 | return 1; |
||
1488 | |||
1489 | bad: |
||
1490 | IPCPDEBUG(("ipcp_rejci: received bad Reject!")); |
||
1491 | return 0; |
||
1492 | } |
||
1493 | |||
1494 | |||
1495 | /* |
||
1496 | * ipcp_reqci - Check the peer's requested CIs and send appropriate response. |
||
1497 | * Callback from fsm_rconfreq, Receive Configure Request |
||
1498 | * |
||
1499 | * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified |
||
1500 | * appropriately. If reject_if_disagree is non-zero, doesn't return |
||
1501 | * CONFNAK; returns CONFREJ if it can't return CONFACK. |
||
1502 | * |
||
1503 | * inp = Requested CIs |
||
1504 | * len = Length of requested CIs |
||
1505 | */ |
||
1506 | static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { |
||
1507 | ppp_pcb *pcb = f->pcb; |
||
1508 | ipcp_options *wo = &pcb->ipcp_wantoptions; |
||
1509 | ipcp_options *ho = &pcb->ipcp_hisoptions; |
||
1510 | ipcp_options *ao = &pcb->ipcp_allowoptions; |
||
1511 | u_char *cip, *next; /* Pointer to current and next CIs */ |
||
1512 | u_short cilen, citype; /* Parsed len, type */ |
||
1513 | #if VJ_SUPPORT |
||
1514 | u_short cishort; /* Parsed short value */ |
||
1515 | #endif /* VJ_SUPPORT */ |
||
1516 | u32_t tl, ciaddr1, ciaddr2;/* Parsed address values */ |
||
1517 | int rc = CONFACK; /* Final packet return code */ |
||
1518 | int orc; /* Individual option return code */ |
||
1519 | u_char *p; /* Pointer to next char to parse */ |
||
1520 | u_char *ucp = inp; /* Pointer to current output char */ |
||
1521 | int l = *len; /* Length left */ |
||
1522 | #if VJ_SUPPORT |
||
1523 | u_char maxslotindex, cflag; |
||
1524 | #endif /* VJ_SUPPORT */ |
||
1525 | #if LWIP_DNS |
||
1526 | int d; |
||
1527 | #endif /* LWIP_DNS */ |
||
1528 | |||
1529 | /* |
||
1530 | * Reset all his options. |
||
1531 | */ |
||
1532 | BZERO(ho, sizeof(*ho)); |
||
1533 | |||
1534 | /* |
||
1535 | * Process all his options. |
||
1536 | */ |
||
1537 | next = inp; |
||
1538 | while (l) { |
||
1539 | orc = CONFACK; /* Assume success */ |
||
1540 | cip = p = next; /* Remember begining of CI */ |
||
1541 | if (l < 2 || /* Not enough data for CI header or */ |
||
1542 | p[1] < 2 || /* CI length too small or */ |
||
1543 | p[1] > l) { /* CI length too big? */ |
||
1544 | IPCPDEBUG(("ipcp_reqci: bad CI length!")); |
||
1545 | orc = CONFREJ; /* Reject bad CI */ |
||
1546 | cilen = l; /* Reject till end of packet */ |
||
1547 | l = 0; /* Don't loop again */ |
||
1548 | goto endswitch; |
||
1549 | } |
||
1550 | GETCHAR(citype, p); /* Parse CI type */ |
||
1551 | GETCHAR(cilen, p); /* Parse CI length */ |
||
1552 | l -= cilen; /* Adjust remaining length */ |
||
1553 | next += cilen; /* Step to next CI */ |
||
1554 | |||
1555 | switch (citype) { /* Check CI type */ |
||
1556 | case CI_ADDRS: |
||
1557 | if (!ao->old_addrs || ho->neg_addr || |
||
1558 | cilen != CILEN_ADDRS) { /* Check CI length */ |
||
1559 | orc = CONFREJ; /* Reject CI */ |
||
1560 | break; |
||
1561 | } |
||
1562 | |||
1563 | /* |
||
1564 | * If he has no address, or if we both have his address but |
||
1565 | * disagree about it, then NAK it with our idea. |
||
1566 | * In particular, if we don't know his address, but he does, |
||
1567 | * then accept it. |
||
1568 | */ |
||
1569 | GETLONG(tl, p); /* Parse source address (his) */ |
||
1570 | ciaddr1 = lwip_htonl(tl); |
||
1571 | if (ciaddr1 != wo->hisaddr |
||
1572 | && (ciaddr1 == 0 || !wo->accept_remote)) { |
||
1573 | orc = CONFNAK; |
||
1574 | if (!reject_if_disagree) { |
||
1575 | DECPTR(sizeof(u32_t), p); |
||
1576 | tl = lwip_ntohl(wo->hisaddr); |
||
1577 | PUTLONG(tl, p); |
||
1578 | } |
||
1579 | } else if (ciaddr1 == 0 && wo->hisaddr == 0) { |
||
1580 | /* |
||
1581 | * If neither we nor he knows his address, reject the option. |
||
1582 | */ |
||
1583 | orc = CONFREJ; |
||
1584 | wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ |
||
1585 | break; |
||
1586 | } |
||
1587 | |||
1588 | /* |
||
1589 | * If he doesn't know our address, or if we both have our address |
||
1590 | * but disagree about it, then NAK it with our idea. |
||
1591 | */ |
||
1592 | GETLONG(tl, p); /* Parse desination address (ours) */ |
||
1593 | ciaddr2 = lwip_htonl(tl); |
||
1594 | if (ciaddr2 != wo->ouraddr) { |
||
1595 | if (ciaddr2 == 0 || !wo->accept_local) { |
||
1596 | orc = CONFNAK; |
||
1597 | if (!reject_if_disagree) { |
||
1598 | DECPTR(sizeof(u32_t), p); |
||
1599 | tl = lwip_ntohl(wo->ouraddr); |
||
1600 | PUTLONG(tl, p); |
||
1601 | } |
||
1602 | } else { |
||
1603 | wo->ouraddr = ciaddr2; /* accept peer's idea */ |
||
1604 | } |
||
1605 | } |
||
1606 | |||
1607 | ho->old_addrs = 1; |
||
1608 | ho->hisaddr = ciaddr1; |
||
1609 | ho->ouraddr = ciaddr2; |
||
1610 | break; |
||
1611 | |||
1612 | case CI_ADDR: |
||
1613 | if (!ao->neg_addr || ho->old_addrs || |
||
1614 | cilen != CILEN_ADDR) { /* Check CI length */ |
||
1615 | orc = CONFREJ; /* Reject CI */ |
||
1616 | break; |
||
1617 | } |
||
1618 | |||
1619 | /* |
||
1620 | * If he has no address, or if we both have his address but |
||
1621 | * disagree about it, then NAK it with our idea. |
||
1622 | * In particular, if we don't know his address, but he does, |
||
1623 | * then accept it. |
||
1624 | */ |
||
1625 | GETLONG(tl, p); /* Parse source address (his) */ |
||
1626 | ciaddr1 = lwip_htonl(tl); |
||
1627 | if (ciaddr1 != wo->hisaddr |
||
1628 | && (ciaddr1 == 0 || !wo->accept_remote)) { |
||
1629 | orc = CONFNAK; |
||
1630 | if (!reject_if_disagree) { |
||
1631 | DECPTR(sizeof(u32_t), p); |
||
1632 | tl = lwip_ntohl(wo->hisaddr); |
||
1633 | PUTLONG(tl, p); |
||
1634 | } |
||
1635 | } else if (ciaddr1 == 0 && wo->hisaddr == 0) { |
||
1636 | /* |
||
1637 | * Don't ACK an address of 0.0.0.0 - reject it instead. |
||
1638 | */ |
||
1639 | orc = CONFREJ; |
||
1640 | wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ |
||
1641 | break; |
||
1642 | } |
||
1643 | |||
1644 | ho->neg_addr = 1; |
||
1645 | ho->hisaddr = ciaddr1; |
||
1646 | break; |
||
1647 | |||
1648 | #if LWIP_DNS |
||
1649 | case CI_MS_DNS1: |
||
1650 | case CI_MS_DNS2: |
||
1651 | /* Microsoft primary or secondary DNS request */ |
||
1652 | d = citype == CI_MS_DNS2; |
||
1653 | |||
1654 | /* If we do not have a DNS address then we cannot send it */ |
||
1655 | if (ao->dnsaddr[d] == 0 || |
||
1656 | cilen != CILEN_ADDR) { /* Check CI length */ |
||
1657 | orc = CONFREJ; /* Reject CI */ |
||
1658 | break; |
||
1659 | } |
||
1660 | GETLONG(tl, p); |
||
1661 | if (lwip_htonl(tl) != ao->dnsaddr[d]) { |
||
1662 | DECPTR(sizeof(u32_t), p); |
||
1663 | tl = lwip_ntohl(ao->dnsaddr[d]); |
||
1664 | PUTLONG(tl, p); |
||
1665 | orc = CONFNAK; |
||
1666 | } |
||
1667 | break; |
||
1668 | #endif /* LWIP_DNS */ |
||
1669 | |||
1670 | #if 0 /* UNUSED - WINS */ |
||
1671 | case CI_MS_WINS1: |
||
1672 | case CI_MS_WINS2: |
||
1673 | /* Microsoft primary or secondary WINS request */ |
||
1674 | d = citype == CI_MS_WINS2; |
||
1675 | |||
1676 | /* If we do not have a DNS address then we cannot send it */ |
||
1677 | if (ao->winsaddr[d] == 0 || |
||
1678 | cilen != CILEN_ADDR) { /* Check CI length */ |
||
1679 | orc = CONFREJ; /* Reject CI */ |
||
1680 | break; |
||
1681 | } |
||
1682 | GETLONG(tl, p); |
||
1683 | if (lwip_htonl(tl) != ao->winsaddr[d]) { |
||
1684 | DECPTR(sizeof(u32_t), p); |
||
1685 | tl = lwip_ntohl(ao->winsaddr[d]); |
||
1686 | PUTLONG(tl, p); |
||
1687 | orc = CONFNAK; |
||
1688 | } |
||
1689 | break; |
||
1690 | #endif /* UNUSED - WINS */ |
||
1691 | |||
1692 | #if VJ_SUPPORT |
||
1693 | case CI_COMPRESSTYPE: |
||
1694 | if (!ao->neg_vj || |
||
1695 | (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) { |
||
1696 | orc = CONFREJ; |
||
1697 | break; |
||
1698 | } |
||
1699 | GETSHORT(cishort, p); |
||
1700 | |||
1701 | if (!(cishort == IPCP_VJ_COMP || |
||
1702 | (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) { |
||
1703 | orc = CONFREJ; |
||
1704 | break; |
||
1705 | } |
||
1706 | |||
1707 | ho->neg_vj = 1; |
||
1708 | ho->vj_protocol = cishort; |
||
1709 | if (cilen == CILEN_VJ) { |
||
1710 | GETCHAR(maxslotindex, p); |
||
1711 | if (maxslotindex > ao->maxslotindex) { |
||
1712 | orc = CONFNAK; |
||
1713 | if (!reject_if_disagree){ |
||
1714 | DECPTR(1, p); |
||
1715 | PUTCHAR(ao->maxslotindex, p); |
||
1716 | } |
||
1717 | } |
||
1718 | GETCHAR(cflag, p); |
||
1719 | if (cflag && !ao->cflag) { |
||
1720 | orc = CONFNAK; |
||
1721 | if (!reject_if_disagree){ |
||
1722 | DECPTR(1, p); |
||
1723 | PUTCHAR(wo->cflag, p); |
||
1724 | } |
||
1725 | } |
||
1726 | ho->maxslotindex = maxslotindex; |
||
1727 | ho->cflag = cflag; |
||
1728 | } else { |
||
1729 | ho->old_vj = 1; |
||
1730 | ho->maxslotindex = MAX_STATES - 1; |
||
1731 | ho->cflag = 1; |
||
1732 | } |
||
1733 | break; |
||
1734 | #endif /* VJ_SUPPORT */ |
||
1735 | |||
1736 | default: |
||
1737 | orc = CONFREJ; |
||
1738 | break; |
||
1739 | } |
||
1740 | endswitch: |
||
1741 | if (orc == CONFACK && /* Good CI */ |
||
1742 | rc != CONFACK) /* but prior CI wasnt? */ |
||
1743 | continue; /* Don't send this one */ |
||
1744 | |||
1745 | if (orc == CONFNAK) { /* Nak this CI? */ |
||
1746 | if (reject_if_disagree) /* Getting fed up with sending NAKs? */ |
||
1747 | orc = CONFREJ; /* Get tough if so */ |
||
1748 | else { |
||
1749 | if (rc == CONFREJ) /* Rejecting prior CI? */ |
||
1750 | continue; /* Don't send this one */ |
||
1751 | if (rc == CONFACK) { /* Ack'd all prior CIs? */ |
||
1752 | rc = CONFNAK; /* Not anymore... */ |
||
1753 | ucp = inp; /* Backup */ |
||
1754 | } |
||
1755 | } |
||
1756 | } |
||
1757 | |||
1758 | if (orc == CONFREJ && /* Reject this CI */ |
||
1759 | rc != CONFREJ) { /* but no prior ones? */ |
||
1760 | rc = CONFREJ; |
||
1761 | ucp = inp; /* Backup */ |
||
1762 | } |
||
1763 | |||
1764 | /* Need to move CI? */ |
||
1765 | if (ucp != cip) |
||
1766 | MEMCPY(ucp, cip, cilen); /* Move it */ |
||
1767 | |||
1768 | /* Update output pointer */ |
||
1769 | INCPTR(cilen, ucp); |
||
1770 | } |
||
1771 | |||
1772 | /* |
||
1773 | * If we aren't rejecting this packet, and we want to negotiate |
||
1774 | * their address, and they didn't send their address, then we |
||
1775 | * send a NAK with a CI_ADDR option appended. We assume the |
||
1776 | * input buffer is long enough that we can append the extra |
||
1777 | * option safely. |
||
1778 | */ |
||
1779 | if (rc != CONFREJ && !ho->neg_addr && !ho->old_addrs && |
||
1780 | wo->req_addr && !reject_if_disagree && !pcb->settings.noremoteip) { |
||
1781 | if (rc == CONFACK) { |
||
1782 | rc = CONFNAK; |
||
1783 | ucp = inp; /* reset pointer */ |
||
1784 | wo->req_addr = 0; /* don't ask again */ |
||
1785 | } |
||
1786 | PUTCHAR(CI_ADDR, ucp); |
||
1787 | PUTCHAR(CILEN_ADDR, ucp); |
||
1788 | tl = lwip_ntohl(wo->hisaddr); |
||
1789 | PUTLONG(tl, ucp); |
||
1790 | } |
||
1791 | |||
1792 | *len = ucp - inp; /* Compute output length */ |
||
1793 | IPCPDEBUG(("ipcp: returning Configure-%s", CODENAME(rc))); |
||
1794 | return (rc); /* Return final code */ |
||
1795 | } |
||
1796 | |||
1797 | |||
1798 | #if 0 /* UNUSED */ |
||
1799 | /* |
||
1800 | * ip_check_options - check that any IP-related options are OK, |
||
1801 | * and assign appropriate defaults. |
||
1802 | */ |
||
1803 | static void |
||
1804 | ip_check_options() |
||
1805 | { |
||
1806 | struct hostent *hp; |
||
1807 | u32_t local; |
||
1808 | ipcp_options *wo = &ipcp_wantoptions[0]; |
||
1809 | |||
1810 | /* |
||
1811 | * Default our local IP address based on our hostname. |
||
1812 | * If local IP address already given, don't bother. |
||
1813 | */ |
||
1814 | if (wo->ouraddr == 0 && !disable_defaultip) { |
||
1815 | /* |
||
1816 | * Look up our hostname (possibly with domain name appended) |
||
1817 | * and take the first IP address as our local IP address. |
||
1818 | * If there isn't an IP address for our hostname, too bad. |
||
1819 | */ |
||
1820 | wo->accept_local = 1; /* don't insist on this default value */ |
||
1821 | if ((hp = gethostbyname(hostname)) != NULL) { |
||
1822 | local = *(u32_t *)hp->h_addr; |
||
1823 | if (local != 0 && !bad_ip_adrs(local)) |
||
1824 | wo->ouraddr = local; |
||
1825 | } |
||
1826 | } |
||
1827 | ask_for_local = wo->ouraddr != 0 || !disable_defaultip; |
||
1828 | } |
||
1829 | #endif /* UNUSED */ |
||
1830 | |||
1831 | #if DEMAND_SUPPORT |
||
1832 | /* |
||
1833 | * ip_demand_conf - configure the interface as though |
||
1834 | * IPCP were up, for use with dial-on-demand. |
||
1835 | */ |
||
1836 | static int |
||
1837 | ip_demand_conf(u) |
||
1838 | int u; |
||
1839 | { |
||
1840 | ppp_pcb *pcb = &ppp_pcb_list[u]; |
||
1841 | ipcp_options *wo = &ipcp_wantoptions[u]; |
||
1842 | |||
1843 | if (wo->hisaddr == 0 && !pcb->settings.noremoteip) { |
||
1844 | /* make up an arbitrary address for the peer */ |
||
1845 | wo->hisaddr = lwip_htonl(0x0a707070 + ifunit); |
||
1846 | wo->accept_remote = 1; |
||
1847 | } |
||
1848 | if (wo->ouraddr == 0) { |
||
1849 | /* make up an arbitrary address for us */ |
||
1850 | wo->ouraddr = lwip_htonl(0x0a404040 + ifunit); |
||
1851 | wo->accept_local = 1; |
||
1852 | ask_for_local = 0; /* don't tell the peer this address */ |
||
1853 | } |
||
1854 | if (!sifaddr(pcb, wo->ouraddr, wo->hisaddr, get_mask(wo->ouraddr))) |
||
1855 | return 0; |
||
1856 | if (!sifup(pcb)) |
||
1857 | return 0; |
||
1858 | if (!sifnpmode(pcb, PPP_IP, NPMODE_QUEUE)) |
||
1859 | return 0; |
||
1860 | #if 0 /* UNUSED */ |
||
1861 | if (wo->default_route) |
||
1862 | if (sifdefaultroute(pcb, wo->ouraddr, wo->hisaddr, |
||
1863 | wo->replace_default_route)) |
||
1864 | default_route_set[u] = 1; |
||
1865 | #endif /* UNUSED */ |
||
1866 | #if 0 /* UNUSED - PROXY ARP */ |
||
1867 | if (wo->proxy_arp) |
||
1868 | if (sifproxyarp(pcb, wo->hisaddr)) |
||
1869 | proxy_arp_set[u] = 1; |
||
1870 | #endif /* UNUSED - PROXY ARP */ |
||
1871 | |||
1872 | ppp_notice("local IP address %I", wo->ouraddr); |
||
1873 | if (wo->hisaddr) |
||
1874 | ppp_notice("remote IP address %I", wo->hisaddr); |
||
1875 | |||
1876 | return 1; |
||
1877 | } |
||
1878 | #endif /* DEMAND_SUPPORT */ |
||
1879 | |||
1880 | /* |
||
1881 | * ipcp_up - IPCP has come UP. |
||
1882 | * |
||
1883 | * Configure the IP network interface appropriately and bring it up. |
||
1884 | */ |
||
1885 | static void ipcp_up(fsm *f) { |
||
1886 | ppp_pcb *pcb = f->pcb; |
||
1887 | u32_t mask; |
||
1888 | ipcp_options *ho = &pcb->ipcp_hisoptions; |
||
1889 | ipcp_options *go = &pcb->ipcp_gotoptions; |
||
1890 | ipcp_options *wo = &pcb->ipcp_wantoptions; |
||
1891 | |||
1892 | IPCPDEBUG(("ipcp: up")); |
||
1893 | |||
1894 | /* |
||
1895 | * We must have a non-zero IP address for both ends of the link. |
||
1896 | */ |
||
1897 | if (!ho->neg_addr && !ho->old_addrs) |
||
1898 | ho->hisaddr = wo->hisaddr; |
||
1899 | |||
1900 | if (!(go->neg_addr || go->old_addrs) && (wo->neg_addr || wo->old_addrs) |
||
1901 | && wo->ouraddr != 0) { |
||
1902 | ppp_error("Peer refused to agree to our IP address"); |
||
1903 | ipcp_close(f->pcb, "Refused our IP address"); |
||
1904 | return; |
||
1905 | } |
||
1906 | if (go->ouraddr == 0) { |
||
1907 | ppp_error("Could not determine local IP address"); |
||
1908 | ipcp_close(f->pcb, "Could not determine local IP address"); |
||
1909 | return; |
||
1910 | } |
||
1911 | if (ho->hisaddr == 0 && !pcb->settings.noremoteip) { |
||
1912 | ho->hisaddr = lwip_htonl(0x0a404040); |
||
1913 | ppp_warn("Could not determine remote IP address: defaulting to %I", |
||
1914 | ho->hisaddr); |
||
1915 | } |
||
1916 | #if 0 /* UNUSED */ |
||
1917 | script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0); |
||
1918 | if (ho->hisaddr != 0) |
||
1919 | script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1); |
||
1920 | #endif /* UNUSED */ |
||
1921 | |||
1922 | #if LWIP_DNS |
||
1923 | if (!go->req_dns1) |
||
1924 | go->dnsaddr[0] = 0; |
||
1925 | if (!go->req_dns2) |
||
1926 | go->dnsaddr[1] = 0; |
||
1927 | #if 0 /* UNUSED */ |
||
1928 | if (go->dnsaddr[0]) |
||
1929 | script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0); |
||
1930 | if (go->dnsaddr[1]) |
||
1931 | script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0); |
||
1932 | #endif /* UNUSED */ |
||
1933 | if (pcb->settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) { |
||
1934 | sdns(pcb, go->dnsaddr[0], go->dnsaddr[1]); |
||
1935 | #if 0 /* UNUSED */ |
||
1936 | script_setenv("USEPEERDNS", "1", 0); |
||
1937 | create_resolv(go->dnsaddr[0], go->dnsaddr[1]); |
||
1938 | #endif /* UNUSED */ |
||
1939 | } |
||
1940 | #endif /* LWIP_DNS */ |
||
1941 | |||
1942 | /* |
||
1943 | * Check that the peer is allowed to use the IP address it wants. |
||
1944 | */ |
||
1945 | if (ho->hisaddr != 0) { |
||
1946 | u32_t addr = lwip_ntohl(ho->hisaddr); |
||
1947 | if ((addr >> IP_CLASSA_NSHIFT) == IP_LOOPBACKNET |
||
1948 | || IP_MULTICAST(addr) || IP_BADCLASS(addr) |
||
1949 | /* |
||
1950 | * For now, consider that PPP in server mode with peer required |
||
1951 | * to authenticate must provide the peer IP address, reject any |
||
1952 | * IP address wanted by peer different than the one we wanted. |
||
1953 | */ |
||
1954 | #if PPP_SERVER && PPP_AUTH_SUPPORT |
||
1955 | || (pcb->settings.auth_required && wo->hisaddr != ho->hisaddr) |
||
1956 | #endif /* PPP_SERVER && PPP_AUTH_SUPPORT */ |
||
1957 | ) { |
||
1958 | ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr); |
||
1959 | ipcp_close(pcb, "Unauthorized remote IP address"); |
||
1960 | return; |
||
1961 | } |
||
1962 | } |
||
1963 | #if 0 /* Unused */ |
||
1964 | /* Upstream checking code */ |
||
1965 | if (ho->hisaddr != 0 && !auth_ip_addr(f->unit, ho->hisaddr)) { |
||
1966 | ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr); |
||
1967 | ipcp_close(f->unit, "Unauthorized remote IP address"); |
||
1968 | return; |
||
1969 | } |
||
1970 | #endif /* Unused */ |
||
1971 | |||
1972 | #if VJ_SUPPORT |
||
1973 | /* set tcp compression */ |
||
1974 | sifvjcomp(pcb, ho->neg_vj, ho->cflag, ho->maxslotindex); |
||
1975 | #endif /* VJ_SUPPORT */ |
||
1976 | |||
1977 | #if DEMAND_SUPPORT |
||
1978 | /* |
||
1979 | * If we are doing dial-on-demand, the interface is already |
||
1980 | * configured, so we put out any saved-up packets, then set the |
||
1981 | * interface to pass IP packets. |
||
1982 | */ |
||
1983 | if (demand) { |
||
1984 | if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) { |
||
1985 | ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr, |
||
1986 | wo->replace_default_route); |
||
1987 | if (go->ouraddr != wo->ouraddr) { |
||
1988 | ppp_warn("Local IP address changed to %I", go->ouraddr); |
||
1989 | script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0); |
||
1990 | wo->ouraddr = go->ouraddr; |
||
1991 | } else |
||
1992 | script_unsetenv("OLDIPLOCAL"); |
||
1993 | if (ho->hisaddr != wo->hisaddr && wo->hisaddr != 0) { |
||
1994 | ppp_warn("Remote IP address changed to %I", ho->hisaddr); |
||
1995 | script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0); |
||
1996 | wo->hisaddr = ho->hisaddr; |
||
1997 | } else |
||
1998 | script_unsetenv("OLDIPREMOTE"); |
||
1999 | |||
2000 | /* Set the interface to the new addresses */ |
||
2001 | mask = get_mask(go->ouraddr); |
||
2002 | if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { |
||
2003 | #if PPP_DEBUG |
||
2004 | ppp_warn("Interface configuration failed"); |
||
2005 | #endif /* PPP_DEBUG */ |
||
2006 | ipcp_close(f->unit, "Interface configuration failed"); |
||
2007 | return; |
||
2008 | } |
||
2009 | |||
2010 | /* assign a default route through the interface if required */ |
||
2011 | if (ipcp_wantoptions[f->unit].default_route) |
||
2012 | if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr, |
||
2013 | wo->replace_default_route)) |
||
2014 | default_route_set[f->unit] = 1; |
||
2015 | |||
2016 | #if 0 /* UNUSED - PROXY ARP */ |
||
2017 | /* Make a proxy ARP entry if requested. */ |
||
2018 | if (ho->hisaddr != 0 && ipcp_wantoptions[f->unit].proxy_arp) |
||
2019 | if (sifproxyarp(pcb, ho->hisaddr)) |
||
2020 | proxy_arp_set[f->unit] = 1; |
||
2021 | #endif /* UNUSED - PROXY ARP */ |
||
2022 | |||
2023 | } |
||
2024 | demand_rexmit(PPP_IP,go->ouraddr); |
||
2025 | sifnpmode(pcb, PPP_IP, NPMODE_PASS); |
||
2026 | |||
2027 | } else |
||
2028 | #endif /* DEMAND_SUPPORT */ |
||
2029 | { |
||
2030 | /* |
||
2031 | * Set IP addresses and (if specified) netmask. |
||
2032 | */ |
||
2033 | mask = get_mask(go->ouraddr); |
||
2034 | |||
2035 | #if !(defined(SVR4) && (defined(SNI) || defined(__USLC__))) |
||
2036 | if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { |
||
2037 | #if PPP_DEBUG |
||
2038 | ppp_warn("Interface configuration failed"); |
||
2039 | #endif /* PPP_DEBUG */ |
||
2040 | ipcp_close(f->pcb, "Interface configuration failed"); |
||
2041 | return; |
||
2042 | } |
||
2043 | #endif |
||
2044 | |||
2045 | /* bring the interface up for IP */ |
||
2046 | if (!sifup(pcb)) { |
||
2047 | #if PPP_DEBUG |
||
2048 | ppp_warn("Interface failed to come up"); |
||
2049 | #endif /* PPP_DEBUG */ |
||
2050 | ipcp_close(f->pcb, "Interface configuration failed"); |
||
2051 | return; |
||
2052 | } |
||
2053 | |||
2054 | #if (defined(SVR4) && (defined(SNI) || defined(__USLC__))) |
||
2055 | if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { |
||
2056 | #if PPP_DEBUG |
||
2057 | ppp_warn("Interface configuration failed"); |
||
2058 | #endif /* PPP_DEBUG */ |
||
2059 | ipcp_close(f->unit, "Interface configuration failed"); |
||
2060 | return; |
||
2061 | } |
||
2062 | #endif |
||
2063 | #if DEMAND_SUPPORT |
||
2064 | sifnpmode(pcb, PPP_IP, NPMODE_PASS); |
||
2065 | #endif /* DEMAND_SUPPORT */ |
||
2066 | |||
2067 | #if 0 /* UNUSED */ |
||
2068 | /* assign a default route through the interface if required */ |
||
2069 | if (wo->default_route) |
||
2070 | if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr, |
||
2071 | wo->replace_default_route)) |
||
2072 | pcb->default_route_set = 1; |
||
2073 | #endif /* UNUSED */ |
||
2074 | |||
2075 | #if 0 /* UNUSED - PROXY ARP */ |
||
2076 | /* Make a proxy ARP entry if requested. */ |
||
2077 | if (ho->hisaddr != 0 && wo->proxy_arp) |
||
2078 | if (sifproxyarp(pcb, ho->hisaddr)) |
||
2079 | pcb->proxy_arp_set = 1; |
||
2080 | #endif /* UNUSED - PROXY ARP */ |
||
2081 | |||
2082 | wo->ouraddr = go->ouraddr; |
||
2083 | |||
2084 | ppp_notice("local IP address %I", go->ouraddr); |
||
2085 | if (ho->hisaddr != 0) |
||
2086 | ppp_notice("remote IP address %I", ho->hisaddr); |
||
2087 | #if LWIP_DNS |
||
2088 | if (go->dnsaddr[0]) |
||
2089 | ppp_notice("primary DNS address %I", go->dnsaddr[0]); |
||
2090 | if (go->dnsaddr[1]) |
||
2091 | ppp_notice("secondary DNS address %I", go->dnsaddr[1]); |
||
2092 | #endif /* LWIP_DNS */ |
||
2093 | } |
||
2094 | |||
2095 | #if PPP_STATS_SUPPORT |
||
2096 | reset_link_stats(f->unit); |
||
2097 | #endif /* PPP_STATS_SUPPORT */ |
||
2098 | |||
2099 | np_up(pcb, PPP_IP); |
||
2100 | pcb->ipcp_is_up = 1; |
||
2101 | |||
2102 | #if PPP_NOTIFY |
||
2103 | notify(ip_up_notifier, 0); |
||
2104 | #endif /* PPP_NOTIFY */ |
||
2105 | #if 0 /* UNUSED */ |
||
2106 | if (ip_up_hook) |
||
2107 | ip_up_hook(); |
||
2108 | #endif /* UNUSED */ |
||
2109 | } |
||
2110 | |||
2111 | |||
2112 | /* |
||
2113 | * ipcp_down - IPCP has gone DOWN. |
||
2114 | * |
||
2115 | * Take the IP network interface down, clear its addresses |
||
2116 | * and delete routes through it. |
||
2117 | */ |
||
2118 | static void ipcp_down(fsm *f) { |
||
2119 | ppp_pcb *pcb = f->pcb; |
||
2120 | ipcp_options *ho = &pcb->ipcp_hisoptions; |
||
2121 | ipcp_options *go = &pcb->ipcp_gotoptions; |
||
2122 | |||
2123 | IPCPDEBUG(("ipcp: down")); |
||
2124 | #if PPP_STATS_SUPPORT |
||
2125 | /* XXX a bit IPv4-centric here, we only need to get the stats |
||
2126 | * before the interface is marked down. */ |
||
2127 | /* XXX more correct: we must get the stats before running the notifiers, |
||
2128 | * at least for the radius plugin */ |
||
2129 | update_link_stats(f->unit); |
||
2130 | #endif /* PPP_STATS_SUPPORT */ |
||
2131 | #if PPP_NOTIFY |
||
2132 | notify(ip_down_notifier, 0); |
||
2133 | #endif /* PPP_NOTIFY */ |
||
2134 | #if 0 /* UNUSED */ |
||
2135 | if (ip_down_hook) |
||
2136 | ip_down_hook(); |
||
2137 | #endif /* UNUSED */ |
||
2138 | if (pcb->ipcp_is_up) { |
||
2139 | pcb->ipcp_is_up = 0; |
||
2140 | np_down(pcb, PPP_IP); |
||
2141 | } |
||
2142 | #if VJ_SUPPORT |
||
2143 | sifvjcomp(pcb, 0, 0, 0); |
||
2144 | #endif /* VJ_SUPPORT */ |
||
2145 | |||
2146 | #if PPP_STATS_SUPPORT |
||
2147 | print_link_stats(); /* _after_ running the notifiers and ip_down_hook(), |
||
2148 | * because print_link_stats() sets link_stats_valid |
||
2149 | * to 0 (zero) */ |
||
2150 | #endif /* PPP_STATS_SUPPORT */ |
||
2151 | |||
2152 | #if DEMAND_SUPPORT |
||
2153 | /* |
||
2154 | * If we are doing dial-on-demand, set the interface |
||
2155 | * to queue up outgoing packets (for now). |
||
2156 | */ |
||
2157 | if (demand) { |
||
2158 | sifnpmode(pcb, PPP_IP, NPMODE_QUEUE); |
||
2159 | } else |
||
2160 | #endif /* DEMAND_SUPPORT */ |
||
2161 | { |
||
2162 | #if DEMAND_SUPPORT |
||
2163 | sifnpmode(pcb, PPP_IP, NPMODE_DROP); |
||
2164 | #endif /* DEMAND_SUPPORT */ |
||
2165 | sifdown(pcb); |
||
2166 | ipcp_clear_addrs(pcb, go->ouraddr, |
||
2167 | ho->hisaddr, 0); |
||
2168 | #if LWIP_DNS |
||
2169 | cdns(pcb, go->dnsaddr[0], go->dnsaddr[1]); |
||
2170 | #endif /* LWIP_DNS */ |
||
2171 | } |
||
2172 | } |
||
2173 | |||
2174 | |||
2175 | /* |
||
2176 | * ipcp_clear_addrs() - clear the interface addresses, routes, |
||
2177 | * proxy arp entries, etc. |
||
2178 | */ |
||
2179 | static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute) { |
||
2180 | LWIP_UNUSED_ARG(replacedefaultroute); |
||
2181 | |||
2182 | #if 0 /* UNUSED - PROXY ARP */ |
||
2183 | if (pcb->proxy_arp_set) { |
||
2184 | cifproxyarp(pcb, hisaddr); |
||
2185 | pcb->proxy_arp_set = 0; |
||
2186 | } |
||
2187 | #endif /* UNUSED - PROXY ARP */ |
||
2188 | #if 0 /* UNUSED */ |
||
2189 | /* If replacedefaultroute, sifdefaultroute will be called soon |
||
2190 | * with replacedefaultroute set and that will overwrite the current |
||
2191 | * default route. This is the case only when doing demand, otherwise |
||
2192 | * during demand, this cifdefaultroute would restore the old default |
||
2193 | * route which is not what we want in this case. In the non-demand |
||
2194 | * case, we'll delete the default route and restore the old if there |
||
2195 | * is one saved by an sifdefaultroute with replacedefaultroute. |
||
2196 | */ |
||
2197 | if (!replacedefaultroute && pcb->default_route_set) { |
||
2198 | cifdefaultroute(pcb, ouraddr, hisaddr); |
||
2199 | pcb->default_route_set = 0; |
||
2200 | } |
||
2201 | #endif /* UNUSED */ |
||
2202 | cifaddr(pcb, ouraddr, hisaddr); |
||
2203 | } |
||
2204 | |||
2205 | |||
2206 | /* |
||
2207 | * ipcp_finished - possibly shut down the lower layers. |
||
2208 | */ |
||
2209 | static void ipcp_finished(fsm *f) { |
||
2210 | ppp_pcb *pcb = f->pcb; |
||
2211 | if (pcb->ipcp_is_open) { |
||
2212 | pcb->ipcp_is_open = 0; |
||
2213 | np_finished(pcb, PPP_IP); |
||
2214 | } |
||
2215 | } |
||
2216 | |||
2217 | |||
2218 | #if 0 /* UNUSED */ |
||
2219 | /* |
||
2220 | * create_resolv - create the replacement resolv.conf file |
||
2221 | */ |
||
2222 | static void |
||
2223 | create_resolv(peerdns1, peerdns2) |
||
2224 | u32_t peerdns1, peerdns2; |
||
2225 | { |
||
2226 | |||
2227 | } |
||
2228 | #endif /* UNUSED */ |
||
2229 | |||
2230 | #if PRINTPKT_SUPPORT |
||
2231 | /* |
||
2232 | * ipcp_printpkt - print the contents of an IPCP packet. |
||
2233 | */ |
||
2234 | static const char* const ipcp_codenames[] = { |
||
2235 | "ConfReq", "ConfAck", "ConfNak", "ConfRej", |
||
2236 | "TermReq", "TermAck", "CodeRej" |
||
2237 | }; |
||
2238 | |||
2239 | static int ipcp_printpkt(const u_char *p, int plen, |
||
2240 | void (*printer) (void *, const char *, ...), void *arg) { |
||
2241 | int code, id, len, olen; |
||
2242 | const u_char *pstart, *optend; |
||
2243 | #if VJ_SUPPORT |
||
2244 | u_short cishort; |
||
2245 | #endif /* VJ_SUPPORT */ |
||
2246 | u32_t cilong; |
||
2247 | |||
2248 | if (plen < HEADERLEN) |
||
2249 | return 0; |
||
2250 | pstart = p; |
||
2251 | GETCHAR(code, p); |
||
2252 | GETCHAR(id, p); |
||
2253 | GETSHORT(len, p); |
||
2254 | if (len < HEADERLEN || len > plen) |
||
2255 | return 0; |
||
2256 | |||
2257 | if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipcp_codenames)) |
||
2258 | printer(arg, " %s", ipcp_codenames[code-1]); |
||
2259 | else |
||
2260 | printer(arg, " code=0x%x", code); |
||
2261 | printer(arg, " id=0x%x", id); |
||
2262 | len -= HEADERLEN; |
||
2263 | switch (code) { |
||
2264 | case CONFREQ: |
||
2265 | case CONFACK: |
||
2266 | case CONFNAK: |
||
2267 | case CONFREJ: |
||
2268 | /* print option list */ |
||
2269 | while (len >= 2) { |
||
2270 | GETCHAR(code, p); |
||
2271 | GETCHAR(olen, p); |
||
2272 | p -= 2; |
||
2273 | if (olen < 2 || olen > len) { |
||
2274 | break; |
||
2275 | } |
||
2276 | printer(arg, " <"); |
||
2277 | len -= olen; |
||
2278 | optend = p + olen; |
||
2279 | switch (code) { |
||
2280 | case CI_ADDRS: |
||
2281 | if (olen == CILEN_ADDRS) { |
||
2282 | p += 2; |
||
2283 | GETLONG(cilong, p); |
||
2284 | printer(arg, "addrs %I", lwip_htonl(cilong)); |
||
2285 | GETLONG(cilong, p); |
||
2286 | printer(arg, " %I", lwip_htonl(cilong)); |
||
2287 | } |
||
2288 | break; |
||
2289 | #if VJ_SUPPORT |
||
2290 | case CI_COMPRESSTYPE: |
||
2291 | if (olen >= CILEN_COMPRESS) { |
||
2292 | p += 2; |
||
2293 | GETSHORT(cishort, p); |
||
2294 | printer(arg, "compress "); |
||
2295 | switch (cishort) { |
||
2296 | case IPCP_VJ_COMP: |
||
2297 | printer(arg, "VJ"); |
||
2298 | break; |
||
2299 | case IPCP_VJ_COMP_OLD: |
||
2300 | printer(arg, "old-VJ"); |
||
2301 | break; |
||
2302 | default: |
||
2303 | printer(arg, "0x%x", cishort); |
||
2304 | } |
||
2305 | } |
||
2306 | break; |
||
2307 | #endif /* VJ_SUPPORT */ |
||
2308 | case CI_ADDR: |
||
2309 | if (olen == CILEN_ADDR) { |
||
2310 | p += 2; |
||
2311 | GETLONG(cilong, p); |
||
2312 | printer(arg, "addr %I", lwip_htonl(cilong)); |
||
2313 | } |
||
2314 | break; |
||
2315 | #if LWIP_DNS |
||
2316 | case CI_MS_DNS1: |
||
2317 | case CI_MS_DNS2: |
||
2318 | p += 2; |
||
2319 | GETLONG(cilong, p); |
||
2320 | printer(arg, "ms-dns%d %I", (code == CI_MS_DNS1? 1: 2), |
||
2321 | htonl(cilong)); |
||
2322 | break; |
||
2323 | #endif /* LWIP_DNS */ |
||
2324 | #if 0 /* UNUSED - WINS */ |
||
2325 | case CI_MS_WINS1: |
||
2326 | case CI_MS_WINS2: |
||
2327 | p += 2; |
||
2328 | GETLONG(cilong, p); |
||
2329 | printer(arg, "ms-wins %I", lwip_htonl(cilong)); |
||
2330 | break; |
||
2331 | #endif /* UNUSED - WINS */ |
||
2332 | default: |
||
2333 | break; |
||
2334 | } |
||
2335 | while (p < optend) { |
||
2336 | GETCHAR(code, p); |
||
2337 | printer(arg, " %.2x", code); |
||
2338 | } |
||
2339 | printer(arg, ">"); |
||
2340 | } |
||
2341 | break; |
||
2342 | |||
2343 | case TERMACK: |
||
2344 | case TERMREQ: |
||
2345 | if (len > 0 && *p >= ' ' && *p < 0x7f) { |
||
2346 | printer(arg, " "); |
||
2347 | ppp_print_string(p, len, printer, arg); |
||
2348 | p += len; |
||
2349 | len = 0; |
||
2350 | } |
||
2351 | break; |
||
2352 | default: |
||
2353 | break; |
||
2354 | } |
||
2355 | |||
2356 | /* print the rest of the bytes in the packet */ |
||
2357 | for (; len > 0; --len) { |
||
2358 | GETCHAR(code, p); |
||
2359 | printer(arg, " %.2x", code); |
||
2360 | } |
||
2361 | |||
2362 | return p - pstart; |
||
2363 | } |
||
2364 | #endif /* PRINTPKT_SUPPORT */ |
||
2365 | |||
2366 | #if DEMAND_SUPPORT |
||
2367 | /* |
||
2368 | * ip_active_pkt - see if this IP packet is worth bringing the link up for. |
||
2369 | * We don't bring the link up for IP fragments or for TCP FIN packets |
||
2370 | * with no data. |
||
2371 | */ |
||
2372 | #define IP_HDRLEN 20 /* bytes */ |
||
2373 | #define IP_OFFMASK 0x1fff |
||
2374 | #ifndef IPPROTO_TCP |
||
2375 | #define IPPROTO_TCP 6 |
||
2376 | #endif |
||
2377 | #define TCP_HDRLEN 20 |
||
2378 | #define TH_FIN 0x01 |
||
2379 | |||
2380 | /* |
||
2381 | * We use these macros because the IP header may be at an odd address, |
||
2382 | * and some compilers might use word loads to get th_off or ip_hl. |
||
2383 | */ |
||
2384 | |||
2385 | #define net_short(x) (((x)[0] << 8) + (x)[1]) |
||
2386 | #define get_iphl(x) (((unsigned char *)(x))[0] & 0xF) |
||
2387 | #define get_ipoff(x) net_short((unsigned char *)(x) + 6) |
||
2388 | #define get_ipproto(x) (((unsigned char *)(x))[9]) |
||
2389 | #define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) |
||
2390 | #define get_tcpflags(x) (((unsigned char *)(x))[13]) |
||
2391 | |||
2392 | static int |
||
2393 | ip_active_pkt(pkt, len) |
||
2394 | u_char *pkt; |
||
2395 | int len; |
||
2396 | { |
||
2397 | u_char *tcp; |
||
2398 | int hlen; |
||
2399 | |||
2400 | len -= PPP_HDRLEN; |
||
2401 | pkt += PPP_HDRLEN; |
||
2402 | if (len < IP_HDRLEN) |
||
2403 | return 0; |
||
2404 | if ((get_ipoff(pkt) & IP_OFFMASK) != 0) |
||
2405 | return 0; |
||
2406 | if (get_ipproto(pkt) != IPPROTO_TCP) |
||
2407 | return 1; |
||
2408 | hlen = get_iphl(pkt) * 4; |
||
2409 | if (len < hlen + TCP_HDRLEN) |
||
2410 | return 0; |
||
2411 | tcp = pkt + hlen; |
||
2412 | if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) |
||
2413 | return 0; |
||
2414 | return 1; |
||
2415 | } |
||
2416 | #endif /* DEMAND_SUPPORT */ |
||
2417 | |||
2418 | #endif /* PPP_SUPPORT && PPP_IPV4_SUPPORT */ |