]> git.decadent.org.uk Git - ap-utils.git/blob - src/bridge.c
8c065004f775ce06c69b8ec0c8f578065559b855
[ap-utils.git] / src / bridge.c
1 /*
2  *      bridge.c from Access Point SNMP Utils for Linux
3  *
4  * Copyright (c) 2002 Roman Festchook <roma at polesye dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License Version 2 from
8  * June 1991 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include "ap-utils.h"
25 #include "ap-curses.h"
26
27 #define IPADDR _("[I] IP: ")
28 #define NETMASK _("[N] Netmask: ")
29 #define GATEWAY _("[G] Gateway: ")
30 #define IP_FILTER _("[F] Filter non-IP traffic: ")
31 #define PR_PORT _("[P] Primary port: ")
32 #define SB_ATTMAC _("Attached station MAC: ")
33 #define DHCP _("[D] DHCP client: ")
34 #define OPER _("[O] Operational mode: ")
35 #define REMOTE_MAC _("[M] Preferred BSSID (remote MAC addr.): ")
36 #define CF_PORT _("[C] Configuration-enabled port(s): ")
37 #define TRAP_PORT _("[T] Trap-sending port(s): ")
38 #define FW_BCAST _("[R] Forward broadcast traffic: ")
39 #define SB_BCAST _("[B] Isolate wireless clients (broadcast traffic): ")
40 #define SB_UCAST _("[U] Isolate wireless clients (unicast traffic): ")
41 #define HELP _("INGFPDOMSCTRBU - set; W - write conf; Q - quit to menu")
42
43 extern short ap_type;
44 extern char IS_ATMEL410_SBRIDGES;
45 extern char IS_ATMEL12350_TELLUS;
46
47 void bridging()
48 {
49     char sysTrapSwitch[] = {
50         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x01, 0x03, 0x00
51     };
52
53     char operIPAddress[] = {
54         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x01, 0x00
55     };
56     char operIPMask[] = {
57         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x02, 0x00
58     };
59     char operEthernetAddress[] = {
60         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x03, 0x00
61     };
62     char operGateway[] = {
63         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x04, 0x00
64     };
65     char operDHCP[] = {
66         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x05, 0x00
67     };
68     char PrimaryPort[] = {
69         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x02, 0x06, 0x00
70     };
71     /* This one is ATMEL12350 MIB specific. */
72     char ConfigPort[] = {
73         0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x02, 0x07, 0x00
74     };
75     /* This one is ATMEL12350 TELLUS MIB specific. */
76     char TrapPort[] = {
77         0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x02, 0x08, 0x00
78     };
79
80     char IPFilter[] = {
81         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x03, 0x01, 0x00
82     };
83     /* These 3 are ATMEL12350 MIB specific. */
84     char ForwardBroadcast[] = {
85         0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x03, 0x02, 0x00
86     };
87     char SendBackBcast[] = {
88         0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x03, 0x03, 0x00
89     };
90     char SendBackUnicast[] = {
91         0x2B, 0x06, 0x01, 0x04, 0x01, 0xE0, 0x3E, 0x01, 0x01, 0x03, 0x04, 0x00
92     };
93
94     char bridgeOperationalMode[] = {
95         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x04, 0x01, 0x00
96     };
97     char bridgeRemoteBridgeBSSID[] = {
98         0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1A, 0x01, 0x01, 0x04, 0x02, 0x00
99     };
100
101     extern WINDOW *main_sub;
102     varbind varbinds[15];
103     struct in_addr ip, mask, gw;
104     unsigned char message[1024], filter, primary_port, dhcp, RemoteBSSID[6],
105         bridge_mode, traps, config_port, fw_bcast, sb_bcast,
106         sb_ucast;
107     char m_filter = 0, m_bridge_mode = 0, m_primary_port = 0, m_traps = 0,
108         m_dhcp = 0, m_ip = 0, m_mask = 0, m_gw = 0, m_remote_bssid = 0,
109         m_config_port = 0, m_trap_port = 0, m_fw_bcast = 0, m_sb_bcast = 0,
110         m_sb_ucast = 0;
111     char *bridge_modes[6] = {
112         _("Wireless Bridge Point to MultiPoint"),
113         _("Access Point"),
114         _("Access Point client"),
115         _("Wireless Bridge Point to Point"),
116         _("Repeater"),
117         ("unknown")
118     }, *pr_ports[2] = {
119         _("Ethernet"),
120         _("Wireless")
121     }, *cf_trap_ports[3] = {
122         _("Both"),
123         _("Ethernet"),
124         _("Wireless")
125     };
126     int i;
127     unsigned int trap_port = 0;
128
129     if (ap_type == ATMEL12350) {
130         operEthernetAddress[5] = 0xE0;
131         operEthernetAddress[6] = 0x3E;
132         IPFilter[5] = 0xE0;
133         IPFilter[6] = 0x3E;
134         PrimaryPort[5] = 0xE0;
135         PrimaryPort[6] = 0x3E;
136         operDHCP[5] = 0xE0;
137         operDHCP[6] = 0x3E;
138         operIPAddress[5] = 0xE0;
139         operIPAddress[6] = 0x3E;
140         operIPMask[5] = 0xE0;
141         operIPMask[6] = 0x3E;
142         operGateway[5] = 0xE0;
143         operGateway[6] = 0x3E;
144         bridgeOperationalMode[5] = 0xE0;
145         bridgeOperationalMode[6] = 0x3E;
146         bridgeRemoteBridgeBSSID[5] = 0xE0;
147         bridgeRemoteBridgeBSSID[6] = 0x3E;
148         sysTrapSwitch[5] = 0xE0;
149         sysTrapSwitch[6] = 0x3E;
150     }
151
152     for (i = 0; i < 15; i++) {
153         varbinds[i].type = NULL_VALUE;
154         varbinds[i].len_val = 0;
155         varbinds[i].len_oid = sizeof(sysTrapSwitch);
156     }
157
158     i = 0;
159
160     varbinds[i++].oid = operEthernetAddress;
161     varbinds[i++].oid = IPFilter;
162     varbinds[i++].oid = PrimaryPort;
163     varbinds[i++].oid = operDHCP;
164     varbinds[i++].oid = operIPAddress;
165     varbinds[i++].oid = operIPMask;
166     varbinds[i++].oid = operGateway;
167     varbinds[i++].oid = bridgeOperationalMode;
168     varbinds[i++].oid = sysTrapSwitch;
169     varbinds[i++].oid = bridgeRemoteBridgeBSSID;
170     if (ap_type == ATMEL12350) {
171         varbinds[i++].oid = ConfigPort;
172         varbinds[i++].oid = ForwardBroadcast;
173         varbinds[i++].oid = SendBackBcast;
174         varbinds[i++].oid = SendBackUnicast;
175         if (IS_ATMEL12350_TELLUS)
176             varbinds[i++].oid = TrapPort;
177     }
178
179     if (snmp(varbinds, i, GET) <= 0) {
180         print_helperr(ERR_RET);
181         goto exit;
182     }
183
184     print_title(_("Bridging"));
185
186     sprintf(message, "%s%02X%02X%02X%02X%02X%02X", MAC,
187             varbinds[0].value[0] & 0xFF,
188             varbinds[0].value[1] & 0xFF,
189             varbinds[0].value[2] & 0xFF,
190             varbinds[0].value[3] & 0xFF,
191             varbinds[0].value[4] & 0xFF,
192             varbinds[0].value[5] & 0xFF);
193     mvwaddstr(main_sub, 0, 0, message);
194
195     memcpy(&ip.s_addr, varbinds[4].value, 4);
196     sprintf(message, "%s%s", IPADDR, inet_ntoa(ip));
197     mvwaddstr(main_sub, 1, 0, message);
198
199     memcpy(&mask.s_addr, varbinds[5].value, 4);
200     sprintf(message, "%s%s", NETMASK, inet_ntoa(mask));
201     mvwaddstr(main_sub, 1, 24, message);
202
203     memcpy(&gw.s_addr, varbinds[6].value, 4);
204     sprintf(message, "%s%s", GATEWAY, inet_ntoa(gw));
205     mvwaddstr(main_sub, 2, 0, message);
206
207     filter = *(varbinds[1].value);
208     sprintf(message, "%s%s", IP_FILTER, (filter == 1) ? ON : OFF);
209     mvwaddstr(main_sub, 3, 0, message);
210
211     if (IS_ATMEL410_SBRIDGES) {
212         sprintf(message, "%s%02X%02X%02X%02X%02X%02X", SB_ATTMAC,
213                 *(varbinds[2].value +0) & 0xFF, *(varbinds[2].value +1) & 0xFF,
214                 *(varbinds[2].value +2) & 0xFF, *(varbinds[2].value +3) & 0xFF,
215                 *(varbinds[2].value +4) & 0xFF, *(varbinds[2].value +5) & 0xFF);
216     } else {
217         primary_port = *(varbinds[2].value);
218         if (primary_port < 1 || primary_port > 2) {
219             primary_port = 1;
220         }
221         sprintf(message, "%s%s", PR_PORT, pr_ports[primary_port - 1]);
222     }
223     mvwaddstr(main_sub, 4, 0, message);
224
225     dhcp = *(varbinds[3].value);
226     sprintf(message, "%s%s", DHCP, (dhcp == 1) ? ON : OFF);
227     mvwaddstr(main_sub, 5, 0, message);
228
229     memcpy(RemoteBSSID, varbinds[9].value, 6);
230     if ((bridge_mode = *(varbinds[7].value)) != 2) {
231         sprintf(message, "%s%02X%02X%02X%02X%02X%02X", REMOTE_MAC,
232                 *(RemoteBSSID + 0) & 0xFF, *(RemoteBSSID + 1) & 0xFF,
233                 *(RemoteBSSID + 2) & 0xFF, *(RemoteBSSID + 3) & 0xFF,
234                 *(RemoteBSSID + 4) & 0xFF, *(RemoteBSSID + 5) & 0xFF);
235         mvwaddstr(main_sub, 7, 0, message);
236     }
237     if (bridge_mode > 5)
238         bridge_mode  = 6;
239     sprintf(message, "%s%s", OPER, bridge_modes[bridge_mode - 1]);
240     mvwaddstr(main_sub, 6, 0, message);
241
242     traps = *(varbinds[8].value);
243     sprintf(message, "%s%s", TRAPS, (traps == 1) ? ON : OFF);
244     mvwaddstr(main_sub, 8, 0, message);
245
246     if (ap_type == ATMEL12350) {
247         config_port = *(varbinds[10].value);
248         sprintf(message, "%s%s", CF_PORT, cf_trap_ports[config_port]);
249         mvwaddstr(main_sub, 9, 0, message);
250
251         if (IS_ATMEL12350_TELLUS) {
252             for (i = 0; i < varbinds[14].len_val;
253                     trap_port += varbinds[14].value[i] *
254                     (1 << ((varbinds[14].len_val - i - 1) * 8)), i++);
255             sprintf(message, "%s%u", TRAP_PORT, trap_port);
256             mvwaddstr(main_sub, 10, 0, message);
257         }
258
259         fw_bcast = *(varbinds[11].value);
260         sprintf(message, "%s%s", FW_BCAST, (fw_bcast == 1) ? ON : OFF);
261         mvwaddstr(main_sub, 11, 0, message);
262
263         sb_bcast = *(varbinds[12].value);
264         sprintf(message, "%s%s", SB_BCAST, (sb_bcast == 1) ? ON : OFF);
265         mvwaddstr(main_sub, 12, 0, message);
266
267         sb_ucast = *(varbinds[13].value);
268         sprintf(message, "%s%s", SB_UCAST, (sb_ucast == 1) ? ON : OFF);
269         mvwaddstr(main_sub, 13, 0, message);
270     }
271     wrefresh(main_sub);
272     noecho();
273
274     print_help(HELP);
275     while (1) {
276         switch (getch()) {
277         case 'I':
278         case 'i':
279             get_ip(&ip, 1, strlen(IPADDR), HELP);
280             m_ip = 1;
281             continue;
282         case 'N':
283         case 'n':
284             get_mask(&mask, 1, strlen(IPADDR) + 16 + strlen(NETMASK), HELP);
285             m_mask = 1;
286             continue;
287         case 'G':
288         case 'g':
289             get_ip(&gw, 2, strlen(GATEWAY), HELP);
290             m_gw = 1;
291             continue;
292         case 'F':
293         case 'f':
294             filter = on_off(3, strlen(IP_FILTER));
295             clear_main_new(3, 4);
296             print_menusel(3, 0, IP_FILTER, (filter == 1) ? ON : OFF);
297             m_filter = 1;
298             continue;
299         case 'P':
300         case 'p':
301             if (!IS_ATMEL410_SBRIDGES) {
302                 primary_port = menu_choose(4, strlen(PR_PORT), pr_ports, 2) + 1;
303                 clear_main_new(4, 5);
304                 print_menusel(4, 0, PR_PORT, pr_ports[primary_port - 1]);
305                 m_primary_port = 1;
306             }   
307             continue;
308         case 'D':
309         case 'd':
310             dhcp = on_off(5, strlen(DHCP));
311             clear_main_new(5, 6);
312             print_menusel(5, 0, DHCP, (dhcp == 1) ? ON : OFF);
313             m_dhcp = 1;
314             continue;
315         case 'O':
316         case 'o':
317             bridge_mode = menu_choose(6, strlen(OPER), bridge_modes, 5) + 1;
318             clear_main_new(6, 8);
319             print_menusel(6, 0, OPER, bridge_modes[bridge_mode - 1]);
320             if (bridge_mode != 2) {
321                 sprintf(message, "%02X%02X%02X%02X%02X%02X",
322                         *(RemoteBSSID + 0) & 0xFF,
323                         *(RemoteBSSID + 1) & 0xFF,
324                         *(RemoteBSSID + 2) & 0xFF,
325                         *(RemoteBSSID + 3) & 0xFF,
326                         *(RemoteBSSID + 4) & 0xFF,
327                         *(RemoteBSSID + 5) & 0xFF);
328                 print_menusel(7, 0, REMOTE_MAC, message);
329             }
330             m_bridge_mode = 1;
331             continue;
332         case 'M':
333         case 'm':
334             if (bridge_mode == 2)
335                 continue;
336
337             get_mac(RemoteBSSID, 7, strlen(REMOTE_MAC));
338 /*          mvwaddstr(main_sub, 7, 21, "  :  :  :  :  :  ");
339             for (i = 0; i < 6; i++) {
340                 get_value(message, 7, 21 + i * 3, 3, ANY_STRING, 0, 0, NULL);
341                 RemoteBSSID[i] = strtol(message, NULL, 16);
342             }
343             sprintf(message, "%s%02X%02X%02X%02X%02X%02X", REMOTE_MAC,
344                 *(RemoteBSSID + 0) & 0xFF, *(RemoteBSSID + 1) & 0xFF,
345                 *(RemoteBSSID + 2) & 0xFF, *(RemoteBSSID + 3) & 0xFF,
346                 *(RemoteBSSID + 4) & 0xFF, *(RemoteBSSID + 5) & 0xFF);
347 */
348             m_remote_bssid = 1;
349             continue;
350         case 'S':
351         case 's':
352             traps = on_off(8, strlen(TRAPS));
353             clear_main_new(8, 9);
354             print_menusel(8, 0, TRAPS, (traps == 1) ? ON : OFF);
355             m_traps = 1;
356             continue;
357         case 'C':
358         case 'c':
359             if (ap_type == ATMEL12350) {
360                 config_port = menu_choose(9, strlen(CF_PORT), cf_trap_ports, 3);
361                 clear_main_new(9, 10);
362                 print_menusel(9, 0, CF_PORT, cf_trap_ports[config_port]);
363                 m_config_port = 1;
364             }
365             continue;
366         case 'T':
367         case 't':
368             if (IS_ATMEL12350_TELLUS) {
369                 get_value(message, 10, strlen(TRAP_PORT), 6, INT_STRING,
370                     0, 65535, HELP);
371                 trap_port = atoi(message);
372                 m_trap_port = 1;
373             }
374             continue;
375         case 'R':
376         case 'r':
377             if (ap_type == ATMEL12350) {
378                 fw_bcast = on_off(11, strlen(FW_BCAST));
379                 clear_main_new(11, 12);
380                 print_menusel(11, 0, FW_BCAST, (fw_bcast == 1) ? ON : OFF);
381                 m_fw_bcast = 1;
382             }
383             continue;
384         case 'B':
385         case 'b':
386             if (ap_type == ATMEL12350) {
387                 sb_bcast = on_off(12, strlen(SB_BCAST));
388                 clear_main_new(12, 13);
389                 print_menusel(12, 0, SB_BCAST, (sb_bcast == 1) ? ON : OFF);
390                 m_sb_bcast = 1;
391             }
392             continue;
393         case 'U':
394         case 'u':
395             if (ap_type == ATMEL12350) {
396                 sb_ucast = on_off(13, strlen(SB_UCAST));
397                 clear_main_new(13, 14);
398                 print_menusel(13, 0, SB_UCAST, (sb_ucast == 1) ? ON : OFF);
399                 m_sb_ucast = 1;
400             }
401             continue;
402         case 'w':
403         case 'W':
404             i = 0;
405             if (m_filter) {
406                 varbinds[i].oid = IPFilter;
407                 varbinds[i].len_oid = sizeof(IPFilter);
408                 varbinds[i].type = INT_VALUE;
409                 varbinds[i].value = (char *) &filter;
410                 varbinds[i].len_val = 1;
411                 i++;
412             }
413             if (m_primary_port) {
414                 varbinds[i].oid = PrimaryPort;
415                 varbinds[i].len_oid = sizeof(PrimaryPort);
416                 varbinds[i].type = INT_VALUE;
417                 varbinds[i].value = (char *) &primary_port;
418                 varbinds[i].len_val = 1;
419                 i++;
420             }
421             if (m_dhcp) {
422                 varbinds[i].oid = operDHCP;
423                 varbinds[i].len_oid = sizeof(operDHCP);
424                 varbinds[i].type = INT_VALUE;
425                 varbinds[i].value = (char *) &dhcp;
426                 varbinds[i].len_val = 1;
427                 i++;
428             }
429             if (m_ip) {
430                 varbinds[i].oid = operIPAddress;
431                 varbinds[i].len_oid = sizeof(operIPAddress);
432                 ip.s_addr = htonl(ip.s_addr);
433                 ip.s_addr = swap4(ip.s_addr);
434                 varbinds[i].value = (char *) &ip.s_addr;
435                 varbinds[i].len_val = 4;
436                 varbinds[i].type = INT_VALUE;
437                 i++;
438             }
439             if (m_mask) {
440                 varbinds[i].oid = operIPMask;
441                 varbinds[i].len_oid = sizeof(operIPMask);
442                 mask.s_addr = htonl(mask.s_addr);
443                 mask.s_addr = swap4(mask.s_addr);
444                 varbinds[i].value = (char *) &mask.s_addr;
445                 varbinds[i].len_val = 4;
446                 varbinds[i].type = INT_VALUE;
447                 i++;
448             }
449             if (m_gw) {
450                 varbinds[i].oid = operGateway;
451                 gw.s_addr = htonl(gw.s_addr);
452                 gw.s_addr = swap4(gw.s_addr);
453                 varbinds[i].len_oid = sizeof(operGateway);
454                 varbinds[i].value = (char *) &gw.s_addr;
455                 varbinds[i].len_val = 4;
456                 varbinds[i].type = INT_VALUE;
457                 i++;
458             }
459             if (m_traps) {
460                 varbinds[i].oid = sysTrapSwitch;
461                 varbinds[i].len_oid = sizeof(sysTrapSwitch);
462                 varbinds[i].value = &traps;
463                 varbinds[i].len_val = 1;
464                 varbinds[i].type = INT_VALUE;
465                 i++;
466             }
467             if (m_bridge_mode) {
468                 varbinds[i].oid = bridgeOperationalMode;
469                 varbinds[i].len_oid = sizeof(bridgeOperationalMode);
470                 varbinds[i].value = (char *) &bridge_mode;
471                 varbinds[i].len_val = 1;
472                 varbinds[i].type = INT_VALUE;
473                 i++;
474             }
475             if (m_remote_bssid) {
476                 varbinds[i].oid = bridgeRemoteBridgeBSSID;
477                 varbinds[i].len_oid = sizeof(bridgeRemoteBridgeBSSID);
478                 varbinds[i].value = RemoteBSSID;
479                 varbinds[i].len_val = 6;
480                 varbinds[i].type = STRING_VALUE;
481                 i++;
482             }
483             if (m_config_port) {
484                 varbinds[i].oid = ConfigPort;
485                 varbinds[i].len_oid = sizeof(ConfigPort);
486                 varbinds[i].type = INT_VALUE;
487                 varbinds[i].value = (char *) &config_port;
488                 varbinds[i].len_val = 1;
489                 i++;
490             }
491             if (m_fw_bcast) {
492                 varbinds[i].oid = ForwardBroadcast;
493                 varbinds[i].len_oid = sizeof(ForwardBroadcast);
494                 varbinds[i].type = INT_VALUE;
495                 varbinds[i].value = (char *) &fw_bcast;
496                 varbinds[i].len_val = 1;
497                 i++;
498             }
499             if (m_sb_bcast) {
500                 varbinds[i].oid = SendBackBcast;
501                 varbinds[i].len_oid = sizeof(SendBackBcast);
502                 varbinds[i].type = INT_VALUE;
503                 varbinds[i].value = (char *) &sb_bcast;
504                 varbinds[i].len_val = 1;
505                 i++;
506             }
507             if (m_sb_ucast) {
508                 varbinds[i].oid = SendBackUnicast;
509                 varbinds[i].len_oid = sizeof(SendBackUnicast);
510                 varbinds[i].type = INT_VALUE;
511                 varbinds[i].value = (char *) &sb_ucast;
512                 varbinds[i].len_val = 1;
513                 i++;
514             }
515             if (m_trap_port) {
516                 int len_val;
517
518                 len_val = (trap_port > 0x7fff) ? 3 : (trap_port > 0x7f) ? 2 : 1;
519                 varbinds[i].oid = TrapPort;
520                 varbinds[i].len_oid = sizeof(TrapPort);
521                 varbinds[i].type = STRING_VALUE;
522                 varbinds[i].value = (char *) &trap_port;
523                 varbinds[i].len_val = len_val;
524                 i++;
525             }
526
527             print_help(WAIT_SET);
528             if (snmp(varbinds, i, SET) <= 0)
529                 print_helperr(ERR_SET);
530             else
531                 print_help(DONE_SET);
532             goto exit;
533         case 'Q':
534         case 'q':
535             goto quit;
536         }
537         continue;
538     }
539   exit:
540     getch();
541   quit:
542     print_title("");
543     clear_main(0);
544 }
545