Logo Search packages:      
Sourcecode: airport-utils version File versions  Download package

AirportBaseStationConfigurator.java

/*
 * AirportBaseStationConfigurator
 *
 * Copyright (C) 2000, Jonathan Sevy <jsevy@mcs.drexel.edu>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
 



import java.util.*;
import java.net.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.*;
import java.awt.event.*;
import java.io.*;

import byteblock.*;
import snmp.*;
import airport.*;





public class AirportBaseStationConfigurator extends JFrame
                                          implements ActionListener
{
      
      public static final String encryptionKeySizeString = "05";
      public static final int encryptionKeySize = 5;
      public static final String aboutString = "Airport Base Station Configurator ";
      
      
      
      JButton discoverDevicesButton, retrieveItemButton, updateBaseStationButton;
      
      JTextField hostIDField;
      JTextField communityField;
      
      GridBagLayout  mainLayout = new GridBagLayout();
      
      MenuBar theMenubar;
      Menu fileMenu;
      MenuItem quitItem, openItem, saveItem, aboutItem, uploadFirmwareItem;
      
      private final int baseBlockSize = 68*16*16;
      private ByteBlock baseBlock = new ByteBlock(68*16, 16);
      
      private final int configurationSize = 17336;    // total number of significant bytes, including checksum
      
      AirportInfo airportInfo;
      
      AirportInfoTabbedPane infoPane;
      JTextArea messagesArea;
      
      SNMPv1CommunicationInterface comInterface;
      
      SNMPVarBindList retrievedVars;
      
      
      
      // WindowCloseAdapter to catch window close-box closings
      private class WindowCloseAdapter extends WindowAdapter
      { 
            public void windowClosing(WindowEvent e)
            {
                System.exit(0);
            }
      };
            
            
            
      
      
      
      public AirportBaseStationConfigurator()
      {
            
            airportInfo = new AirportInfo(baseBlock);
            
            setUpDisplay();
            
            retrievedVars = new SNMPVarBindList();
            
      }
      
      
      
      private void setUpDisplay()
      {
            
            // set fonts to smaller-than-normal size, for compaction!
            UIManager manager = new UIManager();
            FontUIResource appFont = new FontUIResource("SansSerif", Font.PLAIN, 10);
            UIDefaults defaults = manager.getLookAndFeelDefaults();
            Enumeration keys = defaults.keys();
            
            while (keys.hasMoreElements())
            {
                  String nextKey = (String)(keys.nextElement());
                  if ((nextKey.indexOf("font") > -1) || (nextKey.indexOf("Font") > -1))
                  {
                        manager.put(nextKey, appFont);
                  }
            }
            
            
            
            // add WindowCloseAdapter to catch window close-box closings
            // thanks to Jer for this one!
            addWindowListener(new WindowCloseAdapter());

            
            
            
            
            this.setTitle("AirPort Base Station Configurator");
            
            this.getRootPane().setBorder(new BevelBorder(BevelBorder.RAISED));
            
            theMenubar = new MenuBar();
            this.setMenuBar(theMenubar);
            fileMenu = new Menu("File");
            
            openItem = new MenuItem("Open saved settings...");
            openItem.setShortcut(new MenuShortcut('o'));
            openItem.setActionCommand("open settings");
            openItem.addActionListener(this);
            fileMenu.add(openItem);
            
            saveItem = new MenuItem("Save settings...");
            saveItem.setShortcut(new MenuShortcut('s'));
            saveItem.setActionCommand("save settings");
            saveItem.addActionListener(this);
            fileMenu.add(saveItem);
            
            fileMenu.addSeparator();
            
            uploadFirmwareItem = new MenuItem("Upload new base station firmware...");
            uploadFirmwareItem.setActionCommand("upload firmware");
            uploadFirmwareItem.addActionListener(this);
            fileMenu.add(uploadFirmwareItem);
            
            fileMenu.addSeparator();
            
            aboutItem = new MenuItem("About...");
            aboutItem.setActionCommand("about");
            aboutItem.addActionListener(this);
            fileMenu.add(aboutItem);
            
            quitItem = new MenuItem("Quit");
            quitItem.setShortcut(new MenuShortcut('q'));
            quitItem.setActionCommand("quit");
            quitItem.addActionListener(this);
            fileMenu.add(quitItem);
            
            theMenubar.add(fileMenu);
            
            JLabel hostIDLabel = new JLabel("Device address:");
            hostIDField = new JTextField(10);
            hostIDField.setText("10.0.1.1");
            
            JLabel communityLabel = new JLabel("Community name (password):");
            communityField = new JPasswordField(10);
            //communityField = new JTextField(10);
            //communityField.setText("public");
            
            
            
            discoverDevicesButton = new JButton("Discover Devices");
            discoverDevicesButton.setActionCommand("discover devices");
            discoverDevicesButton.addActionListener(this);
            
            retrieveItemButton = new JButton("Retrieve Settings");
            retrieveItemButton.setActionCommand("retrieve data");
            retrieveItemButton.addActionListener(this);
            
            updateBaseStationButton = new JButton("Update Base Station");
            updateBaseStationButton.setActionCommand("update base station");
            updateBaseStationButton.addActionListener(this);
            
            updateBaseStationButton.setEnabled(false);      //initially disabled until read in or open settings
            

            // set params for layout manager
            GridBagLayout  theLayout = new GridBagLayout();
            GridBagConstraints c = new GridBagConstraints();
            
            c.gridwidth = 1;
            c.gridheight = 1;
            c.fill = GridBagConstraints.NONE;
            c.ipadx = 0;
            c.ipady = 0;
            Insets theMargin = new Insets(2,2,2,2);
            c.insets = theMargin;
            c.anchor = GridBagConstraints.CENTER;
            c.weightx = .5;
            c.weighty = .5;
            
            
            JPanel buttonPanel = new JPanel();
            buttonPanel.setLayout(theLayout);
            
            c.gridx = 1;
            c.gridy = 1;
            theLayout.setConstraints(discoverDevicesButton, c);
            buttonPanel.add(discoverDevicesButton);
            
            c.gridx = 2;
            c.gridy = 1;
            theLayout.setConstraints(retrieveItemButton, c);
            buttonPanel.add(retrieveItemButton);
            
            c.gridx = 3;
            c.gridy = 1;
            theLayout.setConstraints(updateBaseStationButton, c);
            buttonPanel.add(updateBaseStationButton);
            
            
            
            JPanel hostPanel = new JPanel();
            hostPanel.setLayout(theLayout);
            
            c.gridx = 1;
            c.gridy = 1;
            theLayout.setConstraints(hostIDLabel, c);
            hostPanel.add(hostIDLabel);
            
            c.gridx = 2;
            c.gridy = 1;
            theLayout.setConstraints(hostIDField, c);
            hostPanel.add(hostIDField);
            
            c.gridx = 3;
            c.gridy = 1;
            theLayout.setConstraints(communityLabel, c);
            hostPanel.add(communityLabel);
            
            c.gridx = 4;
            c.gridy = 1;
            theLayout.setConstraints(communityField, c);
            hostPanel.add(communityField);
            
            
            infoPane = new AirportInfoTabbedPane(airportInfo);
            
            
            
            JPanel messagesPanel = new JPanel();
            messagesPanel.setLayout(theLayout);
            
            messagesArea = new JTextArea(4,60);
            JScrollPane messagesScroll = new JScrollPane(messagesArea);
            
            c.gridx = 1;
            c.gridy = 1;
            JLabel messagesLabel = new JLabel("Messages:");
            theLayout.setConstraints(messagesLabel, c);
            messagesPanel.add(messagesLabel);
            
            c.gridx = 1;
            c.gridy = 2;
            theLayout.setConstraints(messagesScroll, c);
            messagesPanel.add(messagesScroll);
            
            
            
            
            this.getContentPane().setLayout(mainLayout);
            
            c.gridx = 1;
            c.gridy = 1;
            mainLayout.setConstraints(hostPanel, c);
            this.getContentPane().add(hostPanel);
            
            c.gridx = 1;
            c.gridy = 2;
            mainLayout.setConstraints(buttonPanel, c);
            this.getContentPane().add(buttonPanel);
            
            c.gridx = 1;
            c.gridy = 3;
            mainLayout.setConstraints(infoPane, c);
            this.getContentPane().add(infoPane);
            
            c.gridx = 1;
            c.gridy = 4;
            mainLayout.setConstraints(messagesPanel, c);
            this.getContentPane().add(messagesPanel);
            
            c.gridx = 1;
            c.gridy = 5;
            JLabel authorLabel = new JLabel(" Version 1.5.2        J. Sevy, November 2001 ");
            authorLabel.setFont(new Font("SansSerif", Font.ITALIC, 8));
            mainLayout.setConstraints(authorLabel, c);
            this.getContentPane().add(authorLabel);
            
            
            
      }
      
      
      
      
      public void actionPerformed(ActionEvent theEvent)
      // respond to button pushes, menu selections
      {
            String command = theEvent.getActionCommand();
            
      
            if (command.equals("quit"))
            {
                  System.exit(0);
            }
            
            
            
            if (command == "about")
            {
                  AboutDialog aboutDialog = new AboutDialog(this);
            }
            
            
            
            if (command.equals("discover devices"))
            {
                  AirportDiscoverer discoverer = new AirportDiscoverer();
            }     
            
            
            
            if (command.equals("retrieve data"))
            {
                  
                  
                  try
                  {
                        
                        if (comInterface != null)
                              comInterface.closeConnection();
                  
                        String community = communityField.getText();
                        InetAddress hostAddress = InetAddress.getByName(hostIDField.getText());
                        int version = 0;  // SNMPv1
                        
                        messagesArea.append("Retrieving settings from base station " + hostAddress + "......\n");
                        
                        comInterface = new SNMPv1CommunicationInterface(version, hostAddress, community);
                        
                        
                        for (int k = 1; k <= 68; k++)
                        {
                              String itemID = "1.3.6.1.4.1.762.2.2.1.1." + k;
                              
                              SNMPVarBindList newVars = comInterface.getMIBEntry(itemID);
                              
                              SNMPSequence pair = (SNMPSequence)(newVars.getSNMPObjectAt(0));
                              SNMPOctetString value = (SNMPOctetString)(pair.getSNMPObjectAt(1));
                              
                              
                              // get the 256 bytes
                              byte[] bytes = (byte[])value.getValue();
                              
                              // create a window to write bytes into
                              int startIndex = (k-1)*256;
                              int rows = 16;
                              int cols = 16;
                              ByteBlockRectangularWindow currentBlock = new ByteBlockRectangularWindow(startIndex, rows, cols, baseBlock);
                  
                              // write the bytes
                              currentBlock.writeBytes(bytes);
                              
                              
                        
                        }
                        
                        // would like to check checksum to make sure retrieved block is valid, at least...
                        // however, base station doesn't return valid checksum when data retrieved -
                        // it's just a partial echo of the last checksum sent to it   :-(
                        
                        messagesArea.append("Settings retrieved.\n");
                        
                        
                        // now refresh display
                        this.refreshInfoPane();
                        
                        // enable updating
                        updateBaseStationButton.setEnabled(true); 
                        
                  }
                  catch(UnknownHostException e)
                  {
                        messagesArea.append("Error retrieving settings: unknown host.\n");
                  }
                  catch(SocketException e)
                  {
                        messagesArea.append("Error retrieving settings: " + e + "\n");
                  }
                  catch(IOException e)
                  {
                        messagesArea.append("Error retrieving settings: timed out waiting for response.\n");
                  }
                  catch (SNMPBadValueException e)
                  {
                        // will never occur!
                        messagesArea.append("Error retrieving settings: bad SNMP value received.\n");
                  }
                  catch (SNMPGetException e)
                  {
                        messagesArea.append("Error retrieving settings: incorrect community name (password).\n");
                  }
                  catch (Exception e)
                  {
                        messagesArea.append("Error retrieving settings: " + e.getMessage() + "\n");
                  }
                  
            }
            
            if (command.equals("save settings"))
            {
                  
                  
                        
                  try
                  {
                        
                        infoPane.writeData();
                        setDependentData();
                        setStaticData();
                        setChecksum(baseBlock, configurationSize - 2);
                        
                        
                        FileDialog fd = new FileDialog(this, "Save current settings as...", FileDialog.SAVE);
                        fd.show();
                        
                        if (fd.getFile() != null)
                        {
                              File newFile = new File(fd.getDirectory(), fd.getFile());
                              FileOutputStream fStream = new FileOutputStream(newFile);
                              fStream.write(baseBlock.bytes, 0, configurationSize);
                              fStream.flush();
                              fStream.close();
                        }
                        
                  }
                  catch (ValueFormatException ve)
                  {
                        messagesArea.append("Problem with supplied value: " + ve.getMessage() + "\n");
                  }
                  catch (Exception e)
                  {
                        messagesArea.append("Error saving settings: " + e.getMessage() + "\n");
                  }
                  
                  
            }
            
            
            
            if (command.equals("update base station"))
            {
                  
                  try
                  {
                        infoPane.writeData();
                        setDependentData();
                        setStaticData();
                        setChecksum(baseBlock, configurationSize - 2);  // second checksum set in transmitBlocks()
                        
                        // configurationSize = 17336 indicates number of bytes to burn to prom:
                        // includes first checksum (but not second, which is "transmission" 
                        // checksum - added by transmitBlocks method)
                        
                        transmitBlocks(baseBlock, configurationSize);
                        
                  }
                  catch (ValueFormatException ve)
                  {
                        messagesArea.append("Problem with supplied value: " + ve.getMessage() + "\n");
                  }
                  
            }
            
            
            
            if (command.equals("open settings"))
            {
                  
                  try
                  {
                        FileDialog fd = new FileDialog(this, "Open settings file...", FileDialog.LOAD);
                        fd.show();
                        
                        if (fd.getFile() != null)
                        {
                              File newFile = new File(fd.getDirectory(), fd.getFile());
                              
                              FileInputStream fStream = new FileInputStream(newFile);
                              
                              byte[] newBytes = new byte[17408];
                              
                              fStream.read(newBytes);
                              
                              fStream.close();
                              
                              // check checksum to make sure block is valid, at least...
                              
                              // save current bytes in case new ones invalid
                              byte[] currentBytes = baseBlock.bytes;
                              baseBlock.bytes = newBytes;
                              
                              // see if shift key held down while open selected; if so, don't check checksum
                              boolean shiftKeyDown = ((theEvent.getModifiers() & ActionEvent.SHIFT_MASK) > 0);
                              
                              // make sure checksum is valid, to verify this is a valid settings file
                              // first make sure file big enough to even check checksum!
                              if ( (newFile.length() < configurationSize) || (!shiftKeyDown && !checksumValid()) )
                              {
                                    // reset base block to current bytes
                                    baseBlock.bytes = currentBytes;
                                    throw new Exception("invalid settings file.");
                              }
                              
                              
                              
                              // now refresh display of data
                              this.refreshInfoPane();
                              
                              // enable updating
                              updateBaseStationButton.setEnabled(true);
                              
                        }
                        
                  }
                  catch (Exception e)
                  {
                        messagesArea.append("Error opening settings: " + e.getMessage() + "\n");
                  }
                  
                  
            }
            
            
            
            if (command.equals("upload firmware"))
            {
                  
                  try
                  {
                        FileDialog fd = new FileDialog(this, "Select firmware file...", FileDialog.LOAD);
                        fd.show();
                        
                        if (fd.getFile() != null)
                        {
                              File firmwareFile = new File(fd.getDirectory(), fd.getFile());
                              
                              FileInputStream fStream = new FileInputStream(firmwareFile);
                              
                              int fileLength = (int)firmwareFile.length();
                              
                              // determine number of 256-byte blocks that need to be sent
                              int numBlocks = (int)Math.ceil((double)fileLength/256);
                              
                              // create underlying ByteBlock with appropriate number of sub-blocks
                              ByteBlock firmwareBlock = new ByteBlock(numBlocks*16, 16);
                              
                              fStream.read(firmwareBlock.bytes);
                              
                              fStream.close();
                              
                              // verify this is a valid firmware file; can unfortunately only verify the embedded
                              // configuration checksum.... AND apparently the Apple-supplied formware files computed the
                              // checksum before the community name default passwords (4 "public" and one count of 06)
                              // were inserted. Thus the checksum computation differs by 0xA02 for these files,
                              // so the checksum check is a little weird....
                              
                              // see if shift key held down while open selected; if so, don't validate file
                              boolean shiftKeyDown = ((theEvent.getModifiers() & ActionEvent.SHIFT_MASK) > 0);
                              
                              if (!shiftKeyDown)
                              {
                                    // first make sure file big enough to even check checksum!
                                    if (fileLength < configurationSize)
                                    {
                                          throw new Exception("invalid firmware file.");
                                    }
                                    else if ( (!appleFirmwareChecksumValid(firmwareBlock)) && (!checksumValid(firmwareBlock)) )
                                    {
                                          throw new Exception("invalid firmware file.");
                                    }
                              }
                              
                              // put up a dialog permitting the user to select uploading the current settings, if
                              // they're valid...
                              String messageString = "Upload firmware to base station " + hostIDField.getText() + "?";
                              String response = new String("Cancel");
                              // see if current settings are valid; if so, these become upload option
                              if (updateBaseStationButton.isEnabled())
                              {
                                    String[] possibleValues = { "Upload firmware with current settings", "Upload firmware with default settings", "Cancel" };
                                    int selectedValue = JOptionPane.showOptionDialog(null, messageString, "Firmware Upload", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE, null, possibleValues, possibleValues[0]);
                                    if ( !(selectedValue == JOptionPane.CLOSED_OPTION) )
                                          response = possibleValues[selectedValue];
                              }
                              else
                              {
                                    String[] possibleValues = { "Upload firmware with default settings", "Cancel" };
                                    int selectedValue = JOptionPane.showOptionDialog(null, messageString, "Firmware Upload", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE, null, possibleValues, possibleValues[0]);
                                    if ( !(selectedValue == JOptionPane.CLOSED_OPTION) )
                                          response = possibleValues[selectedValue];
                              }
                              
                              
                              // if current settings selected, upload these to base station with firmware;
                              // if not, leave default settings alone in firmware bytes
                              if (response.equals("Upload firmware with current settings"))
                              {
                                    // note that current settings could throw ValueFormatException!
                                    infoPane.writeData();
                                    setDependentData();
                                    setStaticData();
                                    setCommunityNames();          // so base station will know what to use after reset!!
                                    setChecksum(baseBlock, configurationSize - 2);
                                    
                                    // copy current setting bytes into firmware bytes
                                    for (int i = 0; i < configurationSize; i++)
                                          firmwareBlock.bytes[i] = baseBlock.bytes[i];
                                    // now transmit info
                                    transmitBlocks(firmwareBlock, fileLength);
                                    
                              }
                              else if (response.equals("Upload firmware with default settings"))
                              {
                                    // just transmit firmware info with default settings
                                    transmitBlocks(firmwareBlock, fileLength);
                              }
                              
                              
                              
                        }
                        
                  }
                  catch (ValueFormatException ve)
                  {
                        messagesArea.append("Problem with supplied value: " + ve.getMessage() + "\n");
                  }
                  catch (Exception e)
                  {
                        messagesArea.append("Error updating firmware: " + e.getMessage() + "\n");
                  }
                  
            }
            
            
      }
      
      
      
      
      private String hexByte(byte b)
      {
            int pos = b;
            if (pos < 0)
                  pos += 256;
            String returnString = new String();
            returnString += Integer.toHexString(pos/16);
            returnString += Integer.toHexString(pos%16);
            return returnString;
      }
      
      
      
      
      private void refreshInfoPane()
      {
            // first, remove current infoPane
            this.remove(infoPane);
            
            
            //now create new tabbed pane to hold info
            infoPane = new AirportInfoTabbedPane(airportInfo);
            
            
            // set params for layout manager
            GridBagConstraints c = new GridBagConstraints();
            
            c.gridwidth = 1;
            c.gridheight = 1;
            c.fill = GridBagConstraints.NONE;
            c.ipadx = 0;
            c.ipady = 0;
            Insets theMargin = new Insets(2,2,2,2);
            c.insets = theMargin;
            c.anchor = GridBagConstraints.CENTER;
            c.weightx = .5;
            c.weighty = .5;
            
            
            // then add pane to frame
            c.gridx = 1;
            c.gridy = 3;
            mainLayout.setConstraints(infoPane, c);
            this.getContentPane().add(infoPane);
            
            
            // call validate to update display
            this.validate();
      }
      
      
      
      private void setDependentData()
            throws ValueFormatException
      {
            /*
            *     Write values for DHCP/NAT-delivered base station IP address, router
            *     IP address, mask; do here since requires "cross-reference" between data
            *     in separate panels.
            */
            
            
            boolean ethernetConnection = false, modemConnection = false;      // flags specifying base station connection and
            boolean dhcpConfig = false, manualConfig = false;                       // configuration style
            boolean natEnabled = false, dhcpEnabled = false;                        // flags indicating address delivery services of base station
            boolean portMappingEnabled = false;
            
            
            // set flags for Ethernet/Modem mode
            AirportInfoRecord ethernetModemSwitch1Record = airportInfo.get("Ethernet/Modem switch 1");
            String ethernetModemSwitch1Setting = ethernetModemSwitch1Record.toString();
            AirportInfoRecord ethernetModemSwitch2Record = airportInfo.get("Configuration interface");
            String ethernetModemSwitch2Setting = ethernetModemSwitch2Record.toString();
            
            if (ethernetModemSwitch1Setting.equals("60") || ethernetModemSwitch2Setting.equals("00"))
                  ethernetConnection = true;
            if (ethernetModemSwitch1Setting.equals("62") || ethernetModemSwitch2Setting.equals("03"))
                  modemConnection = true;
            
            
            //set flags for base station configuration mode
            AirportInfoRecord baseConfigModeRecord = airportInfo.get("Base station configuration mode switch");
            String baseConfigModeSetting = baseConfigModeRecord.toString();
            
            if (baseConfigModeSetting.equals("00"))
                  manualConfig = true;
            if (baseConfigModeSetting.equals("20"))
                  dhcpConfig = true;
                  
            
            // set flags for NAT/DHCP mode
            AirportInfoRecord dhcpSwitchRecord = airportInfo.get("DHCP switch");
            String dhcpSetting = dhcpSwitchRecord.toString();
            
            if (dhcpSetting.equals("80"))
                  dhcpEnabled = true;
            
            
            AirportInfoRecord natSwitchRecord = airportInfo.get("NAT switch");
            String natSetting = natSwitchRecord.toString();
            
            if (natSetting.equals("02"))
                  natEnabled = true;
            
            
            // set flag for port mapping
            AirportInfoRecord portMappingSwitchRecord = airportInfo.get("Port mapping switch"); 
            String portMappingSwitchSetting = portMappingSwitchRecord.toString();
            
            if (portMappingSwitchSetting.equals("04"))
                  portMappingEnabled = true;
                  
            
            // get records for setting dependent data
            AirportInfoRecord natInboundPrivateIPAddressRecord = airportInfo.get("NAT inbound private IP address"); 
            AirportInfoRecord natInboundPrivateSubnetMaskRecord = airportInfo.get("NAT inbound private subnet mask");
            AirportInfoRecord natOutboundPrivateIPAddressRecord = airportInfo.get("NAT outbound private IP address"); 
            AirportInfoRecord natOutboundPrivateSubnetMaskRecord = airportInfo.get("NAT outbound private subnet mask");
            AirportInfoRecord natOutboundPublicIPAddressRecord = airportInfo.get("NAT outbound public IP address"); 
            AirportInfoRecord natOutboundPublicSubnetMaskRecord = airportInfo.get("NAT outbound public subnet mask");
            AirportInfoRecord dhcpServerRouterIPAddressRecord = airportInfo.get("DHCP server router address"); 
            AirportInfoRecord dhcpServerSubnetMaskRecord = airportInfo.get("DHCP server subnet mask"); 
            
            AirportInfoRecord baseStationIPAddressRecord = airportInfo.get("Base station IP address");
            AirportInfoRecord subnetMaskRecord = airportInfo.get("Subnet mask");
            AirportInfoRecord routerIPAddressRecord = airportInfo.get("Router IP address");
                        
            
            // when NAT enabled, set data that depends on settings from other panels
            if (natEnabled)
            {
                  // set NAT outbound IP address and mask
                  if (modemConnection)
                  {
                        natOutboundPublicIPAddressRecord.setBytesFromString("0.0.0.0");
                        natOutboundPublicSubnetMaskRecord.setBytesFromString("255.255.255.0");
                  }
                  if (ethernetConnection)
                  {
                        natOutboundPublicIPAddressRecord.setBytesFromString(baseStationIPAddressRecord.toString());
                        natOutboundPublicSubnetMaskRecord.setBytesFromString(subnetMaskRecord.toString());
                        
                        /*
                        if (manualConfig)
                        {
                              natOutboundPublicIPAddressRecord.setBytesFromString(baseStationIPAddressRecord.toString());
                              natOutboundPublicSubnetMaskRecord.setBytesFromString(subnetMaskRecord.toString());
                        }
                        else if (dhcpConfig)
                        {
                              natOutboundPublicIPAddressRecord.setBytesFromString("0.0.0.0");
                              natOutboundPublicSubnetMaskRecord.setBytesFromString("255.255.255.0");
                        }
                        */
                        
                  }
            }
            
            
            
            // if serving DHCP, set router and subnet mask
            if (dhcpEnabled)
            {
                  if (natEnabled)
                  {
                        // use private network parameters
                        dhcpServerRouterIPAddressRecord.setBytesFromString(natInboundPrivateIPAddressRecord.toString());
                        dhcpServerSubnetMaskRecord.setBytesFromString(natInboundPrivateSubnetMaskRecord.toString());
                  }
                  else
                  {
                        // use global base station parameters
                        dhcpServerRouterIPAddressRecord.setBytesFromString(routerIPAddressRecord.toString());
                        dhcpServerSubnetMaskRecord.setBytesFromString(subnetMaskRecord.toString());
                  }
            }
            
            
            
            
            // if port mapping, and using manual Ethernet config, need to put in base station IP address
            // as the public IP address in the port maps
            if (portMappingEnabled && ethernetConnection && manualConfig)
            {
                  // get count of port maps
                  AirportInfoRecord portMappingCountRecord = airportInfo.get("Count of port mappings");
                  int portMapCount = Integer.parseInt(portMappingCountRecord.toString());
                  
                  // get starting indices and other parameters for the byte block multi-windows
                  // that will hold the public IP address for port mapping, which is just the
                  // manually configured base station IP address
                  int publicIPStartIndex = 0xD72;
                  int publicIPBeginningNumRows = 1;   
                  int publicIPBeginningNumCols = 2;
                  
                  int publicIPEndingIndex = 0xD9A;
                  int publicIPEndingNumRows = 1;      
                  int publicIPEndingNumCols = 2;
                  
                  int publicIPDataType = AirportInfoRecord.IP_ADDRESS;
                  
                  //set the public IP address for each port map
                  for (int i = 0; i < portMapCount; i++)
                  {
                        // need to use a multi-window, since the first two and last two octets are separated
                        ByteBlockMultiWindow publicIPWindow = new ByteBlockMultiWindow();
                              
                        ByteBlockWindow publicIPBeginningWindow = new ByteBlockRectangularWindow(publicIPStartIndex, publicIPBeginningNumRows, publicIPBeginningNumCols, baseBlock);
                        publicIPWindow.addWindow(publicIPBeginningWindow);
                        
                        ByteBlockWindow publicIPEndingWindow = new ByteBlockRectangularWindow(publicIPEndingIndex, publicIPEndingNumRows, publicIPEndingNumCols, baseBlock);
                        publicIPWindow.addWindow(publicIPEndingWindow);
                        
                        AirportInfoRecord publicIPRecord = new AirportInfoRecord(publicIPDataType, publicIPWindow);
                        publicIPRecord.setBytesFromString(baseStationIPAddressRecord.toString());
                        
                        // augment addresses
                        publicIPStartIndex += 2;
                        publicIPEndingIndex += 2;
                        
                  } 
            }
            
      }
      
      
      
      private void setStaticData()
            throws ValueFormatException
      {
            // set read community password field
            AirportInfoRecord readCommunityRecord = airportInfo.get("Read community");
            readCommunityRecord.setBytesFromString("public");
            
            /*
            // set miscellaneous switches that are sometimes zero in "plain vanilla" config files
            String miscellaneousSetting;
            
            AirportInfoRecord miscellaneousRecord1 = airportInfo.get("Miscellaneous switch 1");
            miscellaneousSetting = miscellaneousRecord1.toString();
            if (miscellaneousSetting.equals("00"))
                  miscellaneousRecord1.setBytesFromString("01");
            
            AirportInfoRecord miscellaneousRecord2 = airportInfo.get("Miscellaneous switch 2");
            miscellaneousSetting = miscellaneousRecord2.toString();
            if (miscellaneousSetting.equals("00"))
                  miscellaneousRecord2.setBytesFromString("01");
            */
            
      }
      
      
      
      
      private void setCommunityNames()
            throws ValueFormatException
      {
            
            // Set community name into password field so base station will know what to use after reboot!
            // Find out if there's an entry in the main panel; if so, use this, otherwise use
            // current community name field
            AirportInfoRecord communityNameRecord = airportInfo.get("Read/write community");
            String communityName = communityNameRecord.toString();
            if (communityName.equals(""))
                  communityName = communityField.getText();
            communityNameRecord.setBytesFromString(communityName);
            
            //System.out.println("Community name: " + communityName);
            
            // set trap community password field
            AirportInfoRecord trapCommunityRecord = airportInfo.get("Trap community");
            trapCommunityRecord.setBytesFromString("public");
            
            // set remaining community password field (and count field)
            AirportInfoRecord remainingCommunityCountRecord = airportInfo.get("Remaining community count");
            remainingCommunityCountRecord.setBytesFromString("06");
            
            AirportInfoRecord remainingCommunityRecord = airportInfo.get("Remaining community");
            remainingCommunityRecord.setBytesFromString("public");
      }
      
      
      
      
      
      
      private void transmitBlocks(ByteBlock byteBlock, int numBytes)
      {
            
            try
            {
                  
                  String community = communityField.getText();
                  InetAddress hostAddress = InetAddress.getByName(hostIDField.getText());
                  
                  messagesArea.append("Sending data to base station " + hostAddress + "......\n");
                  
                  
                  if (comInterface == null)
                  {
                        int version = 0;  // SNMPv1
                        comInterface = new SNMPv1CommunicationInterface(version, hostAddress, community);
                  }
                        
                  comInterface.requestID = 1;
                        
                  byte[] bytes = byteBlock.bytes;
                  
                  // determine number of 256-byte blocks that need to be sent
                  int numBlocks = (int)Math.ceil((double)(numBytes + 2)/256);       // +2 leaves room for transmission checksum
                  
                  // send all but last block
                  for (int k = 1; k < numBlocks; k++)
                  {
                        String itemID = "1.3.6.1.4.1.762.2.3.1.1." + k;
                        
                        // create new 256 byte array
                        byte[] newBytes = new byte[256];
                        
                        // copy block of 256 bytes from given bytes to new array
                        for (int j = 0; j < 256; j++)
                        {
                              newBytes[j] = bytes[256*(k-1) + j];
                        }
                        
                        // create SNMP octet string from these bytes
                        SNMPOctetString theObject = new SNMPOctetString(newBytes);
                        
                        // send the bytes
                        SNMPVarBindList newVars = comInterface.setMIBEntry(itemID, theObject);
                  
                  }
                  
                  
                  // now send last block
                  String itemID = "1.3.6.1.4.1.762.2.3.1.1." + numBlocks;
                        
                  // create new 256 byte array
                  byte[] newBytes = new byte[256];
                  
                  // copy remaining bytes from given bytes to new array
                  int endPosition = numBytes - (numBlocks-1)*256;
                  
                  for (int j = 0; j < endPosition; j++)
                  {
                        newBytes[j] = bytes[256*(numBlocks-1) + j];
                  }
                  
                  // now set transmission checksum as 2 bytes following last (legitimate) bytes;
                  // note that number of blocks was chosen to be (numBytes+2)/256, ensuring room
                  ByteBlock lastBlock = new ByteBlock(16, 16, newBytes);
                  short checksum = computeChecksum(byteBlock.bytes, numBytes);
                  setChecksum(checksum, lastBlock, endPosition);
                  
                  // create SNMP octet string from these bytes
                  SNMPOctetString theObject = new SNMPOctetString(lastBlock.bytes);
                  
                  // send the bytes
                  SNMPVarBindList newVars = comInterface.setMIBEntry(itemID, theObject);
            
                  
                  // now send reset signal: indicates number of bytes to burn to prom.
                  // also indicates location of checksum
                  
                  SNMPInteger numBytesWritten = new SNMPInteger(numBytes);
                  
                  //System.out.println("Number of bytes to burn in: " + numBytesWritten);
                              
                  
                  itemID = "1.3.6.1.4.1.762.2.1.2.0";
                  newVars = comInterface.setMIBEntry(itemID, numBytesWritten);
                  
                  itemID = "1.3.6.1.4.1.762.2.1.3.0";
                  newVars = comInterface.setMIBEntry(itemID, numBytesWritten);
                  
                  messagesArea.append("Data transmitted; base station restarting.\n");
                  
                  
                  
            }
            catch(UnknownHostException e)
            {
                  messagesArea.append("Error transmitting data: unknown host.\n");
            }
            catch(SocketException e)
            {
                  messagesArea.append("Error transmitting data: " + e.getMessage() + "\n");
            }
            catch(IOException e)
            {
                  messagesArea.append("Error transmitting data: timed out waiting for response.\n");
            }
            catch (SNMPSetException e)
            {
                  messagesArea.append("Error transmitting data: " + e.getMessage() + "\n");
            }
            catch (SNMPBadValueException e)
            {
                  // will never occur!
                  messagesArea.append("Error transmitting data: bad SNMP value.\n");
            }
            
      }
      
      
      
      /*
      *     Compute the 2-byte checksum for the bytes up to (but not including) the indicated position
      */
      
      private short computeChecksum(byte[] bytes, int position)
      {
            short sum = 0;
            
            for (int i = 0; i < position; i++)
            {
                  sum += bytes[i];
                  if(bytes[i] < 0)
                        sum += 256;
            }
            
            return sum;
            
      }
      
      
      
      
      
      private void setChecksum(short sum, ByteBlock byteBlock, int position)
      {
            
            String checksumString = littleEndianHexString(sum);
            
            // create info record to write into
            int numRows = 1;
            int numCols = 2;
            int baseStartIndex = position;
            ByteBlockWindow checksumWindow = new ByteBlockRectangularWindow(baseStartIndex, numRows, numCols, byteBlock);
      
            int dataType = AirportInfoRecord.BYTE_STRING;
            AirportInfoRecord checksumRecord = new AirportInfoRecord(dataType, checksumWindow);
            checksumRecord.byteBlockWindow.clearBytes();
            
            // write in new checksum
            try
            {
                  checksumRecord.setBytesFromString(checksumString);
            }
            catch (ValueFormatException ve)
            {
                  // won't occur!
                  messagesArea.append("Problem writing checksum with value " + checksumString + ".\n");
            }
            
      }
      
      
      
      /*
      *     Convenience method for writing checksum value into same block it's computed from. This
      *     is the usual case for config files; however, the more general routine is used to set
      *     the transmission checksum immediately following the transmitted data bytes.
      */
      private void setChecksum(ByteBlock byteBlock, int position)
      {
            
            short sum = computeChecksum(byteBlock.bytes, position);
            
            setChecksum(sum, byteBlock, position);
            
      }
      
      
      
      
      /**
      * Return little-endian hex string
      */
      private String littleEndianHexString(short value)
      {
            int intValue = value;
            intValue = intValue & 0xFFFF;
            int switched = ((intValue << 8) | (intValue >>> 8)) & 0xFFFF;
            
            String returnString = Integer.toHexString(switched);
            
            // add leading zeros if needed
            while (returnString.length() < 4)
                  returnString = "0" + returnString;
            
            return returnString;
      }
      
      
      
      
      
      
      
      /**
      *     Used to validate checksum in stored settings, to ensure file is legitimate! Verify just
      *     first checksum, for compatibility with Apple configurator's stored settings.
      */
      
      private boolean checksumValid(ByteBlock byteBlock)
      {
            short sum = computeChecksum(byteBlock.bytes, configurationSize - 2);
            
            String computedChecksumString = littleEndianHexString(sum);
            
            //System.out.println("Computed checksum: " + computedChecksumString);
            
            // get configuration checksum from block
            int baseStartIndex = 0x43B6;
            int numRows = 1;  
            int numCols = 2;
            int dataType = AirportInfoRecord.BYTE_STRING;
            AirportInfoRecord checksumRecord = new AirportInfoRecord(baseStartIndex, numRows, numCols, dataType, byteBlock);
            String existingChecksumString = checksumRecord.toString();
            
            //System.out.println("Existing checksum: " + existingChecksumString);
            
            if (computedChecksumString.equals(existingChecksumString))
                  return true;
            else
                  return false;
            
      }
      
      
      private boolean checksumValid()
      {
            return checksumValid(baseBlock);
      }
      
      
      
      
      // Apparently the Apple-supplied firmware files computed the
      // checksum before the community name default passwords (4 "public" and one count of 06)
      // were inserted. Thus the checksum computation should differ by 0xA02 for these files.
      // Thus the need for this "hacked" checksum validation....
      private boolean appleFirmwareChecksumValid(ByteBlock byteBlock)
      {
            short sum = computeChecksum(byteBlock.bytes, configurationSize - 2);
            
            sum -= 0xA02;
            
            String computedChecksumString = littleEndianHexString(sum);
            
            //System.out.println("Computed checksum: " + computedChecksumString);
            
            // get configuration checksum from block
            int baseStartIndex = 0x43B6;
            int numRows = 1;  
            int numCols = 2;
            int dataType = AirportInfoRecord.BYTE_STRING;
            AirportInfoRecord checksumRecord = new AirportInfoRecord(baseStartIndex, numRows, numCols, dataType, byteBlock);
            String existingChecksumString = checksumRecord.toString();
            
            //System.out.println("Existing checksum: " + existingChecksumString);
            
            if (computedChecksumString.equals(existingChecksumString))
                  return true;
            else
                  return false;
            
      }
      
      
      
      
      public static void main(String args[]) 
      {
            try
            {
                  AirportBaseStationConfigurator theApp = new AirportBaseStationConfigurator();
                  theApp.pack();
                  
                  // tweak app size to make it a little larger than necessary, to address the
                  // "shrunken textfields" problem arising from the layout manager packing stuff
                  // a little too tightly.
                  Dimension dim = theApp.getSize();
                  dim.height += 20;
                  dim.width += 20;
                  theApp.setSize(dim);
                  
                  theApp.show();
            }
            catch (Exception e)
            {}
      }
      

}

Generated by  Doxygen 1.6.0   Back to index